分步骤讲解Deployment故障排除
背景假设
当你希望在Kubernetes中部署应用程序时,你通常会定义三个组件:
- 一个Deployment - 这是一份用于创建你的应用程序的Pod副本的"食谱";
 - 一个Service - 一个内部负载均衡器,用于将流量路由到内部的Pod上;
 - 一个Ingress - 描述如何流量应该如何从集群外部流入到集群内部的你的服务上。
 
下面让我们用示意图快速总结一下要点。
1.在Kubernetes中,你的应用程序通过两层负载均衡器暴露服务:内部的和外部的

2.内部的负载均衡器称为Service,而外部的负载均衡器称为Ingress

3.Pod不会直接部署。Deployment会负责创建Pod并管理它们

假设你要部署一个简单的"HelloWorld"应用,该应用的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/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - http:
    paths:
    - backend:
        serviceName: app
        servicePort: 80
      path: /
这个定义很长,组件之间的相互关系并不容易看出来。
例如:
- 什么时候应使用端口80,又是何时应使用端口8080?
 - 你是否应该为每个服务创建一个新端口以免它们相互冲突?
 - 标签(label)名重要吗?它们是否在每一处都应该是一样的?
 
在进行调试之前,让我们回顾一下这三个组件是如何相互关联的。
让我们从Deployment和Service开始。
一. 连接Deployment和Service
令人惊讶的消息是,Service和Deployment之间根本没有连接。事实是:Service直接指向Pod,并完全跳过了Deployment。因此,你应该注意的是Pod和Service之间的相互关系。
应该记住三件事:
- Service selector应至少与Pod的一个标签匹配;
 - Service的targetPort应与Pod中容器的containerPort匹配;
 - Service的port可以是任何数字。多个Service可以使用同一端口号,因为它们被分配了不同的IP地址。
1.考虑上面被一个服务暴露的Pod

 
2.创建Pod时,应为Pod中的每个容器定义containerPort端口

3.当创建一个Service时,你可以定义port和targetPort,但是哪个用来连接容器呢?

- targetPort和containerPort应该始终保持匹配

 
5.如果容器暴露3000端口(containerPort),那么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顶部的track: canary标签呢?它也应该匹配吗?
该标签属于deployment,service的选择器未使用它来路由流量。换句话说,你可以安全地删除它或为其分配其他值。
那matchLabels选择器呢?
它必须始终与Pod的标签匹配,并且被Deployment用来跟踪Pod。
假设你已经进行了所有正确的设置,该如何测试它呢?你可以使用以下命令检查Pod是否具有正确的标签:
kubectl get pods --show-labels
或者,如果你拥有属于多个应用程序的Pod:
kubectl get pods --selector any-name=my-app --show-labels
any-name=my-app 就是标签:any-name: my-app。
有问题吗?你也可以连接到Pod!
你可以使用kubectl中的port-forward命令连接到service并测试连接。
kubectl port-forward service/<service name> 3000:80
- service/ 是服务的名称- 在上面的YAML中是“my-service”
 - 3000是你希望在计算机上打开的端口
 - 80是service通过 port 字段暴露的端口
 
如果可以连接,则说明设置正确。
如果不行,则很可能是你填写了错误的标签或端口不匹配。
二. 连接Service和Ingress
配置Ingress以将你的应用暴露到集群外部。
Ingress必须知道如何检索服务,然后检索Pod并将流量路由给它们。
Ingress按名字和暴露的端口检索正确的服务。
在Ingress和Service中应该匹配两件事:
1.Ingress的 servicePort 应该匹配service的 port
2.Ingress的 serviceName 应该匹配服务的 name
下面的图总结了如何连接端口:
1.你已经知道servive暴露一个port

2.Ingress有一个字段叫servicePort

3.service的port和Ingress的service应该始终保持匹配

4.如果你为service指定的port是80,那么你也应该将ingress的 servicePort 改为80

实践中,你应该查看以下几行(下面代码中的 my-service 和80):
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    any-name: my-app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - http:
    paths:
    - backend:
        serviceName: my-service
        servicePort: 80
      path: /
