公众号关注 「奇妙的 Linux 世界」
设为「星标」,每天带你玩转 Linux !
当你希望在 Kubernetes 中部署应用程序时,你通常会定义三个组件:
• 一个Deployment-用于创建应用程序的副本。
• 一个Service-内部负载均衡器,负责路由流量到Pod。
• 一个Ingress-描述流量应该如何从集群外部流入到你的服务。
1. 在 Kubernetes 中,你的应用程序通过两层负载均衡器公开:内部和外部。
2. 内部负载均衡器称为 Service,而外部负载均衡器称为 Ingress。
3. Pod 不是直接部署的。Deployment 会创建 Pod 并对其进行处理。
假设你希望部署一个简单的Hello World应用程序,此类应用程序的 YAML(hello-world.yaml) 应如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
labels:
track: canary
spec:
selector:
matchLabels:
any-name: my-app
template:
metadata:
labels:
any-name: my-app
spec:
containers:
- name: cont1
image: learnk8s/app:1.0.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- port: 80
targetPort: 8080
selector:
name: app
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- http:
paths:
- backend:
service:
name: my-service
port:
number: 80
path: /
pathType: Prefix
• 什么时候应该使用 80 端口,什么时候应该使用 8080 端口?
• 你是否应该为每个服务创建一个新端口,以免它们发生冲突?
• 标签名称重要吗?应该都一样吗?
在调试之前,让我们回顾一下这三个组件如何相互链接。让我们从Deployment 和 Service开始。
连接Deployment 和 Service
令人惊讶的是 Service 和 Deployment 根本没有联系。相反,Service直接指向 Pod 并完全跳过Deployment。所以你应该注意的是Pods和Services是如何相互关联的。
你应该记住三件事:
1. Service 选择器应该至少匹配一个 Pod 的标签。
2. Service 的
targetPort
应该与Pod 的containerPort
匹配。3. Service 的
port
可以是任何数字。多个服务可以使用相同的端口,因为它们分配了不同的 IP 地址。
下图总结了 Service如何连接Pod的端口:
1. 考虑以下由 Service 公开的 Pod。
2. 创建 Pod 时,你应该为 Pod中的每个容器的
containerPort
定义端口。
1. 创建 Service时,你可以定义 一个
port
和 一个targetPort
。
1.
targetPort
和containerPort
应该始终匹配。
1. 如果你的容器端口是 3000,则
targetPort
应与该数字匹配。
如果你查看 YAML文件,标签和ports
/targetPort
应该匹配:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
labels:
track: canary
spec:
selector:
matchLabels:
any-name: my-app
template:
metadata:
labels:
any-name: my-app
spec:
containers:
- name: cont1
image: learnk8s/app:1.0.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- port: 80
targetPort: 8080
selector:
any-name: my-app
由此我们找到开头提到的Deployment和 Service的标签并不匹配。假设你做出了正确的改变,你如何测试它?你可以使用以下命令检查 Pod 是否具有正确的标签:
kubectl get pods --show-labels
NAME READY STATUS LABELS
my-deployment-pv6pd 1/1 Running any-name=my-app,pod-template-hash=7d6979fb54
my-deployment-f36rt 1/1 Running any-name=my-app,pod-template-hash=7d6979fb54
或者,如果你有属于多个应用程序的 Pod:
kubectl get pods --selector any-name=my-app --show-labels
any-name=my-app
标签在哪里any-name: my-app
。
你可以使用kubectl 中的命令port-forward
,从集群外部连接到 Service 进行测试。
kubectl port-forward service/<service name> 3000:80
Forwarding from 127.0.0.1:3000 -> 8080
Forwarding from [::1]:3000 -> 8080
说明:
•
service/<service name>
是服务的名称——在本文的 YAML 中是my-service
。• 3000 是你希望在计算机上打开的端口。
• 80是Service在暴露的
port
端口。
如果可以连接,则设置正确。如果不能,则很可能是标签匹配错了或端口不匹配。
连接 Service和Ingress
公开你的应用程序的下一步是配置 Ingress。
Ingress 通过公开的名称和端口检索正确的 ,然后连接 Pod 并路由流量。
Ingress 和 Service 中应该匹配两件事:
1. Ingress中的
service.port
应该匹配Service的port
2. Ingress中的
service.name
应该匹配Service的name
下图总结了Ingress如何连接Service的端口:
1. 通过上文,你已经知道该Service公开了一个
port
.
1. Ingress 有一个名为
service.port
的字段
1. Ingress中的
service.port
应该匹配Service的port
1. 如果你决定将端口 80 分配给Service,你应该更改
service.port
为 80
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- port: 80
targetPort: 8080
selector:
any-name: my-app
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- http:
paths:
- backend:
service:
name: my-service
port:
number: 80
path: /
pathType: Prefix
你如何测试 Ingress 的工作原理?你可以使用与之前相同的策略kubectl port-forward
,但不是连接到服务,而是连接到Ingress控制器。
首先,使用以下命令检索 Ingress 控制器的 Pod 名称:
kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS
kube-system coredns-5644d7b6d9-jn7cq 1/1 Running
kube-system etcd-minikube 1/1 Running
kube-system kube-apiserver-minikube 1/1 Running
kube-system kube-controller-manager-minikube 1/1 Running
kube-system kube-proxy-zvf2h 1/1 Running
kube-system kube-scheduler-minikube 1/1 Running
kube-system nginx-ingress-controller-6fc5bcc 1/1 Running
识别 Ingress Pod(可能在不同的命名空间中)并以检索端口:
kubectl describe pod nginx-ingress-controller-6fc5bcc \
--namespace kube-system \
| grep Ports
Ports: 80/TCP, 443/TCP, 18080/TCP
最后,连接到 Pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
Forwarding from 127.0.0.1:3000 -> 80
Forwarding from [::1]:3000 -> 80
此时,访问计算机上的 3000 端口时,请求都会转发到 Ingress 控制器 Pod 上的 80 端口。
端口回顾
以下是对哪些端口和标签应该匹配的快速回顾:
1. Service的选择器应该匹配 Pod 的标签
2. Service的
targetPort
应该与Pod内的容器的containerPort
相匹配3. Service的端口可以是任意数字。多个服务可以使用相同的端口,因为它们分配了不同的 IP 地址。
4. Ingress中的
service.port
应该匹配Service的port
5. Ingress中的
service.name
应该匹配Service的name
了解如何构建 YAML 定义只是故事的一部分。当出现问题时会发生什么?也许 Pod 没有启动,或者它正在崩溃。
对 Kubernetes 部署进行故障排除的 3 个步骤
在深入调试发生故障的Deployment之前,必须对 Kubernetes 的工作方式有一个明确定义的心理模型。
由于每个部署中都有三个组件,因此你应该从底部开始按顺序调试所有组件。
1. 你应该确保你的 Pod 正在运行,然后
2. 专注于让 Service 将流量路由到 Pod,然后
3. 检查 Ingress 是否正确配置。
你应该从底部开始对Deployment进行故障排除。首先,检查 Pod 是否已就绪并正在运行。
如果 Pod 已就绪,你应该检查 Service 是否可以将流量分配给 Pod。
最后,你应该检查 Service 和 Ingress 之间的连接。
1. 对 Pod 进行故障排除
大多数时候,问题出在 Pod 本身。你应该确保你的 Pod 正在运行 并准备就绪。*你如何检查?*
kubectl get pods
NAME READY STATUS RESTARTS AGE
app1 0/1 ImagePullBackOff 0 47h
app2 0/1 Error 0 47h
app3-76f9fcd46b-xbv4k 1/1 Running 1 47h
在上面的输出中,最后一个 Pod 是Running和Ready —— 但是,前两个Pod既不是Running也不是Ready。
你如何排查出了什么问题?
有四个有用的命令可以对 Pod 进行故障排除:
1.
kubectl logs <pod name>
有助于检索 Pod 容器的日志。2.
kubectl describe pod <pod name>
可用于检索与 Pod 关联的事件列表。3.
kubectl get pod <pod name>
用于提取存储在 Kubernetes 中的 Pod 的 YAML 定义。4.
kubectl exec -ti <pod name> -- bash
可以在 Pod 的容器之一中运行交互式命令
你应该使用哪一个?没有一种万能的。相反,你应该使用它们的组合。
常见的 Pod 错误
Pod 可能有启动和运行时错误。
启动错误包括:
• ImagePullBackoff
• ImageInspectError
• ErrImagePull
• ErrImageNeverPull
• RegistryUnavailable
• InvalidImageName
运行时错误包括:
• CrashLoopBackOff
• RunContainerError
• KillContainerError
• VerifyNonRootError
• RunInitContainerError
• CreatePodSandboxError
• ConfigPodSandboxError
• KillPodSandboxError
• SetupNetworkError
• TeardownNetworkError
以下是最常见的错误列表以及如何修复它们。
ImagePullBackOff
当 Kubernetes 无法检索 Pod 容器之一的镜像时,会出现此错误。
常见的罪魁祸首有以下三种:
1. 镜像名称无效 - 例如,你拼错了名称,或者镜像不存在。
2. 你为镜像指定了一个不存在的标签。
3. 你尝试检索的镜像属于私有镜像仓库,Kubernetes 没有访问它的凭据。
前两种情况可以通过更正镜像名称和标签来解决。最后一个,你应该在你的 Pod 中引用你的私有镜像仓库中的 Secret。
CrashLoopBackOff
如果容器无法启动,Kubernetes 会将 CrashLoopBackOff 作为状态显示。
通常,容器在以下情况下无法启动:
1. 应用程序中存在阻止其启动的错误。
2. 你错误地配置了容器。
3. Liveness 探针失败的次数太多。
你应该尝试从该容器中检索日志以调查失败的原因。
如果因为容器重启太快而看不到日志,可以使用以下命令:
kubectl logs <pod-name> --previous
它会打印来自前一个容器的错误消息。
运行容器错误
当容器无法启动时出现该错误。
甚至在容器内的应用程序启动之前。
该问题通常是由于配置错误造成的,例如:
• 挂载不存在的卷,例如 ConfigMap 或 Secrets。
• 将只读卷挂载为读写。
你应该使用kubectl describe pod <pod-name>
来检查和分析错误。
处于Pending状态的Pod
创建 Pod 时,Pod 保持Pending状态。为什么?
假设你的调度程序组件运行良好,原因如下:
1. 集群没有足够的资源(例如 CPU 和内存)来运行 Pod。
2. 当前 Namespace 有一个 ResourceQuota 对象,创建 Pod 将使 Namespace 超过配额。
3. Pod 绑定到Pending PersistentVolumeClaim。
你最好的选择是检查命令中的事件部分kubectl describe
:
kubectl describe pod <pod name>
对于因 ResourceQuotas 而产生的错误,你可以使用以下命令检查集群的日志:
kubectl get events --sort-by=.metadata.creationTimestamp
处于not Ready状态的Pod
如果 Pod 正在运行但未就绪,则意味着Readiness探针失败。
当 Readiness 探针失败时,Pod 不会附加到服务,并且没有流量转发到该实例。
失败的就绪探针是特定于应用程序的错误,因此你应该通过kubectl describe
命令查看事件以识别错误。
2.对 Service 进行故障排除
如果你的 Pod 正在运行 并准备就绪,但你仍然无法从你的应用程序收到响应,你应该检查服务是否配置正确。
Service旨在根据标签将流量路由到 Pod。
因此,你应该检查的第一件事是Service匹配的 Pod 。你可以通过检查服务中的端点来做到这一点:
kubectl describe service my-service
Name: my-service
Namespace: default
Selector: app=my-app
IP: 10.100.194.137
Port: <unset> 80/TCP
TargetPort: 8080/TCP
Endpoints: 172.17.0.5:8080
一个endpoint 是一对<ip address:port>
,并且应该至少有一个。
如果Endpoints
部分为空,则有两种解释:
1. 你没有使用正确标签运行任何 Pod(提示:你应该检查你是否在正确的命名空间中)。
2. 你在服务的
selector
标签中有拼写错误。
如果你看到Endpoints列表,但仍然无法访问你的应用程序,则你的Service中的 targetPort
可能是罪魁祸首。
你如何测试服务?无论服务类型如何,你都可以使用kubectl port-forward
它来连接:
kubectl port-forward service/<service-name> 3000:80
在哪里:
•
<service-name>
是服务的名称。•
3000
是你希望在计算机上打开的端口。•
80
是服务公开的端口。
3. 对 Ingress 进行故障排除
如果你已到达此部分,则:
• Pod 正在运行并准备就绪。
• Service 将流量分配给 Pod。
但是你仍然看不到你的应用程序的响应。这意味着很可能是 Ingress 配置错误。由于 Ingress 控制器是集群中的第三方组件,因此根据 Ingress 控制器的类型有不同的调试技术。但在深入研究 Ingress 特定工具之前,你可以检查一些简单的东西。
Ingress 使用service.name
和service.port
连接到服务。
你应该检查这些配置是否正确。
你可以检查 Ingress 是否正确配置:
kubectl describe ingress my-ingress
Name: my-ingress
Namespace: default
Rules:
Host Path Backends
---- ---- --------
*
/ my-service:80 (<error: endpoints "my-service" not found>)
如果Backends列是空的,那么一定是配置有错误。
如果你可以在Backend列中看到端点,但仍然无法访问应用程序,则问题很可能是:
• 你如何将你的 Ingress 公开给集群外部。
• 你如何将集群暴露给集群外部。
你可以通过直接连接到 Ingress Pod 将基础设施问题与 Ingress 隔离。
首先,检索 Ingress 控制器的 Pod(可能位于不同的命名空间中):
kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS
kube-system coredns-5644d7b6d9-jn7cq 1/1 Running
kube-system etcd-minikube 1/1 Running
kube-system kube-apiserver-minikube 1/1 Running
kube-system kube-controller-manager-minikube 1/1 Running
kube-system kube-proxy-zvf2h 1/1 Running
kube-system kube-scheduler-minikube 1/1 Running
kube-system nginx-ingress-controller-6fc5bcc 1/1 Running
然后检索端口:
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system \
| grep Ports
Ports: 80/TCP, 443/TCP, 8443/TCP
Host Ports: 80/TCP, 443/TCP, 0/TCP
最后,连接到 Pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
Forwarding from 127.0.0.1:3000 -> 80
Forwarding from [::1]:3000 -> 80
此时,每次访问计算机的 3000 端口时,请求都会转发到 Pod 上的 80 端口。
现在有效吗?
• 如果起作用,则问题出在基础设施上。你应该调查流量如何路由到你的集群。
• 如果它不起作用,则问题出在 Ingress 控制器中。你应该调试 Ingress。
如果你仍然无法让 Ingress 控制器工作,你应该开始调试它。有许多不同版本的 Ingress 控制器。流行的选项包括 Nginx、HAProxy、Traefik 等。你应该查阅 Ingress 控制器的文档以查找故障排除指南。
由于Ingress Nginx是最受欢迎的 Ingress 控制器,我们在下一节中包含了一些关于它的调试技巧。
调试 Ingress Nginx
Ingress-nginx 项目有一个官方的 Kubectl 插件。你可以使用kubectl ingress-nginx
命令来:
• 检查日志、后端、证书等。
• 连接到Ingress。
• 检查当前配置。
你应该尝试的三个命令是:
•
kubectl ingress-nginx lint
,它检查nginx.conf
.•
kubectl ingress-nginx backend
, 检查后端(类似于kubectl describe ingress <ingress-name>
)。•
kubectl ingress-nginx logs
, 检查日志。
请注意,你可能需要为 Ingress 控制器指定正确的命名空间
--namespace <name>
。
总结
Kubernetes 中的故障排除可能是一项艰巨的任务。你应该始终记住自下而上地解决问题:从 Pod 开始,然后排查 Service 和 Ingress 。
你在本文中学到的故障排除技术也可以应用于其他对象,例如:
• Jobs 和 CronJobs。
• StatefulSet 和 DaemonSe
本文转载自:「云原生百宝箱」,原文:https://url.hi-linux.com/ZnN86,版权归原作者所有。欢迎投稿,投稿邮箱: editor@hi-linux.com。
最近,我们建立了一个技术交流微信群。目前群里已加入了不少行业内的大神,有兴趣的同学可以加入和我们一起交流技术,在 「奇妙的 Linux 世界」 公众号直接回复 「加群」 邀请你入群。
你可能还喜欢
点击下方图片即可阅读
浅谈 Kubernetes Pod 中容器的启动优先级
点击上方图片,『美团|饿了么』外卖红包天天免费领
更多有趣的互联网新鲜事,关注「奇妙的互联网」视频号全了解!