3、Pod运维:Pod创建与删除、静态Pod、Init容器、Pod健康检查
各位同学,咱们今天聊聊Pod运维。说实话,Pod是Kubernetes里最基础也最核心的单元。你想想看,整个集群跑的东西,最后都得落到Pod上。我刚开始接触K8s时,觉得Pod不就是个容器嘛,后来踩了不少坑才明白——Pod的设计远比表面复杂。
3.1 Pod的创建与删除
Pod的创建,说白了就是告诉API Server:“嘿,我要跑个东西。”然后调度器找个合适的节点,kubelet把容器拉起来。流程不复杂,但细节决定成败。
先看个最简单的例子:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
保存为 nginx-pod.yaml,然后执行:
kubectl apply -f nginx-pod.yaml
Pod就创建好了。删除也一样简单:
kubectl delete pod nginx-pod
但这里有个坑——直接删除Pod,如果它是由Deployment管理的,控制器会立刻重新创建一个。我曾经在排查问题时,直接删了个Pod想看看日志,结果新的Pod瞬间顶上来了,搞得我一脸懵。正确的做法是先停掉Deployment,或者改副本数为0。
3.2 静态Pod
静态Pod是个有意思的东西。它不由API Server管理,而是由kubelet直接读取节点上的配置文件创建的。你想想看,这意味着什么?——即使API Server挂了,静态Pod照样能跑。
我有个朋友在生产环境遇到过API Server宕机,业务全挂了。后来我建议他把核心监控组件改成静态Pod,再也没出过类似问题。
配置方法很简单:在kubelet的配置目录下放个Pod定义文件。默认路径是 /etc/kubernetes/manifests/。
# 在节点上创建
cat <<EOF > /etc/kubernetes/manifests/static-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-nginx
spec:
containers:
- name: nginx
image: nginx:1.25
EOF
kubelet会定期扫描这个目录,发现新文件就创建Pod。删除也一样,删掉文件就行。
kubectl get pod -n default 能看到静态Pod,但名字后面会带个节点名后缀。比如 static-nginx-node1。
静态Pod不能通过API Server删除,只能去节点上删文件。嗯,这里要注意——如果你用 kubectl delete 删静态Pod,kubelet会立刻重新创建它。
3.3 Init容器
Init容器,说白了就是“前置任务”。主容器启动前,先跑几个初始化任务。比如等数据库就绪、初始化数据、设置权限等。
我个人习惯把Init容器用在需要等待外部依赖的场景。举个例子:
apiVersion: v1
kind: Pod
metadata:
name: app-with-init
spec:
initContainers:
- name: wait-for-db
image: busybox
command: ['sh', '-c', 'until nc -z db-service 3306; do echo waiting for db; sleep 2; done']
containers:
- name: app
image: my-app:latest
这个Pod启动时,会先跑Init容器,不断检查数据库是否可达。直到数据库就绪了,主容器才开始启动。
Init容器有几个特点:
- 按顺序执行,一个成功后才跑下一个
- 如果失败,Pod会重启(取决于restartPolicy)
- Init容器可以有自己的镜像和命令
- 它们不占用主容器的资源限制
我曾经遇到一个案例:有个团队把数据迁移脚本放在Init容器里,结果每次Pod重启都重新跑一遍迁移,把数据库搞乱了。后来我建议他们加个判断逻辑,检查是否已经迁移过。说白了,Init容器要设计成幂等的。
3.4 Pod健康检查
健康检查是Pod运维的重头戏。Kubernetes提供了两种探针:liveness(存活探针)和readiness(就绪探针)。
liveness探针:检查容器是否还活着。如果挂了,kubelet会重启容器。
readiness探针:检查容器是否准备好接收流量。如果没准备好,Service不会把流量转发过来。
你想想看,这两个探针有什么区别?说白了,liveness管“死没死”,readiness管“能不能干活”。
看个例子:
apiVersion: v1
kind: Pod
metadata:
name: health-check-demo
spec:
containers:
- name: app
image: my-app:latest
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
这里我用了HTTP请求做检查。Kubernetes还支持TCP和命令执行两种方式:
| 探针类型 | 检查方式 | 适用场景 |
|---|---|---|
| HTTP | 发送HTTP GET请求 | Web服务、API服务 |
| TCP | 尝试建立TCP连接 | 数据库、缓存服务 |
| Exec | 在容器内执行命令 | 自定义检查逻辑 |
我个人建议:liveness探针别太敏感。initialDelaySeconds设大一点,给应用启动留足时间。periodSeconds也别太短,否则频繁检查反而增加负载。
readiness探针的用法更灵活。比如你的应用启动后需要加载大量数据,加载完才能服务。这时候readiness探针就派上用场了:
readinessProbe:
exec:
command:
- cat
- /tmp/ready
initialDelaySeconds: 5
periodSeconds: 5
应用加载完数据后,创建个 /tmp/ready 文件,探针检查通过,流量就进来了。干净利落。
嗯,最后说一句:健康检查不是万能的。它只能检查容器内部的状态,管不了外部依赖。比如你的应用依赖数据库,数据库挂了,健康检查可能还显示正常。这时候需要更上层的监控来兜底。
好了,Pod运维这块就聊到这儿。下一章咱们聊聊Pod的存储和配置管理,到时候见。