前言
在 Kubernetes 中,Pod 是最小的可部署计算单元,也是所有工作负载的载体。无论是 Deployment、ReplicaSet 还是 Job,最终都会以 Pod 的形式运行在集群节点上。因此,掌握 Pod 的创建、管理、资源声明以及生命周期控制,是玩转 K8s 的第一步。
本文基于实战笔记整理,从命令式对象管理讲到 YAML 声明式配置,再到 Pod 的生命周期与探针机制,带你完整走一遍 Pod 管理的核心知识点。所有命令均在 kubeadm 搭建的 1.35 版本集群实测。
实验环境说明 :集群包含
k8s-master、k8s-node1、k8s-node2三个节点;私有镜像仓库地址为reg.timinglee.org,实验镜像为myapp:v1/myapp:v2(基于 Nginx 的演示镜像,访问根路径会返回Hello MyApp | Version: vX)。你可以用自己的镜像或 Docker Hub 公开镜像替换。
一、命令式对象管理
1.1 命名空间(Namespace)管理
命名空间用于在一个物理集群中隔离不同的项目或环境。默认集群自带几个系统命名空间:default、kube-system、kube-public、kube-node-lease 等。
# 查看所有命名空间
kubectl get namespaces
# 创建命名空间
kubectl create namespace timinglee
# 删除命名空间(其内部所有资源会一并删除,谨慎操作)
kubectl delete namespace timinglee
💡 提示:大多数日常实验都在 default 命名空间中操作即可,无需频繁切换。
1.2 Pod 的创建、查看与删除
最简单的方式是使用 kubectl run 命令式地创建一个 Pod:
# 创建一个名为 lee 的 Pod,使用 nginx:latest 镜像
kubectl run lee --image nginx:latest
pod/lee created
# 查看 Pod 运行状态及所在节点(-o wide 显示更详细信息)
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
lee 1/1 Running 0 25s 10.244.1.10 k8s-node1 <none> <none>
当镜像不存在或拉取失败时,Pod 会处于异常状态:
# 使用一个不存在的镜像
kubectl run error --image lee:v1
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
error 0/1 ImagePullBackOff 0 38s 10.244.2.3 k8s-node2 <none> <none>
删除 Pod:
# 删除指定 Pod
kubectl delete pods error
# 删除当前命名空间下所有 Pod(谨慎)
kubectl delete pods --all
1.3 Pod 故障排查(describe)
当 Pod 状态异常时,第一反应是查看它的详细信息,重点关注 Events 和 Conditions:
kubectl describe pods error
输出中的关键部分:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 87s default-scheduler Successfully assigned default/error to k8s-node2
Warning Failed 28s kubelet Failed to pull image "lee:v1": ... not found
Warning Failed 16s kubelet Error: ImagePullBackOff
通过 Events 可以快速定位是镜像拉取失败、调度失败还是资源不足等问题。
二、kubectl 核心命令实操
2.1 准备工作:镜像准备
在离线或私有仓库环境中,通常需要先把实验镜像加载并推送到私有仓库:
docker load -i myapp.tar.gz
docker tag timinglee/myapp:v1 reg.timinglee.org/library/myapp:v1
docker push reg.timinglee.org/library/myapp:v1
docker tag timinglee/myapp:v2 reg.timinglee.org/library/myapp:v2
docker push reg.timinglee.org/library/myapp:v2
2.2 create / edit / patch
create ------ 命令式创建 Deployment:
kubectl create deployment webcluster --replicas 2 --image myapp:v1
kubectl get deployments.apps
kubectl get pods
edit ------ 在线修改资源配置(会打开编辑器,修改后即时生效):
kubectl create deployment webcluster --image myapp:v1
kubectl edit deployments.apps webcluster
# 将 spec.replicas 改为 2,保存后 Pod 数量自动变为 2
patch ------ 以 JSON 补丁方式局部更新(非交互式,适合脚本/CICD):
kubectl patch deployments.apps webcluster -p '{"spec":{"replicas":1}}'
2.3 expose / logs
expose ------ 为 Deployment 创建 Service,使其可被集群内访问:
kubectl expose deployment webcluster --port 80 --target-port 80
kubectl get service
kubectl describe svc webcluster
# 访问 ClusterIP 验证负载均衡
curl 10.97.61.108/hostname.html
logs ------ 查看容器日志:
kubectl logs pods/webcluster-77c87d9946-gh9v7
2.4 attach / exec / cp
attach ------ 附加到正在运行的容器(类似 docker attach):
kubectl run -it testpod --image busybox:latest
# 在容器内执行 <ctrl+pq> 退出但不停止容器
kubectl attach pods/testpod -it
exec ------ 在容器内执行命令(最常用):
kubectl exec -it pods/testpod -c testpod -- /bin/bash
cp ------ 在宿主机与容器之间拷贝文件:
# 从容器拷贝到宿主机
kubectl cp testpod:/usr/share/nginx/html/index.html /mnt/test
# 从宿主机拷贝到容器
echo timinglee > /mnt/index.html
kubectl cp /mnt/index.html testpod:/usr/share/nginx/html/index.html
curl 10.244.1.12 # 返回 timinglee
2.5 rollout / scale / label
rollout ------ 管理 Deployment 的发布过程:
kubectl rollout status deployment webcluster # 查看滚动发布状态
kubectl rollout restart deployment webcluster # 重启(触发一次滚动更新)
scale ------ 调整副本数:
kubectl scale deployment webcluster --replicas 4
kubectl scale deployment webcluster --replicas 1
label ------ 管理资源标签:
kubectl get pods --show-labels
kubectl label pods webcluster-9787d97f6-zl6q2 app- # 删除标签
kubectl label pods webcluster-9787d97f6-zl6q2 app=webcluster # 添加标签
三、利用控制器实现滚动更新与回滚(版本更替)
单独一个"裸 Pod"无法自愈和滚动更新,通常需要交给 Deployment 控制器管理。
3.1 创建 Deployment 并暴露服务
kubectl create deployment webcluster --image myapp:v1 --replicas 2 --dry-run=client -o yaml > webcluster.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: webcluster
name: webcluster
spec:
replicas: 2
selector:
matchLabels:
app: webcluster
template:
metadata:
labels:
app: webcluster
spec:
containers:
- image: myapp:v1
name: myapp
kubectl apply -f webcluster.yml
kubectl expose deployment webcluster --port 80 --target-port 80 --type NodePort
kubectl get svc
# 通过节点 IP:NodePort 访问
curl http://172.25.254.100:30713/hostname.html
3.2 更新业务版本
kubectl set image deployments webcluster myapp=myapp:v2
# 建议为本次更新添加变更说明
kubectl annotate deployment webcluster kubernetes.io/change-cause="myappv2" --overwrite
curl http://172.25.254.100:30713
# 返回 Hello MyApp | Version: v2 ...
3.3 版本回退
kubectl rollout history deployment webcluster
kubectl rollout undo deployment webcluster --to-revision 3
curl http://172.25.254.100:30713
# 返回 Hello MyApp | Version: v1 ...
💡 提示:想让
rollout history显示有意义的 change-cause,除了annotate,在kubectl apply时加上--record也能自动记录命令。
四、用 YAML 声明 Pod 资源
4.1 多容器 Pod
一个 Pod 内可以运行多个容器,它们共享网络命名空间和存储卷(同一 Pod 内容器通过 localhost 互通):

