3. Pod深入理解:Pod生命周期、静态Pod、Init容器、容器探针
大家好,我是你们的云原生架构师。今天我们来聊聊Pod——这个Kubernetes世界里最基础的调度单元。说实话,很多新手把Pod当成“一组容器的集合”就完事了,但真正在生产环境里踩过坑的人都知道,Pod的生命周期管理、初始化流程、健康检查,每一个细节都可能让你半夜被报警电话叫醒。
我个人习惯把Pod比作一个“微型服务器”。它有自己的生命周期,从出生到死亡;它需要初始化配置,就像服务器上电后要加载BIOS;它还需要健康检查,就像运维人员每天巡检服务器状态。好,我们一个一个来看。
3.1 Pod生命周期
Pod的生命周期,说白了就是它从创建到销毁的全过程。Kubernetes用一组状态来跟踪这个过程:Pending、Running、Succeeded、Failed、Unknown。
为什么会这样设计?你想想看,一个Pod里可能跑着多个容器,每个容器的启动速度不一样,有的容器可能启动失败,有的容器可能一直在运行。Kubernetes需要一种统一的方式来描述Pod的整体状态。
| 状态 | 说明 | 常见场景 |
|---|---|---|
| Pending | Pod已被集群接受,但容器尚未全部启动 | 镜像拉取中、调度等待中 |
| Running | Pod已绑定到节点,所有容器已创建 | 至少一个容器正在运行或正在启动 |
| Succeeded | Pod中所有容器成功退出 | Job任务执行完毕 |
| Failed | Pod中至少一个容器以非零状态退出 | 应用崩溃、配置错误 |
| Unknown | 无法获取Pod状态 | 节点失联、网络分区 |
我在项目中遇到过这样一个案例:一个微服务Pod一直卡在Pending状态,排查了半天,发现是镜像仓库的认证信息过期了。嗯,这里要注意,Pending状态不等于“正在启动”,它可能意味着调度失败、资源不足、或者镜像拉取失败。
3.2 静态Pod
静态Pod,是Kubernetes里一个比较特殊的存在。它不由API Server管理,而是由kubelet直接管理。说白了,就是kubelet在本地节点上根据配置文件直接创建的Pod。
为什么会需要静态Pod?我举个例子:Kubernetes集群自身的核心组件,比如kube-apiserver、kube-controller-manager,它们本身也是Pod。但如果API Server挂了,谁来创建这些Pod?这时候静态Pod就派上用场了——kubelet可以直接从本地文件读取Pod定义,不需要依赖API Server。
静态Pod的配置文件通常放在kubelet的--pod-manifest-path指定的目录下,默认是/etc/kubernetes/manifests。
# 示例:静态Pod配置文件
# /etc/kubernetes/manifests/static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
role: myrole
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
你想想看,kubelet会定期扫描这个目录,发现新的yaml文件就创建Pod,文件被删除就销毁Pod。但注意,静态Pod不能被API Server直接删除,你只能通过删除本地文件来停止它。
3.3 Init容器
Init容器,顾名思义,是用于初始化的容器。它在应用容器启动之前运行,并且必须成功退出后,应用容器才会启动。
为什么需要Init容器?我遇到过这样一个场景:一个Java应用启动前需要等待MySQL数据库就绪,还需要从Git仓库拉取配置文件。这些初始化任务如果放在应用容器里,会让应用镜像变得臃肿,而且初始化逻辑和业务逻辑耦合在一起。
Init容器的典型用法:
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
spec:
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
containers:
- name: myapp
image: myapp:1.0
ports:
- containerPort: 8080
这里有几个关键点:
- Init容器总是运行到成功完成为止
- 如果Init容器失败,Kubernetes会重启它(取决于Pod的restartPolicy)
- 所有Init容器都成功完成后,应用容器才会启动
- Init容器不支持readiness探针,因为它们必须在启动前完成
我曾经用Init容器解决过一个棘手的问题:一个遗留应用需要从S3下载一个几百MB的模型文件,下载过程耗时5分钟。如果把这个逻辑放在应用容器里,会导致Pod启动后长时间无法响应readiness探针,被Service剔除。用Init容器来处理下载,应用容器启动时模型文件已经就绪,完美解决。
3.4 容器探针(Liveness/Readiness/Startup)
容器探针,是Kubernetes用来检测容器健康状态的机制。说白了,就是Kubernetes定期给容器做“体检”,根据体检结果决定下一步操作。
三种探针各有分工:
| 探针类型 | 作用 | 失败后的行为 |
|---|---|---|
| Liveness Probe | 检测容器是否存活 | 重启容器 |
| Readiness Probe | 检测容器是否就绪 | 从Service Endpoints中移除 |
| Startup Probe | 检测容器是否启动完成 | 延迟其他探针的检查 |
你想想看,如果没有探针,Kubernetes怎么知道你的应用是活着还是死了?它只能看到容器进程是否在运行。但进程在运行不代表应用可用——比如Java应用发生了Full GC导致长时间停顿,或者应用陷入了死锁。
3.4.1 Liveness Probe(存活探针)
Liveness探针用于判断容器是否“活着”。如果探针失败,kubelet会杀死容器并重启它。
apiVersion: v1
kind: Pod
metadata:
name: liveness-demo
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
这个例子中,容器启动后创建了一个文件,30秒后删除。Liveness探针每5秒检查一次文件是否存在。30秒后文件被删除,探针失败,容器被重启。
3.4.2 Readiness Probe(就绪探针)
Readiness探针用于判断容器是否“准备好”接收流量。如果探针失败,Pod会被从Service的Endpoints列表中移除,但容器不会被重启。
apiVersion: v1
kind: Pod
metadata:
name: readiness-demo
spec:
containers:
- name: readiness
image: nginx
readinessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 3
periodSeconds: 5
这个例子中,Readiness探针通过HTTP GET请求检查/healthz端点。如果返回200-399状态码,则认为就绪;否则认为未就绪。
我个人习惯在应用里专门实现一个/healthz端点,不仅检查进程是否存活,还检查依赖的服务(比如数据库、缓存)是否可用。这样Readiness探针才能真正反映应用的就绪状态。
3.4.3 Startup Probe(启动探针)
Startup探针是Kubernetes 1.16引入的,专门解决慢启动容器的问题。你想想看,有些Java应用启动需要2-3分钟,如果Liveness探针设置得太早,应用还没启动完成就被判定为不健康,反复重启,陷入死循环。
apiVersion: v1
kind: Pod
metadata:
name: startup-demo
spec:
containers:
- name: startup
image: myapp:1.0
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Startup探针的工作原理:在Startup探针成功之前,其他探针(Liveness和Readiness)不会启动。Startup探针失败30次(failureThreshold: 30,每次间隔10秒)后,容器被重启。也就是说,这个应用最多有300秒的启动时间。
3.5 三种探针的协同工作
三种探针不是孤立的,它们协同工作,形成一个完整的健康检查体系:
- 启动阶段:Startup探针负责检测应用是否启动完成。在此期间,Liveness和Readiness探针被禁用。
- 运行阶段:Startup探针成功后,Liveness探针开始工作,确保应用持续存活。如果应用挂掉,Liveness探针触发重启。
- 流量管理:Readiness探针全程工作,控制Pod是否接收流量。即使应用存活,如果Readiness探针失败,流量也会被切断。
我曾经遇到过一个典型案例:一个内存密集型的应用,在GC时CPU飙升,导致Liveness探针超时,容器被重启。但实际上应用只是在进行正常的GC操作。解决方案是:把Liveness探针的超时时间设长一些,同时增加一个更轻量级的Readiness探针,只检查应用的核心功能是否可用。
- Liveness探针:保命用的,失败就重启
- Readiness探针:控流用的,失败就切流量
- Startup探针:护启动用的,给慢应用争取时间
好了,关于Pod的深入理解就讲到这里。下一章我们会聊聊Pod的资源管理和调度策略,到时候我会分享一些我在生产环境中做资源限制和QoS配置的实战经验。记得动手实践,光看不练是学不会Kubernetes的。