如何测试Ingress是否正常工作呢?
可以使用与以前相同的策略kubectl port-forward,但是这次你应该连接到Ingress控制器,而不是连接到Service。
首先,使用以下命令检索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
此时,每次你访问计算机上的端口3000时,请求都会转发到Ingress控制器Pod上的端口80。
如果访问 http://localhost:3000,则应找到提供网页服务的应用程序。
回顾Port
1.service selector应与Pod的标签匹配
2.service的 targetPort 应与Pod中容器的 containerPort 匹配
3.service的端口可以是任何数字。多个服务可以使用同一端口,因为它们分配了不同的IP地址。
4.ingress的 servicePort 应该匹配 service 的 port
5.serivce的名称应与 ingress 中的 serviceName 字段匹配
三. k8s deployment故障排除的步骤
由于每个deployment中都有三个组件,因此你应该自下而上依次调试所有组件。
1.你应该先确保Pods正在运行
2.然后,专注于让service将流量路由到到正确的Pod
3.再检查是否正确配置了Ingress
1.你应该从底部开始对deployment进行故障排除。首先,检查Pod是否已就绪并正在运行。

2.如果Pod已就绪,则应调查service是否可以将流量分配给Pod。

3.最后,你应该检查service与ingress之间的连接。

1. 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
在上述会话中,最后一个Pod处于就绪并正常运行的状态;但是,前两个Pod既不处于Running也不是Ready。
有四个有用的命令可以对Pod进行故障排除:
kubectl logs <pod name>有助于检索Pod容器的日志kubectl describe pod <pod name>检索与Pod相关的事件列表kubectl get pod <pod name>用于提取存储在Kubernetes中的Pod的YAML定义kubectl exec -ti <pod name> bash在Pod的一个容器中运行交互式命令
常见Pod错误
启动错误包括:
- ImageInspectError
 - ErrImagePull
 - ErrImageNeverPull
 - RegistryUnavailable
 - InvalidImageName交互式命令
 
运行时错误包括:
- CrashLoopBackOff
 - RunContainerError
 - KillContainerError
 - VerifyNonRootError
 - RunInitContainerError
 - CreatePodSandboxError
 - ConfigPodSandboxError
 - KillPodSandboxError
 - SetupNetworkError
 - TeardownNetworkError
 
以下是最常见的错误列表以及如何修复它们的方法。
# ImagePullBackOff
当Kubernetes无法获取到Pod中某个容器的镜像时,将出现此错误。
共有三个可能的原因:
- 镜像名称无效-例如,你拼错了名称,或者image不存在
 - 你为image指定了不存在的标签
 - 你尝试检索的image属于一个私有registry,而Kubernetes没有凭据可以访问它
 
前两种情况可以通过更正image名称和标记来解决。
针对第三种情况,你应该将私有registry的访问凭证通过Secret添加到k8s中并在Pod中引用它。
# CrashLoopBackOff
如果容器无法启动,则Kubernetes将显示错误状态为:CrashLoopBackOff。
通常,在以下情况下容器无法启动:
- 应用程序中存在错误,导致无法启动
 - 你未正确配置容器
 - Liveness探针失败太多次
 
你应该尝试从该容器中检索日志以调查其失败的原因。
如果由于容器重新启动太快而看不到日志,则可以使用以下命令:
$ kubectl logs <pod-name> --previous
这个命令打印前一个容器的错误消息。
# RunContainerError
当容器无法启动时,出现此错误。
甚至在容器内的应用程序启动之前。
该问题通常是由于配置错误,例如:
- 挂载不存在的卷,例如ConfigMap或Secrets
 - 将只读卷安装为可读写
 
你应该使用 kubectl describe pod <pod-name>命令收集和分析错误。
# 处于Pending状态的Pod
当创建Pod时,该Pod保持Pending状态。
为什么?
假设你的调度程序组件运行良好,可能的原因如下:
- 集群没有足够的资源(例如CPU和内存)来运行Pod
 - 当前的命名空间具有ResourceQuota对象,创建Pod将使命名空间超过配额
 - 该Pod绑定到一个处于pending状态的 PersistentVolumeClaim
 
最好的选择是检查kubectl describe命令输出的“事件”部分内容:
$ kubectl describe pod <pod name>
对于因ResourceQuotas而导致的错误,可以使用以下方法检查集群的日志:
$ kubectl get events --sort-by=.metadata.creationTimestamp
# 处于未就绪状态的Pod
如果Pod正在运行但未就绪(not ready),则表示readiness就绪探针失败。
当“就绪”探针失败时,Pod未连接到服务,并且没有流量转发到该实例。
就绪探针失败是应用程序的特定错误,因此你应检查 kubectl describe 中的 Events 部分以识别错误。
# 2. 服务的故障排除
如果你的Pod正在运行并处于就绪状态,但仍无法收到应用程序的响应,则应检查服务的配置是否正确。
service旨在根据流量的标签将流量路由到Pod。
因此,你应该检查的第一件事是服务关联了多少个Pod。
你可以通过检查服务中的端点(endpoint)来做到这一点:
$ kubectl describe service <service-name> | grep Endpoints
端点是一对,并且在服务(至少)以Pod为目标时,应该至少有一个端点。
如果“端点”部分为空,则有两种解释:
- 你没有运行带有正确标签的Pod(提示:你应检查自己是否在正确的命名空间中)
 - service的 
