Kubernetes Pod 管理
一、引言
在 Kubernetes 的生态体系中,Pod 是最核心、最基础的概念。它是 Kubernetes 调度和运行的最小部署单元,承载着一个或多个容器,共享网络和存储资源。无论你是刚接触 K8s 的新手,还是正在准备 CKA 认证的考生,亦或是需要在生产环境中维护集群的运维工程师,系统掌握 Pod 管理的各项技能都是必不可少的。
本文将从实际操作出发,完全基于真实的实验记录,带你一步一步掌握以下内容:
- 命令式对象管理(命名空间、Pod 的增删改查)
- kubectl 核心命令实战(create、edit、patch、expose、logs、exec、cp、rollout、scale、label)
- 利用 Deployment 控制器实现版本更新与回滚
- YAML 声明式管理(多容器 Pod、端口暴露、环境变量、节点选择、hostNetwork)
- 资源优先级(QoS Class)与重启策略
- Pod 生命周期管理(Init 容器、Liveness 探针、Readiness 探针)
环境说明:本文所有实验基于 Kubernetes v1.35.7 集群,包含 1 个 Master 节点(k8s-master)和 2 个 Worker 节点(k8s-node1、k8s-node2),使用 Flannel 作为网络插件,Harbor 作为私有镜像仓库。
二、基础篇:命令式对象管理
命令式管理是学习 Kubernetes 的起点。通过直接输入命令来操作资源,虽然不适合生产环境的大规模管理,但对于理解 K8s 的工作原理和快速验证非常有帮助。
2.1 命名空间管理
命名空间(Namespace)是 Kubernetes 中实现资源隔离的重要手段。不同的命名空间中的资源名称可以相同,互不干扰。
查看所有命名空间:
bash
[root@master ~]# kubectl get namespace
NAME STATUS AGE
default Active 9d
ingress-nginx Active 3d4h
kube-flannel Active 5d5h
kube-node-lease Active 9d
kube-public Active 9d
kube-system Active 9d
metallb-system Active 3d
nfs-storage Active 41m
系统默认创建了四个命名空间:
default:用户资源的默认位置kube-system:Kubernetes 系统组件所在kube-public:公共可访问的资源kube-node-lease:节点租约,用于节点心跳检测
创建命名空间:
bash
[root@master ~]# kubectl create namespace haha
namespace/haha created
[root@master ~]# kubectl get namespace
NAME STATUS AGE
default Active 9d
haha Active 9s
ingress-nginx Active 3d5h
kube-flannel Active 5d6h
kube-node-lease Active 9d
kube-public Active 9d
kube-system Active 9d
metallb-system Active 3d1h
nfs-storage Active 103m
删除命名空间:
bash
[root@master ~]# kubectl delete namespace haha
namespace "haha" deleted
⚠️ 注意:删除命名空间会一并删除该空间下的所有资源,请谨慎操作。
2.2 Pod 的基本操作
查看 Pod 运行情况:
bash
[root@master ~]# kubectl get pods -o wide
No resources found in default namespace.
-o wide 参数会显示更多信息,包括 Pod 的 IP 地址和运行节点。
创建 Pod:
bash
[root@master ~]# kubectl run lee --image nginx:1.23
pod/lee created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
lee 1/1 Running 0 6s 10.244.2.21 node2 <none> <none>
kubectl run 是最常用的快速创建 Pod 的方式。这里我们创建了一个名为 lee 的 Pod,使用 nginx:latest 镜像。
当 Pod 创建失败时的排查:
如果镜像不存在或镜像名称错误,Pod 会进入 ImagePullBackOff 或 ErrImagePull 状态。
bash
[root@master ~]# kubectl run error --image haha
pod/error created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
error 0/1 ContainerCreating 0 6s <none> node1 <none> <none>
lee 1/1 Running 0 69s 10.244.2.21 node2 <none> <none>
使用 describe 查看详细错误信息:
bash
[root@master ~]# kubectl describe pod error
Name: error
Namespace: default
Priority: 0
Service Account: default
Node: node1/172.25.254.10
Start Time: Sat, 29 Aug 2026 17:44:23 +0800
Labels: run=error
Annotations: <none>
Status: Pending
IP: 10.244.1.14
IPs:
IP: 10.244.1.14
Containers:
error:
Container ID:
Image: haha
Image ID:
Port: <none>
Host Port: <none>
State: Waiting
Reason: ImagePullBackOff
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-59jlm (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
kube-api-access-59jlm:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
Optional: false
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 47s default-scheduler Successfully assigned default/error to node1
Warning Failed 20s kubelet spec.containers{error}: Failed to pull image "haha": Error response from daemon: failed to resolve reference "docker.io/library/haha:latest": docker.io/library/haha:latest: not found
Warning Failed 20s kubelet spec.containers{error}: Error: ErrImagePull
Normal BackOff 19s kubelet spec.containers{error}: Back-off pulling image "haha"
Warning Failed 19s kubelet spec.containers{error}: Error: ImagePullBackOff
Normal Pulling 6s (x2 over 46s) kubelet spec.containers{error}: Pulling image "haha"
从 Events 可以看出,kubelet 尝试从 Docker Hub 拉取 haha 镜像但未找到,导致 ImagePullBackOff。
删除 Pod:
bash
# 删除单个 Pod
[root@master ~]# kubectl delete pod error
pod "error" deleted from default namespace
# 删除当前命名空间下所有 Pod
[root@master ~]# kubectl delete pods --all
pod "lee" deleted from default namespace
三、实操篇:kubectl 命令全览
本节将逐一演示 kubectl 的常用命令,每个命令都配有完整的实验输出。
3.1 准备实验镜像
为了后续的实验,我们需要先将实验镜像上传到私有仓库。
bash
# 加载镜像
[root@master ~]# docker load -i myapp.tar.gz
# 打标签并推送到 Harbor 仓库
[root@master ~]# docker tag timinglee/myapp:v1 reg.timinglee.org/library/myapp:v1
[root@master ~]# docker push reg.timinglee.org/library/myapp:v1
[root@master ~]# docker tag timinglee/myapp:v2 reg.timinglee.org/library/myapp:v2
[root@master ~]# docker push reg.timinglee.org/library/myapp:v2
3.2 生成 ReplicaSet YAML 示例
bash
[root@master ~]# vim replica.yml
yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
labels:
app: replica
name: replica
spec:
replicas: 2
selector:
matchLabels:
app: replica
template:
metadata:
labels:
app: replica
spec:
containers:
- image: myapp:v1
name: myapp
3.3 create --- 创建资源
bash
[root@master ~]# kubectl create deployment webcluster --replicas 2 --image myapp:v1
deployment.apps/webcluster created
[root@master ~]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
webcluster 2/2 2 2 32s
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
webcluster-77c87d9946-bx5jn 1/1 Running 0 48s
webcluster-77c87d9946-vkk9w 1/1 Running 0 48s
# 删除刚才创建的 Deployment
[root@master ~]# kubectl delete deployments.apps webcluster
deployment.apps "webcluster" deleted from default namespace
3.4 edit --- 编辑在线资源
bash
# 创建一个单副本的 Deployment
[root@master ~]# kubectl create deployment webcluster --image myapp:v1 deployment.apps/webcluster created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
webcluster-77c87d9946-lw8h2 1/1 Running 0 10s
# 使用 edit 修改副本数为 2
[root@master ~]# kubectl edit deployments.apps webcluster
deployment.apps/webcluster edited
# 在编辑器中修改 replicas: 2 并保存
spec:
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
webcluster-77c87d9946-lw8h2 1/1 Running 0 2m34s
webcluster-77c87d9946-rnc5r 1/1 Running 0 60s
edit 命令会打开系统默认编辑器(如 vim),保存后立即生效。适合进行少量的参数调整。
3.5 patch --- 局部更新
bash
[root@master ~]# kubectl patch deployments.apps webcluster -p '{"spec":{"replicas":1}}'
deployment.apps/webcluster patched
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
webcluster-77c87d9946-lw8h2 1/1 Running 0 5m20s
与 edit 不同,patch 使用 JSON Patch 或 JSON Merge Patch 语法进行精确的局部更新,适合在脚本中自动化操作。
3.6 expose --- 创建 Service 暴露服务
bash
[root@master ~]# kubectl expose deployments.apps webcluster --port 80 --target-port 80
service/webcluster exposed
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d
webcluster ClusterIP 10.106.107.32 <none> 80/TCP 3s
# 查看 Service 的详细信息,包括 Endpoints
[root@master ~]# kubectl describe svc webcluster
Name: webcluster
Namespace: default
Labels: app=webcluster
Annotations: <none>
Selector: app=webcluster
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.106.107.32
IPs: 10.106.107.32
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.2.24:80
Session Affinity: None
Internal Traffic Policy: Cluster
Events: <none>
验证负载均衡效果:
多次访问 Service IP,可以看到请求被轮询分发到不同的 Pod。
bash
[root@master ~]# kubectl edit deployments.apps webcluster
deployment.apps/webcluster edited
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
webcluster-77c87d9946-59hhx 1/1 Running 0 10s
webcluster-77c87d9946-lw8h2 1/1 Running 0 20m
[root@master ~]# curl 10.106.107.32/hostname.html
webcluster-77c87d9946-lw8h2
[root@master ~]# curl 10.106.107.32/hostname.html
webcluster-77c87d9946-59hhx
[root@master ~]# curl 10.106.107.32/hostname.html
webcluster-77c87d9946-lw8h2
[root@master ~]# curl 10.106.107.32/hostname.html
webcluster-77c87d9946-59hhx
3.7 logs --- 查看容器日志
bash
[root@master ~]# kubectl logs pod/webcluster-77c87d9946-59hhx
10.244.0.0 - - [29/Aug/2026:10:31:32 +0000] "GET / HTTP/1.1" 200 65 "-" "curl/7.76.1" "-"
10.244.0.0 - - [29/Aug/2026:10:31:56 +0000] "GET /hostname.html HTTP/1.1" 200 28 "-" "curl/7.76.1" "-"
10.244.0.0 - - [29/Aug/2026:10:31:58 +0000] "GET /hostname.html HTTP/1.1" 200 28 "-" "curl/7.76.1" "-"
3.8 attach --- 附加到运行中的容器
bash
# 准备 busybox 镜像
[root@master ~]# docker load -i busybox-latest.tar.gz
[root@master ~]# docker tag busybox:latest reg.timinglee.org/library/busybox:latest
# 创建交互式 Pod
[root@master ~]# kubectl run -it testpod --image busybox
All commands and output from this session will be recorded in container logs, including credentials and sensitive information passed through the command prompt.
If you don't see a command prompt, try pressing enter.
/ #
/ #
/ # # 按 Ctrl+P+Q 退出但保持容器运行
# 重新 attach 到容器
[root@master ~]# kubectl attach pods/testpod -it
All commands and output from this session will be recorded in container logs, including credentials and sensitive information passed through the command prompt.
If you don't see a command prompt, try pressing enter.
/ #
3.9 exec --- 在容器内执行命令
bash
[root@master ~]# kubectl exec -it pods/testpod -c testpod -- /bin/sh
/ #
/ # ls
bin etc lib proc sys usr
dev home lib64 root tmp var
exec 比 attach 更灵活,它可以在容器中执行任意命令,而不只是进入交互式 Shell。
3.10 cp --- 文件复制
从 Pod 复制文件到宿主机:
bash
[root@master ~]# kubectl exec -it pods/testpod -c testpod -- /bin/sh
/ #
/ # echo haha > index.html
/ # exit
[root@master ~]# kubectl cp testpod:/index.html /mnt/haha
tar: removing leading '/' from member names
[root@master ~]# cat /mnt/haha
haha
从宿主机复制文件到 Pod:
bash
[root@master ~]# cat /mnt/index.html
timinglee
[root@master ~]# kubectl cp /mnt/index.html testpod:/index.html
[root@master ~]# kubectl exec -it pods/testpod -c testpod -- /bin/sh
/ #
/ # ls
bin home lib64 sys var
dev index.html proc tmp
etc lib root usr
/ # cat index.html
timinglee
3.11 rollout --- 部署管理
使用 YAML 创建 Deployment:
bash
[root@master ~]# kubectl create deployment webcluster --image myapp:v1 --replicas 2 --dry-run=client -o yaml > webcluster.yml
[root@master ~]# vim 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
[root@master ~]# kubectl apply -f webcluster.yml
deployment.apps/webcluster created
查看部署状态:
bash
[root@master ~]# kubectl rollout status deployment webcluster
deployment "webcluster" successfully rolled out
重启 Deployment:
bash
开启监控
[root@master ~]# watch -n 1 'kubectl get pods -o wide'
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 19:32:47 2026
NAME READY STATUS RESTARTS AGE IP N
ODE NOMINATED NODE READINESS GATES
webcluster-d45676cd4-8pswz 1/1 Running 0 3m58s 10.244.1.21 n
ode1 <none> <none>
webcluster-d45676cd4-db5s8 1/1 Running 0 4m 10.244.2.28 n
ode2 <none> <none>
[root@master ~]# kubectl rollout restart deployment webcluster
deployment.apps/webcluster restarted
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
webcluster-7bfd865747-jmhwl 1/1 Running 0 6s
webcluster-7bfd865747-qv2xt 1/1 Running 0 8s
# 再次重启,观察滚动更新过程
[root@master ~]# kubectl rollout restart deployment webcluster
deployment.apps/webcluster restarted
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 19:35:51 2026
NAME READY STATUS RESTARTS AGE IP
NODE NOMINATED NODE READINESS GATES
webcluster-7dbf85554d-hvf9d 1/1 Running 0 2s 10.244
.2.30 node2 <none> <none>
webcluster-7dbf85554d-rddpd 0/1 ContainerCreating 0 1s <none>
node1 <none> <none>
webcluster-d64964bcf-6zm9s 0/1 Completed 0 11s 10.244
.2.29 node2 <none> <none>
webcluster-d64964bcf-fv6sw 1/1 Running 0 10s 10.244
.1.22 node1 <none> <none>
可以看到,重启过程中新旧 Pod 交替出现,实现了零宕机更新。
3.12 scale --- 手动扩缩容
bash
# 扩容到 4 个副本
[root@master ~]# kubectl scale deployment webcluster --replicas 4
deployment.apps/webcluster scaled
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 19:38:20 2026
NAME READY STATUS RESTARTS AGE IP
NODE NOMINATED NODE READINESS GATES
webcluster-7dbf85554d-hvf9d 1/1 Running 0 2m31s 10.244.2.30
node2 <none> <none>
webcluster-7dbf85554d-hw5mv 1/1 Running 0 22s 10.244.1.24
node1 <none> <none>
webcluster-7dbf85554d-lmkrv 1/1 Running 0 22s 10.244.2.31
node2 <none> <none>
webcluster-7dbf85554d-rddpd 1/1 Running 0 2m30s 10.244.1.23
node1 <none> <none>
# 缩容到 1 个副本
[root@master ~]# kubectl scale deployment webcluster --replicas 1
deployment.apps/webcluster scaled
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 19:39:17 2026
NAME READY STATUS RESTARTS AGE IP
NODE NOMINATED NODE READINESS GATES
webcluster-7dbf85554d-rddpd 1/1 Running 0 3m27s 10.244.1.23
node1 <none> <none>
3.13 label --- 标签管理
bash
# 查看 Pod 的标签
[root@master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
webcluster-7dbf85554d-rddpd 1/1 Running 0 4m35s app=webcluster,pod-template-hash=7dbf85554d
# 查看 Deployment 的标签
[root@master ~]# kubectl get deployments.apps webcluster --show-labels
NAME READY UP-TO-DATE AVAILABLE AGE LABELS
webcluster 1/1 1 1 14m app=webcluster
# 删除标签(在标签名后加 -)
[root@master ~]# kubectl label pods webcluster-7dbf85554d-rddpd app-
pod/webcluster-7dbf85554d-rddpd unlabeled
# 添加标签
[root@master ~]# kubectl label pods webcluster-7dbf85554d-rddpd app=webcluster
pod/webcluster-7dbf85554d-rddpd labeled
[root@master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
webcluster-7dbf85554d-rddpd 1/1 Running 0 10m app=webcluster,pod-template-hash=7dbf85554d
四、进阶篇:利用控制器实现版本更替
在生产环境中,我们很少直接管理 Pod,而是通过 Deployment 等控制器来实现声明式的应用管理。本节演示如何利用 Deployment 实现应用的版本更新和回滚。
4.1 建立初始环境
⚠️ 前置条件:Harbor 仓库的 library 项目中必须有 myapp:v1 和 myapp:v2 两个镜像。
创建 Deployment:
bash
[root@master ~]# kubectl create deployment webcluster --image myapp:v1 --replicas 2 --dry-run=client -o yaml > webcluster.yml
[root@master ~]# vim 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
[root@master ~]# kubectl apply -f webcluster.yml
deployment.apps/webcluster created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
webcluster-77c87d9946-2fxzz 1/1 Running 0 18s
webcluster-77c87d9946-nj65d 1/1 Running 0 18s
查看部署历史:
bash
[root@master ~]# kubectl rollout history deployment webcluster
deployment.apps/webcluster
REVISION CHANGE-CAUSE
1 <none>
暴露服务(NodePort 类型):
bash
[root@master ~]# kubectl expose deployment webcluster --port 80 --target-port 80 --type NodePort
service/webcluster exposed
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d
webcluster NodePort 10.98.64.91 <none> 80:39685/TCP 26s
访问验证:
bash
# 从外部节点访问
29/08/2026 19:59.24 /home/mobaxterm curl http://172.25.254.100:39685/hostname.html
webcluster-77c87d9946-2fxzz
4.2 更新业务版本(v1 → v2)
bash
# 更新镜像版本
[root@master ~]# kubectl set image deployments webcluster myapp=myapp:v2
deployment.apps/webcluster image updated
# 为此次更新添加变更说明(便于后续追溯)
[root@master ~]# kubectl annotate deployment webcluster kubernetes.io/change-cause="myappv2" --overwrite
deployment.apps/webcluster annotated
# 观察新 Pod 的创建
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
webcluster-6c8b4bb9d7-9wqqr 1/1 Running 0 3m10s
webcluster-6c8b4bb9d7-mzrkv 1/1 Running 0 3m12s
# 查看部署历史(现在有 2 个版本了)
[root@master ~]# kubectl rollout history deployment webcluster
deployment.apps/webcluster
REVISION CHANGE-CAUSE
1 <none>
2 myappv2
验证更新结果:
bash
29/08/2026 20:06.04 /home/mobaxterm curl http://172.25.254.100:39685
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
4.3 版本回退
bash
# 再次更新到 v3,产生新的 Revision
[root@master ~]# kubectl set image deployments webcluster myapp=myapp:v1
deployment.apps/webcluster image updated
[root@master ~]# kubectl annotate deployment webcluster kubernetes.io/change-cause="myappv1" --overwrite
deployment.apps/webcluster annotated
[root@master ~]# kubectl rollout history deployment webcluster
deployment.apps/webcluster
REVISION CHANGE-CAUSE
2 myappv2
3 myappv1
# 回退到 Revision 3(即 v2 版本)
[root@master ~]# kubectl rollout undo deployment webcluster --to-revision 3
deployment.apps/webcluster skipped rollback (current template already matches revision 3)
验证回退结果:
bash
29/08/2026 20:06.11 /home/mobaxterm curl http://172.25.254.100:39685
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
通过 rollout undo,我们可以在几秒内完成版本回退,这是 Kubernetes 在生产环境中保障业务连续性的重要能力。
五、声明式篇:YAML 文件管理资源
YAML 声明式管理是生产环境的标准做法。通过版本化的 YAML 文件,我们可以实现 Infrastructure as Code(IaC),便于团队协作和审计追踪。
5.1 Pod 中运行多容器
一个 Pod 中可以包含多个容器,它们共享网络命名空间和存储卷。这种模式常用于 Sidecar 场景(如日志收集、代理等)。
bash
[root@master ~]# kubectl run testpod --image myapp:v1 --dry-run=client -o yaml > testpod.yaml
[root@master ~]# vim testpod.yaml
yaml
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
应用并验证:
bash
[root@master ~]# kubectl apply -f testpod.yaml
pod/testpod created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
testpod 2/2 Running 0 3s
# 进入 busybox 容器,访问 myapp1 容器(共享 localhost)
[root@master ~]# kubectl exec -it pods/testpod -c busybox -- /bin/sh
/bin/sh: shopt: not found
[ root@node2:/ ]$ curl 127.0.0.1
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
两个容器通过 localhost 相互通信,证明了 Pod 内网络命名空间的共享。
5.2 在 Pod 所在节点暴露端口
bash
[root@master ~]# vim testpod.yaml
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
containers:
- image: myapp:v1
name: myapp1
ports:
- name: http
containerPort: 80
hostPort: 80
protocol: TCP
bash
[root@master ~]# kubectl apply -f testpod.yaml
pod/testpod created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
testpod 1/1 Running 0 36s 172.25.254.20 node2 <none> <none>
# 直接通过节点 IP 访问
[root@master ~]# curl 172.25.254.20
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
⚠️ 注意 :使用
hostPort会导致该端口只能被一个 Pod 占用,且调度时需要避开端口冲突,一般不建议在生产环境使用。
5.3 在 Pod 中注入环境变量
环境变量是配置 Pod 容器的常用方式,尤其适合数据库密码、连接地址等配置。
bash
[root@master ~]# vim mysql.yml
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: mysql
name: 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"
ports:
- name: phpadminport
containerPort: 80
hostPort: 80
protocol: TCP
bash
[root@master ~]# kubectl apply -f mysql.yml
pod/mysql created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql 2/2 Running 0 26s 10.244.1.29 node1 <none> <none>
MYSQL_ROOT_PASSWORD=lee 为 MySQL 容器设置了 root 密码,PMA_ARBITRARY=1 允许 phpMyAdmin 连接任意 MySQL 服务器。
5.4 选择运行节点(nodeSelector)
bash
# 查看节点标签
[root@master ~]# kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
master Ready control-plane 9d v1.35.7 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
node1 Ready <none> 9d v1.35.7 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1,kubernetes.io/os=linux
node2 Ready <none> 9d v1.35.7 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node2,kubernetes.io/os=linux
修改 YAML,指定调度到 k8s-node2:
bash
[root@master ~]# vim mysql.yml
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: mysql
name: mysql
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node2
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"
ports:
- name: phpadminport
containerPort: 80
hostPort: 80
protocol: TCP
bash
[root@master ~]# kubectl apply -f mysql.yml
pod/mysql created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql 2/2 Running 0 57s 10.244.2.37 node2 <none> <none>
5.5 共享宿主机网络(hostNetwork)
hostNetwork: true 使得 Pod 直接使用宿主机的网络命名空间,适合需要监听宿主机端口或获取真实客户端 IP 的场景。
bash
[root@master ~]# vim testpod.yaml
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
hostNetwork: true
containers:
- image: busybox:latest
name: busybox
command:
- /bin/sh
- -c
- sleep 10000
bash
[root@master ~]# kubectl apply -f testpod.yml
pod/testpod created
# 进入容器查看网络接口
[root@master ~]# kubectl exec -it pods/testpod -c busybox -- /bin/sh
/ #
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:9D:4D:86
inet addr:172.25.254.20 Bcast:172.25.254.255 Mask:255.255.255.0
...
flannel.1 Link encap:Ethernet HWaddr 9E:14:23:75:FE:0E
inet addr:10.244.2.0 Bcast:0.0.0.0 Mask:255.255.255.255
...
可以看到容器内的网络接口与宿主机完全一致(包括 eth0、flannel.1 等)。
5.6 资源优先级(QoS Class)
Kubernetes 根据 Pod 的资源请求(requests)和限制(limits)将 Pod 分为三个 QoS(Quality of Service)等级,决定了在资源紧张时 Pod 的驱逐优先级。
BestEffort --- 最低优先级
没有设置任何 requests 和 limits,资源使用优先级最低,在资源紧张时会被优先驱逐。
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
hostNetwork: true
containers:
- image: busybox:latest
name: busybox
command:
- /bin/sh
- -c
- sleep 10000
bash
[root@master ~]# kubectl describe pods testpod | grep "QoS Class"
QoS Class: BestEffort
Burstable --- 中等优先级
设置了 requests 和 limits,但两者不相等,优先级次之。
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
hostNetwork: true
containers:
- image: busybox:latest
name: busybox
command:
- /bin/sh
- -c
- sleep 10000
resources:
limits:
cpu: 700m
memory: 200M
requests:
cpu: 500m
memory: 100M
bash
[root@master ~]# kubectl describe pods testpod | grep "QoS Class"
QoS Class: Burstable
Guaranteed --- 最高优先级
requests 和 limits 完全相等,优先级最高,只有在系统资源严重不足时才会被驱逐。
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
hostNetwork: true
containers:
- image: busybox:latest
name: busybox
command:
- /bin/sh
- -c
- sleep 10000
resources:
limits:
cpu: 500m
memory: 100M
requests:
cpu: 500m
memory: 100M
bash
[root@master ~]# kubectl describe pods testpod | grep "QoS Class"
QoS Class: Guaranteed
💡 生产建议:关键业务 Pod 应设置为 Guaranteed 等级,确保资源稳定性。
5.7 容器重启策略
Kubernetes 支持三种重启策略(restartPolicy):
Always --- 总是重启
无论容器以何种方式退出,都会自动重启。
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
hostNetwork: true
restartPolicy: Always
containers:
- image: busybox:latest
name: busybox
command:
- /bin/sh
- -c
- sleep 60
bash
# 在另一个终端监控 Pod 状态
[root@master ~]# kubectl get pods -o wide -w
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 21:54:16 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NO
DE READINESS GATES
testpod 1/1 Running 0 29s 172.25.254.20 node2 <none>
<none>
# 在 Node 上强制删除容器,模拟故障
[root@node2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d382b12acb86 40680ace50cf "/bin/sh -c 'sleep 1..." About a minute ago Up About a minute k8s_busybox_testpod_default_19290be1-3515-4194-b6ec-480492fd01e7_0
[root@node2 ~]# docker rm -f d382b12acb86
d382b12acb86
#监控
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 21:57:22 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED
NODE READINESS GATES
testpod 1/1 Running 1 3m35s 172.25.254.20 node2 <none>
<none>
可以看到 Pod 会被 kubelet 自动重建。
OnFailure --- 仅异常退出时重启
只有当容器以非零状态码退出时才会重启,正常退出不重启。
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
hostNetwork: true
restartPolicy: OnFailure
containers:
- image: busybox:latest
name: busybox
command:
- /bin/sh
- -c
- sleep 30
bash
[root@master ~]# kubectl apply -f testpod.yml
pod/testpod created
[root@k8s-master ~]# kubectl get pods -o wide -w
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 22:00:05 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED
NODE READINESS GATES
testpod 0/1 Completed 0 33s 172.25.254.20 node2 <none>
<none>
30 秒后容器正常退出,Pod 状态变为 Completed,不会重启。
Never --- 永不重启
容器退出后 Pod 状态变为 Completed 或 Failed,不会自动重启。
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
hostNetwork: true
restartPolicy: Never
containers:
- image: busybox:latest
name: busybox
command:
- /bin/sh
- -c
- sleep 30
bash
[root@master ~]# kubectl apply -f testpod.yml
pod/testpod created
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 22:01:40 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED
NODE READINESS GATES
testpod 0/1 Completed 0 44s 172.25.254.20 node2 <none>
<none>
六、核心篇:Pod 生命周期管理
Kubernetes 提供了多种机制来管理 Pod 的生命周期,确保应用的高可用性。
6.1 Init 容器
Init 容器在 Pod 的业务容器启动之前运行,用于执行初始化任务(如等待依赖服务就绪、下载配置等)。
bash
[root@master ~]# kubectl run webserver --image myapp:v1 --dry-run=client -o yaml > init-example.yml
[root@master ~]# vim init-example.yml
yaml
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
bash
[root@master ~]# kubectl apply -f init-example.yml
pod/webserver created
# 在另一个终端监控
[root@master ~]# watch -n 1 kubectl get pods -o wide
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 22:09:25 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED N
ODE READINESS GATES
webserver 0/1 Init:0/1 0 76s 10.244.2.38 node2 <none>
<none>
此时 Init 容器会一直等待 /testfile 文件出现。我们手动创建这个文件:
bash
[root@master ~]# kubectl exec -it pods/webserver -c busybox -- /bin/sh
/ #
/ # touch /testfile
/ # command terminated with exit code 137
[root@master ~]# watch -n 1 'kubectl get pods -o wide'
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 22:11:01 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED
NODE READINESS GATES
webserver 1/1 Running 0 2m52s 10.244.2.38 node2 <none>
<none>
Init 容器完成任务后退出,业务容器随即启动,Pod 变为 Running 状态。
6.2 存活探针(Liveness Probe)
存活探针用于检测容器是否仍在正常运行。如果探针检测失败,kubelet 会重启容器。
没有存活探针时的问题:
bash
[root@master ~]# kubectl run testpod --image myapp:v1 --dry-run=client -o yaml > livness-example.yml
[root@master ~]# vim livness-example.yml
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
containers:
- image: myapp:v1
name: testpod
command: ["/bin/sh", "-c"]
args:
- |
nginx -g "daemon off;"
sleep 10000
restartPolicy: Always
bash
[root@master ~]# kubectl apply -f livness-example.yml
pod/testpod created
# 监控 Pod 状态
[root@k8s-master ~]# watch -n 1 kubectl get pods -o wide
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 22:17:16 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
READINESS GATES
testpod 1/1 Running 0 22s 10.244.2.39 node2 <none>
<none>
# 进入容器手动停止 nginx
[root@master ~]# kubectl exec -it pods/testpod -c testpod -- /bin/sh
/ # nginx -s stop
2026/08/29 14:19:50 [notice] 15#15: signal process started
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 22:20:59 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NOD
E READINESS GATES
testpod 1/1 Running 0 4m5s 10.244.2.39 node2 <none>
<none>
此时虽然 nginx 已停止,但 Pod 状态仍然是 Running,实际服务已不可用:
bash
[root@node2 ~]# curl 10.244.2.39
curl: (7) Failed to connect to 10.244.2.39 port 80: 拒绝连接
配置存活探针后:
bash
[root@master ~]# kubectl delete -f livness-example.yml --force
Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "testpod" force deleted from default namespace
[root@k8s-master ~]# vim livness-example.yaml
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
containers:
- image: myapp:v1
name: testpod
command: ["/bin/sh", "-c"]
args:
- |
nginx -g "daemon off;"
sleep 10000
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 3
periodSeconds: 1
timeoutSeconds: 1
restartPolicy: Always
bash
[root@master ~]# kubectl apply -f livness-example.yml
pod/testpod created
[root@master ~]# kubectl get pods -o wide -w
当再次执行 nginx -s stop 停止服务后,探针检测到 TCP 连接失败,自动触发容器重启,服务恢复:
bash
[root@master ~]# curl 10.244.2.41
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 22:36:24 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED
NODE READINESS GATES
testpod 1/1 Running 1 (30s ago) 111s 10.244.2.41 node2 <none>
<none>
6.3 就绪探针(Readiness Probe)
就绪探针用于检测容器是否已准备好接收流量。只有探针检测成功时,Pod 才会被加入 Service 的 Endpoints 中。
没有就绪探针时的问题:
bash
[root@k8s-master ~]# vim readness-example.yml
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: webserver
name: webserver
spec:
containers:
- image: myapp:v1
name: webserver
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
run: webserver
name: webserver
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: webserver
bash
[root@master ~]# kubectl apply -f readness-example.yml
pod/webserver created
service/webserver created
[root@master ~]# kubectl describe svc webserver
Name: webserver
Namespace: default
Labels: run=webserver
Annotations: <none>
Selector: run=webserver
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.97.181.69
IPs: 10.97.181.69
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.2.42:80# Pod 在 Endpoints 中
删除 index.html 文件后:
bash
[root@master ~]# kubectl exec -it pods/webserver -c webserver -- /bin/sh
/ # rm -f /usr/share/nginx/html/index.html
/ # exit
bash
[root@master ~]# curl 10.97.181.69
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.12.2</center>
</body>
</html>
此时 Service 仍然将流量转发到该 Pod,但业务实际上已不可用(403 Forbidden)。
配置就绪探针后:
bash
[root@master ~]# vim readness-example.yml
yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: webserver
name: webserver
spec:
containers:
- image: myapp:v1
name: webserver
readinessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 3
periodSeconds: 2
timeoutSeconds: 1
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
run: webserver
name: webserver
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: webserver
bash
[root@master ~]# kubectl get pods -o wide
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 22:45:27 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NO
DE READINESS GATES
webserver 1/1 Running 0 52s 10.244.2.43 node2 <none>
<none>
[root@master ~]# kubectl describe svc webserver
Name: webserver
Namespace: default
Labels: run=webserver
Annotations: <none>
Selector: run=webserver
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.98.27.211
IPs: 10.98.27.211
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.2.43:80
Session Affinity: None
Internal Traffic Policy: Cluster
Events: <none>
当再次删除 index.html 后,就绪探针检测失败,Pod 被从 Endpoints 中摘除:
bash
/ # rm -fr /usr/share/nginx/html/index.html
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 22:47:55 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED
NODE READINESS GATES
webserver 0/1 Running 0 3m20s 10.244.2.43 node2 <none>
<none>
/ # echo haha > /usr/share/nginx/html/index.html # 恢复后重新加入 Endpoints
Every 1.0s: kubectl get pods -o wide master: Sat Aug 29 22:48:42 2026
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED N
ODE READINESS GATES
webserver 1/1 Running 0 4m7s 10.244.2.43 node2 <none>
<none>
七、总结与最佳实践
7.1 核心要点回顾
| 管理方式 | 适用场景 | 优缺点 |
|---|---|---|
| 命令式(kubectl run/create) | 快速验证、临时测试 | 简单直接,但不可追溯 |
| 命令式 + 配置文件 | 日常运维操作 | 灵活,但缺乏版本控制 |
| 声明式(YAML + apply) | 生产环境标准做法 | 支持 GitOps、审计、回滚 |
7.2 生产环境最佳实践
-
始终使用 YAML 声明式管理
- 将 YAML 文件纳入版本控制
- 使用
--dry-run=client -o yaml生成模板
-
合理设置资源配额
- 为每个 Pod 设置 requests 和 limits
- 关键业务设置为 Guaranteed QoS
-
配置健康检查
- Liveness Probe:防止"僵尸"容器
- Readiness Probe:确保流量只转发到就绪的 Pod
-
使用 change-cause 记录变更
bashkubectl annotate deployment webcluster kubernetes.io/change-cause="更新到 v2,修复XX Bug" -
谨慎使用 hostNetwork 和 hostPort
- 会与宿主机端口冲突
- 降低 Pod 的可移植性
-
合理设置重启策略
- Deployment 默认为 Always,适合长期运行的服务
- Job/CronJob 使用 OnFailure 或 Never
7.3 常用命令速查
| 操作 | 命令 |
|---|---|
| 查看 Pod | kubectl get pods -o wide |
| 查看日志 | kubectl logs -f <pod-name> |
| 进入容器 | kubectl exec -it <pod-name> -- /bin/bash |
| 扩容/缩容 | kubectl scale deployment <name> --replicas=N |
| 更新镜像 | kubectl set image deployment <name> <container>=<image> |
| 回滚版本 | kubectl rollout undo deployment <name> --to-revision=N |
| 查看历史 | kubectl rollout history deployment <name> |
八、结语
本文从零开始,通过 40+ 个实际操作,完整覆盖了 Kubernetes Pod 管理的方方面面。从最基础的命名空间管理,到命令式的 Pod 操作,再到声明式的 YAML 配置,最后深入到生命周期探针、QoS 等级等高级主题,所有的实验都基于真实的生产级环境。
掌握这些技能,你将能够:
- 熟练使用 kubectl 进行日常运维
- 编写高质量的 Deployment YAML 文件
- 实现应用的版本更新和快速回滚
- 配置健康检查保障服务高可用
- 合理规划资源使用,优化集群稳定性