介绍
我最近收到简单的 Web 应用程序正在运行在具有 MicroK8S 的三节点 Ubuntu 服务器上。我决定尝试重建集群并使用 YAML 清单重新安装所有内容,以确保该过程可复制。但是,现在无法从集群外部访问该应用程序。我正在寻找调试技术来深入了解为什么 NodePort 显然没有在所有节点上创建 TCP 侦听器。
这是我的节点:
姓名 | 知识产权 | 颜色 | 角色 |
---|---|---|---|
阿伦 | 192.168.50.251 | 黄色的 | 领导者 |
尼卡 | 192.168.50.74 | 蓝色的 | 工人 |
山崎 | 192.168.50.135 | 绿色的 | 工人 |
集群再次选择在第三个节点 Yamazaki 上运行工作负载。我预计到达 Arran 或 Nikka 的任何网络流量都会在内部重新路由到 Yamazaki 进行服务,就像之前发生的那样。
我做了什么
从以前工作的集群/应用程序中,下面是我重置所有内容的操作:
microk8s leave
在所有跟随节点上执行对每个跟随节点的领导者执行此操作
microk8s kubectl delete node <nodename>
(他们离开时不会被自动删除)microk8s reset
在所有节点上执行启用插件(dns、ingress)。我不知道是否有必要
microk8s add-node
在领导者上为每个追随者创建加入命令microk8s join <ip>/<token>
在每个关注者上运行一个新的加入命令在任何节点上运行
microk8s status
以确保集群处于 HA 模式使用以下方式从领导者处加载应用程序映像 tarball
microk8s images import workload.tar
通过以下方式启动应用程序
microk8s kubectl apply -f k8s-manifests/production/pod.yaml -f k8s-manifests/production/nodeport.yaml
这是 Pod:
apiVersion: v1 kind: Pod metadata: name: k8s-workload annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"k8s-workload","namespace":"default"},"spec":{"containers":[{"image":"k8s-workload","imagePullPolicy":"Never","name":"k8s-workload","ports":[{"containerPort":9090,"protocol":"TCP"}]}]}} spec: containers: - image: k8s-workload imagePullPolicy: Never name: k8s-workload ports: - containerPort: 9090 protocol: TCP
这是 NodePort:
apiVersion: v1 kind: Service metadata: name: np-service spec: type: NodePort ports: - port: 9090 targetPort: 9090 nodePort: 30090 selector: run: k8s-workload # This should not be needed, but it didn't help # this time anyway externalIPs: [192.168.50.251]
检查应用程序是否通过内部容器调用运行
microk8s kubectl exec -ti k8s-workload -- curl http://localhost:9090
- 这很好检查应用程序是否通过任何节点上的端口转发器运行
microk8s kubectl port-forward pod/k8s-workload 9090 --address='0.0.0.0'
- 这很好节点未在外部进行监听(
curl http://localhost:30090
连接被拒绝,与 LAN 上非集群机器的任何节点 IP 地址相同)
系统状态
以下是正在运行的内容microk8s kubectl get all -o wide
:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/k8s-workload 1/1 Running 0 20h 10.1.134.193 yamazaki <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 35d <none>
service/np-service NodePort 10.152.183.175 192.168.50.251 9090:30090/TCP 3d21h run=k8s-workload
我不知道它service/kubernetes
是什么,我认为它只是标准 K8S 基础设施的一部分。
观察结果
我认为本文表示我的 Web 应用需要成为一项服务,但我只有一个 pod。我认为以前运行此程序时,我只有一个 pod,但集群变得有点混乱,因此有可能应用的服务版本与 pod 版本同时运行。
这篇文章还建议我应该使用入口系统。但是,考虑到 NodePort 是我目前的学习重点,我还不想就此放弃。入口可以稍后再介绍。
我认为我可以确定没有防火墙问题,因为即使在集群中节点上的控制台会话中,任何到端口 30090 的连接都会被拒绝。
我想运行类似的程序microk8s kubectl logs service np-service
来查看 NodePort 正在做什么,但是 logs 子命令只对 pod 有效。
下一步我可以尝试什么?
答案1
当使用kubectl run
启动 Pod 时,Kubernetes 会自动用部署时使用的名称来标记它们。
例如,看一下由以下生成的 YAML kubectl run nginx --image=nginx -o yaml
:
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx <- Automatically assigned
name: nginx
namespace: default
spec:
containers:
- image: nginx
...
现在,假设您提供的 Pod 的 YAMLk8s-workload
已完成,则此标签目前缺失。这很重要,因为selector
您在 中使用了NodePort's
specs
。
apiVersion: v1
kind: Service
metadata:
name: np-service
spec:
...
selector:
run: k8s-workload <- This tells Kubernetes who the Service is for
我猜想 Kubernetes 目前只是找不到该服务对应的 Pod。您可以通过运行来测试这个理论kubectl get pods -l run=k8s-workload
。您应该会收到类似这样的错误消息No resources found in default namespace
。
修复此问题非常简单,只需(重新)分配标签即可。可以使用kubectl label
以下命令完成此操作kubectl label pod k8s-workload run=k8s-workload
。
详细指南如何调试服务以及有关标签和选择器的工作原理可以在官方文档中找到。
更新
关于这种情况是否会被记录:没有端点的服务不是错误,而且(据我所知)不会在任何地方记录。想象一下每周只需要几个小时的部署。部署不活跃,因此服务在 90% 的时间内没有任何端点是可以预料的,并不意味着某些东西配置不正确或无法正常工作。
答案2
正如我所料,解决方案很简单。Eleasar 好心地提供了一个label
命令来修复这个问题,但我更喜欢在 YAML 中修复它,因为我认为这更容易重复。这是我的新命令pod.yaml
:
apiVersion: v1
kind: Pod
metadata:
name: k8s-workload
labels:
run: k8s-workload
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"k8s-workload","namespace":"default"},"spec":{"containers":[{"image":"k8s-workload","imagePullPolicy":"Never","name":"k8s-workload","ports":[{"containerPort":9090,"protocol":"TCP"}]}]}}
spec:
containers:
- image: k8s-workload
imagePullPolicy: Never
name: k8s-workload
ports:
- containerPort: 9090
protocol: TCP
只需两行新代码即可为该对象添加唯一标签。