selector标签上有拼写错误 
如果你看到端点列表,但仍然无法访问你的应用程序,则 targetPort 可能是你服务中的罪魁祸首。
你如何测试服务?
无论服务类型如何,你都可以使用 kubectl port-forward 来连接它:
$ kubectl port-forward service/<service-name> 3000:80
这里:
<service-name>是服务的名称3000是你希望在计算机上打开的端口80是服务公开的端口
# 3.Ingress的故障排除
如果你已到达本节,则:
- Pod正在运行并准备就绪
 - 服务会将流量分配到Pod
 
但是你仍然看不到应用程序的响应。
这意味着最有可能是Ingress配置错误。
由于正在使用的Ingress控制器是集群中的第三方组件,因此有不同的调试技术,具体取决于Ingress控制器的类型。
但是在深入研究Ingress专用工具之前,你可以用一些简单的方法进行检查。
Ingress使用 serviceName 和 servicePort 连接到服务。
你应该检查这些配置是否正确。
你可以通过下面命令检查Ingress配置是否正确:
$ kubectl describe ingress <ingress-name>
如果backend一列为空,则配置中必然有一个错误。
如果你可以在“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 以检索端口:
$ kubectl describe pod nginx-ingress-controller-6fc5bcc --namespace kube-system \ | grep Ports
最后,连接到Pod:
$ kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
此时,每次你访问计算机上的端口3000时,请求都会转发到Pod上的端口80。
现在可以用吗?
- 如果可行,则问题出在基础架构中。你应该调查流量如何路由到你的集群。
 - 如果不起作用,则问题出在Ingress控制器中。你应该调试Ingress。
 
如果仍然无法使Ingress控制器正常工作,则应开始对其进行调试。
目前有许多不同版本的Ingress控制器。
热门选项包括Nginx,HAProxy,Traefik等。
你应该查阅Ingress控制器的文档以查找故障排除指南。
是使用比较多的的Ingress控制器之一,因此在下一部分中我们将介绍一些有关调试ingress-nginx的技巧。
如果参考 kuboard.cn 上的 Kubernetes 安装文档,您安装的 Ingress 控制器是 nginx ingress
,和
# 调试Ingress Nginx
Ingress-nginx 项目有一个 kubectl 的官方插件
你可以用kubectl ingress-nginx来:
- 检查日志,后端,证书等
 - 连接到ingress
 - 检查当前配置
 
你应该尝试的三个命令是:
kubectl ingress-nginx lint,它会检查nginx.confkubectl ingress-nginx backend,以检查后端(类似于kubectl describe ingress <ingress-name>)kubectl ingress-nginx logs,查看日志
请注意,你可能需要为Ingress控制器指定正确的名称空间
--namespace <name>。
四 总结
如果你不知道从哪里开始,那就从Pod开始,然后通过Service和Ingress向上移动堆栈。
分步骤讲解Deployment故障排除的更多相关文章
- Kubernetes Deployment故障排除图解指南
		