图示:一个 Pod 由 Pause 容器提供共享网络栈,多个应用容器与 sidecar 共享同一网络命名空间与 Volume。
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
containers:
- image: myapp:v1
name: myapp1
- image: busyboxplus:latest
name: busybox
command:
- /bin/sh
- -c
- sleep 10000
kubectl apply -f testpod.yaml
kubectl exec -it pods/testpod -c busybox -- /bin/sh
# 在 busybox 容器内访问本地 127.0.0.1 即可访问到 myapp1 容器
4.2 将容器端口暴露到节点(hostPort)
spec:
containers:
- image: myapp:v1
name: myapp1
ports:
- name: http
containerPort: 80 # Pod 内部容器端口
hostPort: 80 # Pod 所在节点的端口
protocol: TCP
kubectl apply -f testpod.yaml
curl k8s-node2 # 直接通过节点主机名/IP 访问,无需经过 Service
4.3 在 Pod 中设置环境变量
常用于传递配置,例如 MySQL 密码:
spec:
containers:
- image: mysql:8.0
name: mysql8
env:
- name: MYSQL_ROOT_PASSWORD
value: lee
- image: phpmyadmin:latest
name: mysqladmin
env:
- name: PMA_ARBITRARY
value: "1"
4.4 选择指定节点运行(nodeSelector)
根据节点标签把 Pod 调度到特定节点:
kubectl get nodes --show-labels
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node2
containers:
- image: mysql:8.0
name: mysql8
env:
- name: MYSQL_ROOT_PASSWORD
value: lee
💡 更灵活的节点调度可以用
nodeName(强制指定)、affinity(亲和性)或tolerations(污点容忍)。
4.5 共享宿主机网络(hostNetwork)
开启后,Pod 直接使用宿主机的网络命名空间(不再有独立的 Pod IP):
spec:
hostNetwork: true
containers:
- image: busybox:latest
name: busybox
command:
- /bin/sh
- -c
- sleep 10000
进入容器后执行 ifconfig,能看到宿主机的 eth0 等网卡,说明网络已共享。
4.6 资源优先级(QoS Class)
Kubernetes 根据容器的资源请求(requests)和限制(limits)自动划分服务质量等级,节点资源紧张时按优先级驱逐(OOM 或 Eviction):
| QoS 等级 | 条件 | 优先级 |
|---|---|---|
| BestEffort | 完全不设置 requests/limits | 最低(最先被驱逐) |
| Burstable | 设置了 requests/limits,但不相等 | 居中 |
| Guaranteed | 每个容器的 requests == limits(且都设置) | 最高(最后被驱逐) |

