**摘要:**本文系统梳理了 Kubernetes 中 Pod 的核心知识。首先介绍 Kubernetes 的资源抽象与三种资源管理方式,以及 kubectl 命令基础;随后重点讲解 Pod 的定义、自主式 Pod 与控制器管理 Pod 的对比,并通过 9 个 YAML 示例覆盖 Pod 的常用配置;最后深入解析 Pod 的生命周期,包括 Init 容器的作用与示例,以及存活探针、就绪探针和启动探针的区别与配置方法。
一、Kubernetes 中的资源
1.1 资源管理介绍
在 Kubernetes 中,所有的内容都抽象为资源,用户需要通过操作资源来管理 Kubernetes。Kubernetes 的本质就是一个集群系统,用户可以在集群中部署各种服务。所谓的部署服务,其实就是在 Kubernetes 集群中运行一个个的容器,并将指定的程序跑在容器中。
Kubernetes 的最小管理单元是 Pod 而不是容器,只能将容器放在 Pod 中。Kubernetes 一般也不会直接管理 Pod,而是通过 Pod 控制器来管理 Pod 的。Pod 中服务的访问是由 Kubernetes 提供的 Service 资源来实现,Pod 中程序的数据需要持久化是由 Kubernetes 提供的各种存储系统来实现。
1.2 资源管理方式
Kubernetes 提供了三种资源管理方式:
- 命令式对象管理 :直接使用命令去操作 Kubernetes 资源,例如
kubectl run nginx-pod --image=nginx:latest --port=80。 - 命令式对象配置 :通过命令配置和配置文件去操作 Kubernetes 资源,例如
kubectl create/patch -f nginx-pod.yaml。 - 声明式对象配置 :通过 apply 命令和配置文件去操作 Kubernetes 资源,例如
kubectl apply -f nginx-pod.yaml。
| 类型 | 适用环境 | 优点 | 缺点 |
|---|---|---|---|
| 命令式对象管理 | 测试 | 简单 | 只能操作活动对象,无法审计、跟踪 |
| 命令式对象配置 | 开发 | 可以审计、跟踪 | 项目大时,配置文件多,操作麻烦 |
| 声明式对象配置 | 开发 | 支持目录操作 | 意外情况下难以调试 |
1.3 kubectl 命令基础
kubectl 是 Kubernetes 集群的命令行工具,通过它能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。kubectl 命令的语法如下:
bash
kubectl [command] [type] [name] [flags]
- command:指定要对资源执行的操作,例如 create、get、delete。
- type:指定资源类型,比如 deployment、pod、service。
- name:指定资源的名称,名称大小写敏感。
- flags:指定额外的可选参数。
常用资源类型可以通过 kubectl api-resources 查看。常见命令操作示例如下:
bash
# 查看所有 pod
kubectl get pod
# 查看某个 pod
kubectl get pod pod_name
# 查看某个 pod,以 yaml 格式展示结果
kubectl get pod pod_name -o yaml
二、什么是 Pod
Pod 是可以创建和管理 Kubernetes 计算的最小可部署单元。一个 Pod 代表着集群中运行的一个进程,每个 Pod 都有一个唯一的 IP。一个 Pod 类似一个豌豆荚,包含一个或多个容器(通常是 Docker),多个容器间共享 IPC、Network 和 UTC namespace。
2.1 创建自主式 Pod(生产不推荐)
自主式 Pod 是指直接通过 kubectl run 等方式手动创建的 Pod,不经过控制器管理。
优点:
- 灵活性高:可以精确控制 Pod 的各种配置参数,包括容器的镜像、资源限制、环境变量、命令和参数等,满足特定的应用需求。
- 学习和调试方便:对于学习 Kubernetes 的原理和机制非常有帮助,通过手动创建 Pod 可以深入了解 Pod 的结构和配置方式。在调试问题时,可以更直接地观察和调整 Pod 的设置。
- 适用于特殊场景:在一些特殊情况下,如进行一次性任务、快速验证概念或在资源受限的环境中进行特定配置时,手动创建 Pod 可能是一种有效的方式。
缺点:
- 管理复杂:如果需要管理大量的 Pod,手动创建和维护会变得非常繁琐和耗时,难以实现自动化的扩缩容、故障恢复等操作。
- 缺乏高级功能:无法自动享受 Kubernetes 提供的高级功能,如自动部署、滚动更新、服务发现等,这可能导致应用的部署和管理效率低下。
- 可维护性差:手动创建的 Pod 在更新应用版本或修改配置时需要手动干预,容易出现错误,并且难以保证一致性。
2.2 利用控制器管理 Pod(推荐)
通过 Pod 控制器(如 Deployment)管理 Pod 是生产环境的推荐方式,具有以下优势:
- 高可用性和可靠性:如果一个 Pod 失败或被删除,控制器会自动创建新的 Pod 来维持期望的副本数量,确保应用始终处于可用状态。可以配置控制器对 Pod 进行健康检查(如存活探针和就绪探针),如果 Pod 不健康,控制器会采取适当的行动,如重启 Pod 或删除并重新创建它。
- 可扩展性:可以通过简单的命令或配置更改来增加或减少 Pod 的数量,以满足不同的工作负载需求。还可以基于自定义指标(如 CPU 利用率、内存使用情况或应用特定的指标)自动调整 Pod 的数量,实现动态的资源分配和成本优化。
- 版本管理和更新:对于 Deployment 等控制器,可以执行滚动更新来逐步替换旧版本的 Pod 为新版本,确保应用在更新过程中始终保持可用。如果更新出现问题,可以轻松回滚到上一个稳定版本。
- 声明式配置:使用 YAML 或 JSON 格式的声明式配置文件来定义应用的部署需求,只需要定义应用的期望状态(如副本数量、容器镜像等),控制器会自动调整实际状态与期望状态保持一致。
- 服务发现和负载均衡:Kubernetes 中的服务(Service)可以自动发现由控制器管理的 Pod,并将流量路由到它们,可以根据不同的策略(如轮询、随机等)将请求分发到不同的 Pod。
- 多环境一致性:在不同的环境(如开发、测试、生产)中,可以使用相同的控制器和配置来部署应用,确保应用在不同环境中的行为一致。
2.3 应用版本的更新
通过控制器可以方便地进行应用的扩容、缩容和版本更新。示例:
bash
# 建立控制器并自动运行 pod
kubectl create deployment timinglee --image nginx
# 为 timinglee 扩容到 6 个副本
kubectl scale deployment timinglee --replicas 6
# 查看 pod 列表
kubectl get pods
2.4 Pod 的 YAML 配置
2.4.1 获取资源帮助
可以使用 kubectl explain 命令查看资源的详细定义:
bash
kubectl explain pod
kubectl explain pod.spec
kubectl explain pod.spec.containers
2.4.2 常用字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| spec.containers | Object | 定义 Pod 中的容器列表 |
| spec.nodeSelector | Object | 定义 Node 的 Label 过滤标签,以 key:value 格式指定 |
| spec.imagePullSecrets | Object | 定义 pull 镜像时使用 secret 名称,以 name:secretkey 格式指定 |
| spec.hostNetwork | Boolean | 定义是否使用主机网络模式,默认值为 false。设置 true 表示使用宿主机网络,不使用 docker 网桥,同时设置了 true 将无法在同一台宿主机上启动第二个副本 |
2.4.3 示例 1:运行简单的单个容器 Pod
用命令获取 yaml 模板:
bash
kubectl run timinglee --image myapp:v1 --dry-run=client -o yaml > pod.yml
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: timing # pod 标签
name: timinglee # pod 名称
spec:
containers:
- image: myapp:v1 # pod 镜像
name: timinglee # 容器名称
2.4.4 示例 2:运行多个容器 Pod
注意:如果多个容器运行在一个 Pod 中,资源共享的同时在使用相同资源时也会干扰,比如端口。在一个 Pod 中开启多个容器时一定要确保容器彼此不能互相干扰。
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: timing
name: timinglee
spec:
containers:
- image: nginx:latest
name: web1
- image: nginx:latest
name: web2
如果两个容器都使用 80 端口,会出现端口冲突,导致 Pod 启动失败:
bash
# 查看日志
kubectl logs timinglee web2
# 输出:bind() to [::]:80 failed (98: Address already in use)
2.4.5 示例 3:理解 Pod 间的网络整合
同在一个 Pod 中的容器公用一个网络,可以通过 localhost 互相访问。示例:
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: timinglee
name: test
spec:
containers:
- image: myapp:v1
name: myapp1
- image: busyboxplus:latest
name: busyboxplus
command: ["/bin/sh","-c","sleep 1000000"]
bash
# 在 busyboxplus 容器中通过 localhost 访问 myapp1
kubectl exec test -c busyboxplus -- curl -s localhost
# 输出:Hello MyApp | Version: v1 | Pod Name
2.4.6 示例 4:端口映射
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: timinglee
name: test
spec:
containers:
- image: myapp:v1
name: myapp1
ports:
- name: http
containerPort: 80
hostPort: 80
protocol: TCP
2.4.7 示例 5:如何设定环境变量
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: timinglee
name: test
spec:
containers:
- image: busybox:latest
name: busybox
command: ["/bin/sh","-c","echo $NAME;sleep 3000000"]
env:
- name: NAME
value: timinglee
2.4.8 示例 6:资源限制
资源限制会影响 Pod 的 QoS Class 资源优先级,资源优先级分为 Guaranteed > Burstable > BestEffort。QoS(Quality of Service)即服务质量。
| 资源设定 | 优先级类型 |
|---|---|
| 资源限定未设定 | BestEffort |
| 资源限定设定且最大和最小不一致 | Burstable |
| 资源限定设定且最大和最小一致 | Guaranteed |
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: timinglee
name: test
spec:
containers:
- image: myapp:v1
name: myapp
resources:
limits: # pod 使用资源的最高限制
cpu: 500m
memory: 100M
requests: # pod 期望使用资源量,不能大于 limits
cpu: 500m
memory: 100M
2.4.9 示例 7:容器启动管理
restartPolicy 定义了容器的重启策略:
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: timinglee
name: test
spec:
restartPolicy: Always
containers:
- image: myapp:v1
name: myapp
2.4.10 示例 8:选择运行节点
通过 nodeSelector 可以将 Pod 调度到指定的节点上:
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: timinglee
name: test
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node1
restartPolicy: Always
containers:
- image: myapp:v1
name: myapp
2.4.11 示例 9:共享宿主机网络
设置 hostNetwork 为 true 后,Pod 直接使用宿主机网络,不使用 docker 网桥:
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: timinglee
name: test
spec:
hostNetwork: true
restartPolicy: Always
containers:
- image: busybox:latest
name: busybox
command: ["/bin/sh","-c","sleep 100000"]
三、Pod 的生命周期
3.1 Init 容器
Pod 可以包含多个容器,应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。Init 容器与普通的容器非常像,除了如下两点:
- 它们总是运行到完成。
- Init 容器不支持 Readiness,因为它们必须在 Pod 就绪之前运行完成,每个 Init 容器必须运行成功,下一个才能够运行。
如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。但是,如果 Pod 对应的 restartPolicy 值为 Never,它不会重新启动。
3.1.1 Init 容器的功能
- Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。
- Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
- 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
- Init 容器能以不同于 Pod 内应用容器的文件系统视图运行。因此,Init 容器可具有访问 Secrets 的权限,而应用容器不能够访问。
- 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod 内的所有的应用容器会并行启动。
3.1.2 Init 容器示例
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
name: initpod
name: initpod
spec:
containers:
- image: myapp:v1
name: myapp
initContainers:
- name: init-myservice
image: busybox
command: ["sh","-c","until test -e /testfile;do echo wating for myservice; sleep 2;done"]
bash
# 查看 pod 状态,此时处于 Init:0/1
kubectl get pods
# 查看 init 容器日志
kubectl logs pods/initpod init-myservice
# 手动创建 /testfile 文件,触发 init 容器完成
kubectl exec pods/initpod -c init-myservice -- /bin/sh -c "touch /testfile"
# 再次查看,pod 已进入 Running 状态
kubectl get pods
3.2 探针
探针是由 kubelet 对容器执行的定期诊断,支持三种探测方式:
- ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
- TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于 200 且小于 400,则诊断被认为是成功的。
每次探测都将获得以下三种结果之一:
- 成功:容器通过了诊断。
- 失败:容器未通过诊断。
- 未知:诊断失败,因此不会采取任何行动。
Kubelet 可以选择是否执行在容器上运行的三种探针:
- livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其重启策略的影响。如果容器不提供存活探针,则默认状态为 Success。
- readinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success。
- startupProbe:指示容器中的应用是否已经启动。如果提供了启动探测,则禁用所有其他探测,直到它成功为止。如果启动探测失败,kubelet 将杀死容器,容器服从其重启策略进行重启。如果容器没有提供启动探测,则默认状态为成功 Success。
ReadinessProbe 与 LivenessProbe 的区别:
- ReadinessProbe 当检测失败后,将 Pod 的 IP:Port 从对应的 EndPoint 列表中删除。
- LivenessProbe 当检测失败后,将杀死容器并根据 Pod 的重启策略来决定作出对应的措施。
StartupProbe 与 ReadinessProbe、LivenessProbe 的区别:
- 如果三个探针同时存在,先执行 StartupProbe 探针,其他两个探针将会被暂时禁用,直到 Pod 满足 StartupProbe 探针配置的条件,其他 2 个探针启动,如果不满足按照规则重启容器。
- 另外两种探针在容器启动后,会按照配置,直到容器消亡才停止探测,而 StartupProbe 探针只是在容器启动后按照配置满足一次后,不再进行后续的探测。
3.2.1 存活探针示例
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
name: liveness
name: liveness
spec:
containers:
- image: myapp:v1
name: myapp
livenessProbe:
tcpSocket: # 检测端口存在性
port: 8080
initialDelaySeconds: 3 # 容器启动后要等待多少秒后探针开始工作,默认是 0
periodSeconds: 1 # 执行探测的时间间隔,默认为 10s
timeoutSeconds: 1 # 探针执行检测请求后,等待响应的超时时间,默认为 1s
3.2.2 就绪探针示例
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
name: readiness
name: readiness
spec:
containers:
- image: myapp:v1
name: myapp
readinessProbe:
httpGet:
path: /test.html
port: 80
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 1
当就绪探针探测失败时,Pod 的 IP 不会加入 Service 的 Endpoints 中;当探测成功后,才会暴露端口:
bash
# 查看 service 的 Endpoints,此时为空
kubectl describe services readiness
# 创建 /test.html 文件,使就绪探针探测成功
kubectl exec pods/readiness -c myapp -- /bin/sh -c "echo test > /usr/share/nginx/html/test.html"
# 再次查看,Endpoints 已包含 Pod 的 IP
kubectl describe services readiness
四、总结
本文围绕 Kubernetes 中 Pod 的核心知识进行了系统梳理。首先介绍了 Kubernetes 的资源抽象模型,以及命令式对象管理、命令式对象配置和声明式对象配置三种资源管理方式,并讲解了 kubectl 命令的基础用法。
随后重点讲解了 Pod 的定义与特性,对比了自主式 Pod 与控制器管理 Pod 的优劣,指出生产环境应优先使用 Deployment 等控制器来管理 Pod,以获得高可用、可扩展、滚动更新和声明式配置等能力。在 Pod 的 YAML 配置部分,通过 9 个示例覆盖了单容器、多容器、网络整合、端口映射、环境变量、资源限制、重启策略、节点选择以及宿主机网络等常用场景。
最后深入解析了 Pod 的生命周期,包括 Init 容器的作用与示例,以及存活探针、就绪探针和启动探针三种探针的区别与配置方法。理解这些知识,是掌握 Kubernetes 应用部署与运维的基础。