个人K8s还在学习中,相关博客还没有写,准备学第二遍再开始学,发现这篇文章挺好,先转载一下. 原创: 白明的赞赏账户 下面是一个示意图,可帮助你调试Kubernetes Deployment(你可以 ...
 - Deployment故障排除图解
		
PDF文件下载地址:https://files.cnblogs.com/files/sanduzxcvbnm/troubleshooting-kubernetes.pdf
 - 针对通过 SSH 连接到 Azure Linux VM 时发生的失败、错误或被拒绝问题进行故障排除
		
尝试连接到 Linux 虚拟机 (VM) 时,有多种原因可能会导致安全外壳 (SSH) 错误.SSH 连接失败或被拒绝. 本文帮助用户找出原因并更正问题. 可以使用 Azure 门户.Azure CL ...
 - 详细故障排除步骤:针对 Azure 中到 Windows VM 的远程桌面连接问题
		
本文提供详细的故障排除步骤,用于为基于 Windows 的 Azure 虚拟机诊断和修复复杂的远程桌面错误. Important 若要消除更常见的远程桌面错误,请务必先阅读远程桌面的基本故障排除文章, ...
 - 对连接到 Azure 中 Linux VM 时出现的问题进行详细的 SSH 故障排除的步骤
		
有许多可能的原因会导致 SSH 客户端无法访问 VM 上的 SSH 服务. 如果已经执行了较常规的 SSH 故障排除步骤,则需要进一步排查连接问题. 本文指导用户完成详细的故障排除步骤,以确定 SSH ...
 - 对NetBackup 问题进行故障排除的步骤
		
错误消息通常是指出哪里出现故障的手段.如果在界面上没有看到错误消息,但仍怀疑有问题,请检查报告和日志. NetBackup提供了各种报告和日志记录工具, 这些工具可提供错误消息,直接为您指出解决方案. ...
 - Kubernetes中Deployment部署故障排除
		
Kubernetes中Deployment部署故障排除 字符型思维导图 排查pod状态(带标签):kubectl get pods,是否有等待处理的pod? 是?kubectl describe po ...
 - 理解 OpenStack + Ceph (7): Ceph 的基本操作和常见故障排除方法
		
本系列文章会深入研究 Ceph 以及 Ceph 和 OpenStack 的集成: (1)安装和部署 (2)Ceph RBD 接口和工具 (3)Ceph 物理和逻辑结构 (4)Ceph 的基础数据结构 ...
 - ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)
		
Copyright (c) 2019, Oracle. All rights reserved. Oracle Confidential. ORA-4031 错误故障排除与诊断[视频] (Do ...
 
随机推荐
- MIT 6.824 Lab2C Raft之持久化
			
书接上文Raft Part B | MIT 6.824 Lab2B Log Replication. 实验准备 实验代码:git://g.csail.mit.edu/6.824-golabs-2021 ...
 - JetBrains系列IDE创建文件模板
			
#coding:utf-8 ''' @version: python3.6 @author: '$USER' @license: Apache Licence @contact: steinven@q ...
 - IDEA快捷键之html篇-1
			
前端IDE中Emmet插件快捷输入HTML代码 前端IDE如VSCode.Atom.Sublime Text和Intellij Idea中使用Emmet插件快捷输入HTML代码的介绍 前端IDE中 ...
 - 04 MySQL_数据相关的SQL
			
字符编码问题: 如果使用Windows电脑SQL语句中写中文报错的话,通过以下指令解决 set names gbk; 判空NULL问题: 判值用=,判空用is xxx = 非空值; xxx is nu ...
 - Linux综合运用
			
一. Linux用户和组及其权限管理 请根据以下项目要求,写出操作过程和命令并进行相应的验证测试操作. 项目要求: 某软件开发公司即将开始在Linux系统上进行项目的开发.要实现的环境是:公司有软件开 ...
 - CF1706A Another String Minimization Problem 题解
			
题意 给定一个长度为 \(n\) 的序列 \(a\) 以及一个长度为 \(m\) 的字符串 \(s\),初始 \(s\) 均为 \(\text{B}\),第 \(i\) 次操作可以把 \(s_{a_i ...
 - Windows下通过dos来编译c语言源代码文件
			
笔者阅览过网上许多的推荐,基本上都是推荐cl命令,但是因为笔者是通过dev c++入门的,不想放弃dev所以就强行使用dev来实现在dos下的编译以及运行 编译 注意:这边涉及到环境变量的配置,环境变 ...
 - 题解【CodeForces 910A The Way to Home】
			
题目大意 一只青蛙现在在一个数轴上,它现在要从点 \(1\) 跳到点 \(n\) ,它每次可以向右跳不超过 \(d\) 个单位.比如,它可以从点 \(x\) 跳到点 \(x+a\)(\(1\le a\ ...
 - DolphinScheduler 线上 Meetup 视频回放(07.25)
			
上周六下午 DolphinScheduler 社区联合 Doris 社区进行了 2020 年首次线上 Meetup,各位讲师都做了非常精彩的分享,也吸引了 1900 多位技术伙伴观看. 其中 Dolp ...
 - Redis 08 地理位置
			
参考源 https://www.bilibili.com/video/BV1S54y1R7SB?spm_id_from=333.999.0.0 版本 本文章基于 Redis 6.2.6 Redis 的 ...