图示为Qos三档质量对比
# Guaranteed 示例:requests 与 limits 相等
spec:
containers:
- image: busybox:latest
name: busybox
command: ["/bin/sh","-c","sleep 10000"]
resources:
limits:
cpu: 500m
memory: 100M
requests:
cpu: 500m
memory: 100M
kubectl describe pods testpod | grep "QoS Class:"
# QoS Class: Guaranteed
4.7 容器重启策略(restartPolicy)
Pod 级别的 restartPolicy 决定容器退出后是否重启,可选值:
-
Always:无论以何种原因退出都重启(默认,适合长驻服务)
-
OnFailure:只有非正常退出(非 0 状态码)才重启(适合批处理)
-
Never:无论退出状态都不重启
spec:
restartPolicy: Always
containers:
- image: busybox:latest
name: busybox
command: ["/bin/sh","-c","sleep 60"]
注意:
restartPolicy仅针对 Pod 内容器;Job/CronJob 通常配合OnFailure/Never使用,避免任务被无限重启。
五、Pod 生命周期与探针
Pod 在其生命周期内会经历不同阶段(Phase) :Pending(调度中/镜像拉取中)、Running(至少一个容器运行中)、Succeeded(所有容器正常退出)、Failed(至少一个容器异常退出)、Unknown(状态无法获取)。
5.1 Init 容器(Init Containers)
Init 容器在主容器启动前按顺序运行,必须全部成功才会启动主容器,常用于等待依赖就绪、初始化配置等。
apiVersion: v1
kind: Pod
metadata:
labels:
run: webserver
name: webserver
spec:
initContainers:
- name: busybox
image: busybox:latest
command:
- /bin/sh
- -c
- "until test -e /testfile; do echo waiting for myservice; sleep 2; done"
containers:
- image: myapp:v1
name: webserver
restartPolicy: Always
进入 init 容器创建 /testfile,等待条件满足后主容器才启动:
kubectl exec -it pods/webserver -c busybox -- /bin/sh
/ # touch /testfile
5.2 存活探针(Liveness Probe)
存活探针用于检测容器是否"活着",检测失败时 kubelet 会杀死并重启容器。没有存活探针时,即使 Nginx 进程挂了,Pod 仍显示 Running,但访问会失败。
spec:
containers:
- image: myapp:v1
name: testpod
command: ["/bin/sh","-c"]
args:
- |
nginx -g "daemon off;"
sleep 10000
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 3 # 容器启动后等待 3 秒再开始探测
periodSeconds: 1 # 每 1 秒探测一次
timeoutSeconds: 1 # 探测超时时间
在容器内执行 nginx -s stop 后,探针探测失败,kubelet 会重启容器从而恢复服务。
Kubernetes 支持三种探针类型:
exec(执行命令)、httpGet(HTTP 请求)、tcpSocket(TCP 端口探测),上面用的是 tcpSocket。
5.3 就绪探针(Readiness Probe)
就绪探针用于判断容器是否"准备好接收流量"。探测失败时,Pod 会被从 Service 的 Endpoints 中摘除,不再接收请求,但容器不会被重启。
spec:
containers:
- image: myapp:v1
name: webserver
readinessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 3
periodSeconds: 2
timeoutSeconds: 1
kubectl describe svc webserver
# Endpoints 中会显示当前就绪的 Pod IP
# 删除容器内的 /usr/share/nginx/html/index.html 后,该 Pod 会被自动从 Endpoints 摘除
💡 关键区别:Liveness 决定"要不要重启容器",Readiness 决定"要不要把流量打给它"。生产环境建议两者都配置,以保障服务健壮性。

图示为两者对比