摘要:Pod 是 K8s 最小调度单元,
目录包括:Pod 核心概念、命令式管理、yaml 声明式编写、控制器管理 Pod、QoS、重启策略、init 容器、存活 / 就绪探针。
一、Pod 基础概念
Pod 是 Kubernetes最小可部署调度单元,一个 Pod 可以包含 1 个或多个紧密耦合的容器。
- 同一个 Pod 内所有容器共享网络命名空间、IP、主机名 ,Pod 内部容器访问直接使用
127.0.0.1 - Pod 内部容器共享存储卷,实现容器间文件共享
- 生产环境不建议直接手动创建 Pod,优先使用 Deployment 等控制器管理;直接创建的自主式 Pod 删除后不会自动重建,故障无法自愈。
补充:K8s 资源管理三种方式
- 命令式对象管理:直接 kubectl 命令操作,适合测试快速验证
- 命令式对象配置 :
kubectl create -f xxx.yaml - 声明式对象配置 :
kubectl apply -f xxx.yaml,生产主流,支持版本管理、重复执行更新资源
二、命令式 Pod 管理实操
2.1 命名空间基础
Namespace 实现资源隔离,不同命名空间资源相互隔离。
# 查看命名空间
[root@k8s-master ~]# kubectl get namespaces
NAME STATUS AGE
default Active 5d5h
kube-flannel Active 5d4h
kube-node-lease Active 5d5h
kube-public Active 5d5h
kube-system Active 5d5h
metallb-system Active 23h
# 创建命名空间
[root@k8s-master ~]# kubectl create zq
error: Unexpected args: [zq]
See 'kubectl create -h' for help and examples
[root@k8s-master ~]# kubectl create namespace zq
namespace/zq created
[root@k8s-master ~]# kubectl get namespaces
NAME STATUS AGE
default Active 5d5h
kube-flannel Active 5d4h
kube-node-lease Active 5d5h
kube-public Active 5d5h
kube-system Active 5d5h
metallb-system Active 23h
zq Active 11s
# 删除命名空间(会删除该命名空间下所有资源)
[root@k8s-master ~]# kubectl delete namespaces zq
namespace "zq" deleted
2.2 Pod 常用命令
# 创建pod
[root@k8s-master ~]# kubectl run zq --image nginx:latest
pod/zq created
# 查看pod基础信息
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
zq 1/1 Running 0 8s
# 查看pod详细信息(节点、podIP)
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
zq 1/1 Running 0 13s 10.244.2.3 k8s-node2 <none> <none>
# 排查pod异常,查看事件Events(排错最重要)
[root@k8s-master ~]# kubectl run error --image lee:v1
pod/error created
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
error 0/1 ContainerCreating 0 9s <none> k8s-node2 <none> <none>
zq 1/1 Running 0 36s 10.244.2.3 k8s-node2 <none> <none>
[root@k8s-master ~]# kubectl describe pods error
Name: error
Namespace: default
Priority: 0
Service Account: default
Node: k8s-node2/172.25.254.20
Start Time: Tue, 25 Aug 2026 16:35:35 +0800
Labels: run=error
Annotations: <none>
Status: Pending
IP:
IPs: <none>
Containers:
error:
Container ID:
Image: lee:v1
Image ID:
Port: <none>
Host Port: <none>
State: Waiting
Reason: ContainerCreating
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-w7w9l (ro)
Conditions:
Type Status
PodReadyToStartContainers False
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
kube-api-access-w7w9l:
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 17s default-scheduler Successfully assigned default/error to k8s-node2
Normal Pulling 17s kubelet spec.containers{error}: Pulling image "lee:v1"
# 删除单个pod
[root@k8s-master ~]# kubectl delete pods error
pod "error" deleted from default namespace
# 删除当前命名空间全部pod
[root@k8s-master ~]# kubectl delete pods --all
pod "zq" deleted from default namespace
常见 Pod 异常状态
ImagePullBackOff:镜像拉取失败,镜像名字错误、私有仓库没有 secret、网络无法访问仓库,使用kubectl describe pod看事件报错信息。CrashLoopBackOff:容器反复启动失败,检查镜像、启动命令、日志。
2.3 上传实验镜像到 Harbor 仓库 library 项目(实验前置)
实验环境说明:本地已经有
myapp.tar.gz镜像包,私有 Harbor 仓库地址为reg.timinglee.org,library是 Harbor 的公共项目,k8s 所有节点都默认可以拉取 library 项目镜像,不需要额外配置镜像拉取 secret。 前提:所有 k8s 节点的 docker 配置了 harbor 域名解析,docker 信任该私有仓库。
#1. 将本地tar镜像包导入docker本地镜像库 [root@k8s-master ~]# docker load -i myapp.tar.gz #2. 给本地镜像打标签,格式:仓库地址/项目名/镜像名:版本 [root@k8s-master ~]# docker tag timinglee/myapp:v1 reg.timinglee.org/library/myapp:v1 [root@k8s-master ~]# docker tag timinglee/myapp:v2 reg.timinglee.org/library/myapp:v2 #3. 将打好标签镜像推送到harbor仓库library项目 [root@k8s-master ~]# docker push reg.timinglee.org/library/myapp:v1 The push refers to repository [reg.timinglee.org/library/myapp] 68695a6cfd7d: Layer already exists d39d92664027: Layer already exists 8460a579ab63: Layer already exists c1dc81a64903: Layer already exists 05a9e65e2d53: Layer already exists a0d2c4392b06: Layer already exists v1: digest: sha256:238a348a45b26007ee5ecead440a7bb9cb31446081a823172797ba3c8c7acfb4 size: 1157 [root@k8s-master ~]# docker push reg.timinglee.org/library/myapp:v22.4 控制器管理 Pod(Deployment)
生产环境使用 Deployment 控制器管理 Pod,实现副本管理、滚动更新、版本回滚、自愈。
# 创建deployment,2副本 [root@k8s-master ~]# kubectl create deployment webcluster --replicas 2 --image myapp:v1 deployment.apps/webcluster created # 查看deployment root@k8s-master ~]# kubectl get deployments.apps NAME READY UP-TO-DATE AVAILABLE AGE webcluster 2/2 2 2 13s # 删除deployment [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE webcluster-77c87d9946-d8dzt 1/1 Running 0 2m27s webcluster-77c87d9946-kx8rq 1/1 Running 0 2m27s [root@k8s-master ~]# kubectl delete deployments.apps webcluster deployment.apps "webcluster" deleted from default namespace [root@k8s-master ~]# kubectl get pods No resources found in default namespace. # 扩缩容 [root@k8s-master ~]# kubectl scale deployment webcluster --replicas 4 deployment.apps/webcluster scaled [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE webcluster-7f8f75f8b9-5v252 1/1 Running 0 14s webcluster-7f8f75f8b9-mf4db 1/1 Running 0 3m45s webcluster-7f8f75f8b9-wmh8v 1/1 Running 0 14s webcluster-7f8f75f8b9-wpmbm 1/1 Running 0 14s [root@k8s-master ~]# kubectl scale deployment webcluster --replicas 1 deployment.apps/webcluster scaled [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE webcluster-7f8f75f8b9-mf4db 1/1 Running 0 3m51s # 查看发布状态 [root@k8s-master ~]# kubectl rollout status deployment webcluster deployment "webcluster" successfully rolled out # 重启deployment所有pod [root@k8s-master ~]# kubectl rollout restart deployment webcluster deployment.apps/webcluster restarted # 将deployment暴露为service,实现访问pod [root@k8s-master ~]# kubectl expose deployment webcluster --port 80 --target-port 80 service/webcluster exposed [root@k8s-master ~]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE extrnalname ExternalName <none> www.timinglee.org <none> 24h kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d6h webcluster ClusterIP 10.107.105.133 <none> 80/TCP 10s [root@k8s-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.107.105.133 IPs: 10.107.105.133 Port: <unset> 80/TCP TargetPort: 80/TCP Endpoints: 10.244.2.10:80 Session Affinity: None Internal Traffic Policy: Cluster Events: <none> [root@k8s-master ~]# curl 10.107.105.133/hostname.html webcluster-77c87d9946-h4lr5 # 直接修改资源 # edit:编辑yaml在线修改 [root@k8s-master ~]# kubectl create deployment webcluster --image myapp:v1 deployment.apps/webcluster created [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE webcluster-77c87d9946-h4lr5 1/1 Running 0 10s [root@k8s-master ~]# kubectl edit deployments.apps webcluster replicas: 2 [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE webcluster-77c87d9946-gf9hm 1/1 Running 0 10s webcluster-77c87d9946-h4lr5 1/1 Running 0 52s # patch补丁方式修改 [root@k8s-master ~]# kubectl patch deployments.apps webcluster -p '{"spec":{"replicas":1}}' deployment.apps/webcluster patched [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE webcluster-77c87d9946-h4lr5 1/1 Running 0 2m32s # 查看pod日志 [root@k8s-master ~]# kubectl logs pods/webcluster-77c87d9946-h4lr5 10.244.0.0 - - [25/Aug/2026:09:11:53 +0000] "GET /hostname.html HTTP/1.1" 200 28 "-" "curl/7.76.1" "-" # 进入pod容器 # attach:直接接入容器控制台,不分配伪终端 root@k8s-master ~]# kubectl run -it testpod --image busybox:latest 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. / # / # / # Session ended, resume using 'kubectl attach testpod -c testpod -i -t' command when the pod is running [root@k8s-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. / # # exec:在pod中执行命令,最常用进入容器 [root@k8s-master ~]# kubectl run testpod --image nginx:latest pod/testpod created [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE testpod 1/1 Running 0 8s webcluster-77c87d9946-h4lr5 1/1 Running 0 19m [root@k8s-master ~]# kubectl exec -it pods/testpod -c testpod -- /bin/bash root@testpod:/# # pod与本地主机文件互相拷贝 [root@k8s-master ~]# kubectl cp testpod:/usr/share/nginx/html/index.html /mnt/test tar: Removing leading `/' from member names [root@k8s-master ~]# kubectl cp testpod:/usr/share/nginx/html /mnt/ tar: Removing leading `/' from member names [root@k8s-master ~]# ls /mnt/ 50x.html hgfs index.html test [root@k8s-master ~]# echo timinglee > /mnt/index.html [root@k8s-master ~]# kubectl cp /mnt/index.html testpod:/usr/share/nginx/html/index.html [root@k8s-master ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES testpod 1/1 Running 0 2m21s 10.244.2.13 k8s-node2 <none> <none> webcluster-77c87d9946-h4lr5 1/1 Running 0 22m 10.244.2.10 k8s-node2 <none> <none> [root@k8s-master ~]# curl 10.244.2.13 timinglee2.5 标签管理 label
标签是 key=value 键值对,控制器依靠标签选择器匹配管理 Pod。
# 查看pod标签 [root@k8s-master ~]# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS webcluster-7f8f75f8b9-mf4db 1/1 Running 0 9m55s app=webcluster,pod-template-hash=7f8f75f8b9 # 增加标签 [root@k8s-master ~]# kubectl label pods webcluster-7f8f75f8b9-mf4db app=webcluster pod/webcluster-7f8f75f8b9-mf4db labeled [root@k8s-master ~]# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS webcluster-7f8f75f8b9-mf4db 1/1 Running 0 11m app=webcluster,pod-template-hash=7f8f75f8b9 # 覆盖已有标签 kubectl label pods webcluster-7f8f75f8b9-mf4db app=webcluster --overwrite # 删除标签,key后面加减号 k[root@k8s-master ~]# kubectl label pods webcluster-7f8f75f8b9-mf4db app- pod/webcluster-7f8f75f8b9-mf4db unlabeled [root@k8s-master ~]# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS webcluster-7f8f75f8b9-h2llz 1/1 Running 0 6s app=webcluster,pod-template-hash=7f8f75f8b9 webcluster-7f8f75f8b9-mf4db 1/1 Running 0 10m pod-template-hash=7f8f75f8b9- # 根据标签筛选资源 -l [root@k8s-master ~]# kubectl get pods -l app=webcluster NAME READY STATUS RESTARTS AGE webcluster-7f8f75f8b9-mf4db 1/1 Running 0 18m2.6 利用控制器实现版本更替
实验前提:harbor 仓库 library 项目中已经准备好
myapp:v1、myapp:v2两个镜像;Deployment 控制器依靠滚动更新机制完成业务版本升级、版本回退,业务更新过程不中断服务。2.6.1 建立控制器
两种方式创建 Deployment 控制器,命令行直接创建,或者导出 yaml 文件 apply 部署。
# 导出yaml模板 [root@k8s-master ~]# kubectl create deployment webcluster --image myapp:v1 --replicas 2 --dry-run=client -o yaml > webcluster.ymlwebcluster.yml 内容:
root@k8s-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 # 应用yaml创建控制器 [root@k8s-master ~]# kubectl apply -f webcluster.yml deployment.apps/webcluster created # 查看pod状态 [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE webcluster-77c87d9946-jcrlz 1/1 Running 0 7s webcluster-77c87d9946-rs8cd 1/1 Running 0 7s # 查看更新历史 [root@k8s-master ~]# kubectl rollout history deployment webcluster deployment.apps/webcluster REVISION CHANGE-CAUSE 1 <none> # 暴露service为NodePort,外部可以访问业务 [root@k8s-master ~]# kubectl expose deployment webcluster --port 80 --target-port 80 --type NodePort service/webcluster exposed # 查看service获取nodePort端口 [root@k8s-master ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE extrnalname ExternalName <none> www.timinglee.org <none> 25h kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d7h webcluster NodePort 10.111.60.94 <none> 80:38224/TCP 5s [root@k8s-master ~]# curl http://172.25.254.100:38224/hostname.html webcluster-77c87d9946-h8pdm2.6.2 更新业务版本(滚动更新)
# 更新镜像版本为v2,触发滚动更新 [root@k8s-master ~]# kubectl set image deployments webcluster myapp=myapp:v2 deployment.apps/webcluster image updated # 给本次更新添加版本注释,方便history查看记录 [root@k8s-master ~]# kubectl annotate deployment webcluster kubernetes.io/change-cause="myappv2" --overwrite deployment.apps/webcluster annotated # 观察pod变化,旧pod逐步销毁,新pod逐步创建 [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE webcluster-6c8b4bb9d7-48f9r 1/1 Running 0 19s webcluster-6c8b4bb9d7-vthnl 1/1 Running 0 21s # 查看版本变更历史记录 [root@k8s-master ~]# kubectl rollout history deployment webcluster deployment.apps/webcluster REVISION CHANGE-CAUSE 1 <none> 2 myappv2 [root@k8s-master ~]# curl http://172.25.254.100:38224 Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>2.6.3 版本回退
新版本业务出现 bug,执行 rollout undo 进行版本回滚,回滚会复用旧版本 ReplicaSet。
# 回退至上一个版本 [root@k8s-master ~]# kubectl rollout undo deployment webcluster deployment.apps/webcluster rolled back [root@k8s-master ~]# kubectl rollout history deployment webcluster deployment.apps/webcluster REVISION CHANGE-CAUSE 2 myappv2 3 <none> # 回退到指定revision版本,例如回退revision=1(v1版本) [root@k8s-master ~]# kubectl rollout undo deployment webcluster --to-revision=2 deployment.apps/webcluster rolled back [root@k8s-master ~]# kubectl rollout history deployment webcluster deployment.apps/webcluster REVISION CHANGE-CAUSE 3 <none> 4 myappv2 # 监控回滚pod变化 root@k8s-master ~]# kubectl get pods -w NAME READY STATUS RESTARTS AGE webcluster-6c8b4bb9d7-64d4d 1/1 Running 0 15s webcluster-6c8b4bb9d7-nktnz 1/1 Running 0 14s补充命令
# 查看发布进度 kubectl rollout status deployment webcluster # 重启控制器下全部pod kubectl rollout restart deployment webcluster三、YAML 声明式编写 Pod
3.1 快速生成 yaml 模板
# --dry-run=client 只输出yaml,不会创建资源 root@k8s-master ~]# kubectl run testpod --image myapp:v1 --dry-run=client -o yaml > testpod.yaml3.2 Pod yaml 核心字段说明
字段 说明 apiVersion 资源 API 版本,Pod 使用 v1,Deployment 使用 apps/v1 kind 资源类型:Pod/Deployment/Service metadata 元数据,name 名称、namespace 命名空间、labels 标签 spec 期望状态,核心配置 spec.containers\[\] 容器数组,可以写多个容器实现多容器 Pod spec.restartPolicy 重启策略 Always/OnFailure/Never spec.nodeSelector 节点标签选择,指定 pod 调度到哪个节点 spec.hostNetwork 是否共享宿主机网络 spec.resources CPU 内存资源请求与限制 基础单容器 Pod
[root@k8s-master ~]# vim testpod.yaml apiVersion: v1 kind: Pod metadata: labels: run: testpod name: testpod spec: containers: - image: reg.timinglee.org/library/myapp:v1 name: myapp执行:
# 创建/更新资源 kubectl apply -f testpod.yaml # 删除资源 kubectl delete -f testpod.yamlPod 内部多容器
同一个 Pod 多个容器共享网络,可以localhost互相访问,注意端口不能冲突。
[root@k8s-master ~]# vim testpod.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 [root@k8s-master ~]# kubectl apply -f testpod.yaml pod/testpod created [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE testpod 2/2 Running 0 25s 进入指定容器 [root@k8s-master ~]# kubectl exec -it pods/testpod -c busybox -- /bin/sh /bin/sh: shopt: not found [ root@testpod:/ ]$ curl 127.0.0.1 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>端口配置 hostPort
hostPort 将容器端口映射到宿主机节点端口,注意同一个节点不能启动多个相同 hostPort 的 Pod,端口冲突。
apiVersion: v1 kind: Pod metadata: labels: run: testpod name: testpod spec: containers: - image: myapp:v1 name: myapp1 ports: - name: http containerPort: 80 #pod内部容器端口 hostPort: 80 #pod所在节点端口 protocol: TCP #端口所用协议 [root@k8s-master ~]# kubectl apply -f testpod.yaml pod/testpod created [root@k8s-master ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES testpod 1/1 Running 0 7s 10.244.2.32 k8s-node2 <none> <none> [root@k8s-master ~]# curl k8s-node2 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>环境变量 env
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 [root@k8s-master ~]# kubectl apply -f mysql.yml pod/mysql created [root@k8s-master ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES mysql 0/2 ContainerCreating 0 7s <none> k8s-node2 <none> <none>指定调度节点 nodeSelector
根据节点标签,强制 Pod 调度匹配标签的节点。
[root@k8s-master ~]# kubectl get nodes --show-labels NAME STATUS ROLES AGE VERSION LABELS k8s-master Ready control-plane 5d7h v1.35.7 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers= k8s-node1 Ready <none> 5d2h v1.35.7 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux k8s-node2 Ready <none> 5d7h v1.35.7 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node2,kubernetes.io/os=linux root@k8s-master ~]# vim testpod.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 root@k8s-master ~]# kubectl apply -f mysql.yml pod/mysql created [root@k8s-master ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES mysql 2/2 Running 0 7s 10.244.2.34 k8s-node2 <none> <none>共享宿主机网络 hostNetwork:true
Pod 直接复用宿主机网络栈,PodIP 就是节点主机 IP。
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 [root@k8s-master ~]# kubectl apply -f testpod.yaml pod/testpod created [root@k8s-master ~]# kubectl exec -it pods/testpod -c busybox -- /bin/sh / # / # ifconfig cni0 Link encap:Ethernet HWaddr F2:F4:C3:31:6E:44 inet addr:10.244.2.1 Bcast:10.244.2.255 Mask:255.255.255.0 inet6 addr: fe80::f0f4:c3ff:fe31:6e44/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1 RX packets:19498 errors:0 dropped:0 overruns:0 frame:0 TX packets:19576 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:1769571 (1.6 MiB) TX bytes:2418429 (2.3 MiB) docker0 Link encap:Ethernet HWaddr 4A:99:2E:8F:C4:BD inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:16 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) eth0 Link encap:Ethernet HWaddr 00:0C:29:D9:65:AB inet addr:172.25.254.20 Bcast:172.25.254.255 Mask:255.255.255.0 inet6 addr: fe80::4e19:1e0d:4a92:a53f/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1088624 errors:0 dropped:0 overruns:0 frame:0 TX packets:69815 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:1597749729 (1.4 GiB) TX bytes:6793679 (6.4 MiB) flannel.1 Link encap:Ethernet HWaddr DE:49:EF:37:F9:00 inet addr:10.244.2.0 Bcast:0.0.0.0 Mask:255.255.255.255 inet6 addr: fe80::dc49:efff:fe37:f900/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1 RX packets:91 errors:0 dropped:0 overruns:0 frame:0 TX packets:65 errors:0 dropped:41 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:5992 (5.8 KiB) TX bytes:6971 (6.8 KiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:20217 errors:0 dropped:0 overruns:0 frame:0 TX packets:20217 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:1672988 (1.5 MiB) TX bytes:1672988 (1.5 MiB) veth44aae0d1 Link encap:Ethernet HWaddr 5A:F6:18:2B:6E:84 inet6 addr: fe80::58f6:18ff:fe2b:6e84/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1 RX packets:9732 errors:0 dropped:0 overruns:0 frame:0 TX packets:10193 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1065375 (1.0 MiB) TX bytes:1411443 (1.3 MiB) veth8697265e Link encap:Ethernet HWaddr A2:53:62:B1:DD:32 inet6 addr: fe80::a053:62ff:feb1:dd32/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1 RX packets:9358 errors:0 dropped:0 overruns:0 frame:0 TX packets:9936 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:901610 (880.4 KiB) TX bytes:1051768 (1.0 MiB) / #四、Pod 资源 QoS 优先级
Pod 设置
resources.requests(资源请求,调度时保证最小资源)、resources.limits(资源上限,最大可用资源),会生成 QoS 等级,当节点资源不足,内核优先驱逐低优先级 Pod。
Guaranteed(最高优先级):requests 与 limits 的 cpu、memory 全部相等
[root@k8s-master ~]# vim testpod.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
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[root@k8s-master ~]# kubectl apply -f testpod.yaml
pod/testpod created
[root@k8s-master ~]# kubectl describe pods testpod | grep "QoS Class:"
QoS Class: GuaranteedBurstable(中等优先级):设置了 requests/limits,但两者值不相等
resources:
limits:
cpu: 700m
memory: 200M
requests:
cpu: 500m
memory: 100M[root@k8s-master ~]# kubectl apply -f testpod.yaml
pod/testpod created
[root@k8s-master ~]# kubectl describe pods testpod | grep "QoS Class:"
QoS Class: BurstableBestEffort(最低优先级):完全不设置 resources 任何参数,资源不足最先被驱逐。
[root@k8s-master ~]# kubectl apply -f testpod.yaml pod/testpod created [root@k8s-master ~]# kubectl describe pods testpod | grep "QoS Class:" QoS Class: BestEffort五、Pod 重启策略 restartPolicy
三种策略,Deployment 控制器只能使用 Always。
Always(默认):容器无论什么退出,都会重启。适合 web 服务类。
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
[root@k8s-node2 ~]# docker ps --filter "name=testpod"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
06c27207c73f 40680ace50cf "/bin/sh -c 'sleep 6..." 19 seconds ago Up 19 seconds k8s_busybox_testpod_default_ee34008d-1019-4afc-9c4b-6e5b0785d55d_2
[root@k8s-node2 ~]# docker rm -f 06c27207c73f
06c27207c73f
root@k8s-master ~]# kubectl get pods -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
testpod 0/1 Completed 2 (2m55s ago) 4m58s 172.25.254.20 k8s-node2
testpod 0/1 CrashLoopBackOff 2 (58s ago) 5m13s 172.25.254.20 k8s-node2
testpod 1/1 Running 3 (59s ago) 5m14s 172.25.254.20 k8s-node2OnFailure:容器异常退出(退出码非 0)才重启;正常退出 (0) 不会重启。适合批处理任务。
spec:
restartPolicy: OnFailureNever:容器退出,无论成功失败,绝不重启。一次性任务。
spec:
restartPolicy: Never六、Pod 生命周期、Init 容器
Pod 生命周期流程:
初始化(init容器执行) → 启动业务容器 → 探针持续检测 → 终止销毁Init 容器
Init 容器在业务容器启动之前顺序执行,必须全部成功退出,才会启动业务主容器;init 失败会反复重启 Pod。 典型场景:等待外部依赖服务就绪、下载配置、初始化数据库。
[root@k8s-master ~]# kubectl run webserver --image myapp:v1 --dry-run=client -o yaml > init-example.yml [root@k8s-master ~]# vim init-example.ymapiVersion: 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 wating for myservice; sleep 2;done" containers: - image: myapp:v1 name: webserver restartPolicy: Alwaysl root@k8s-master ~]# kubectl apply -f init-example.yml pod/webserver created [root@k8s-master ~]# kubectl exec -it pods/webserver -c busybox -- /bin/sh / # / # touch /testfile [root@k8s-master ~]# watch -n 1 kubectl get pods -o wide七、容器探针(Probe)健康检查
kubelet 定期执行探针,检测容器健康,分为 3 种探针:
- livenessProbe 存活探针:判断容器进程是否正常,探测失败直接杀死容器,根据重启策略重启容器,解决进程假死。
- readinessProbe 就绪探针 :判断业务是否可以接收流量,探测失败,把 pod 从 service 的 endpoints 移除,不再转发流量,不会杀死容器。
- startupProbe 启动探针:慢启动应用,启动探针成功之后才启用另外两个探针。
探针支持三种探测方式:
exec命令执行、tcpSocket端口探测、httpGet http请求探测。探针通用参数:
initialDelaySeconds:容器启动后延迟多久开始探测periodSeconds:探测间隔时间timeoutSeconds:探测超时时间存活探针 tcp 探测端口
无存活探针
[root@k8s-master ~]# kubectl run testpod --image myapp:v1 --dry-run=client -o yaml > livness-example.yaml [root@k8s-master ~]# vim livness-example.yaml apiVersion: v1 kind: Pod metadata: labels: run: webserver name: webserver spec: containers: - image: myapp:v1 name: webserver command: ["/bin/sh", "-c"] args: - | nginx -g "daemon off;" sleep 10000 restartPolicy: Always [root@k8s-master ~]# kubectl apply -f livness-example.yaml pod/webserver created [root@k8s-master ~]# kubectl exec -it pods/webserver -c webserver -- /bin/sh / # nginx -s stop 2026/08/25 11:21:25 [notice] 15#15: signal process started / # exec attach failed: error on attach stdin: read escape sequence command terminated with exit code 126 #查看pod的状态仍然是runing,但是访问此pod时访问失败 [root@k8s-master ~]# watch -n 1 kubectl get pods -o wide [root@k8s-master ~]# curl 10.244.2.38 curl: (7) Failed to connect to 10.244.2.38 port 80: 拒绝连接有存活探针
apiVersion: v1 kind: Pod metadata: labels: run: webserver name: webserver 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 [root@k8s-master ~]# kubectl apply -f livness-example.yaml pod/webserver created [root@k8s-master ~]# kubectl get pods -o wide -w NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES webserver 1/1 Running 0 67s 10.244.2.41 k8s-node2 <none> <none> [root@k8s-master ~]# kubectl exec -it pods/webserver -c testpod -- /bin/sh / # nginx -s stop 2026/08/25 11:40:52 [notice] 14#14: signal process started / # exec attach failed: error on attach stdin: read escape sequence command terminated with exit code 126 [root@k8s-master ~]# curl 10.244.2.41 [root@k8s-master ~]# curl 10.244.2.41 curl: (7) Failed to connect to 10.244.2.41 port 80: 拒绝连接 [root@k8s-master ~]# curl 10.244.2.41 curl: (7) Failed to connect to 10.244.2.41 port 80: 拒绝连接 [root@k8s-master ~]# curl 10.244.2.41 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>就绪探针 httpGet 访问页面
无就绪探针
[root@k8s-master ~]# kubectl run testpod --image myapp:v1 --dry-run=client -o yaml > readness-example.yml [root@k8s-master ~]# vim readness-example.yml 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 [root@k8s-master ~]# kubectl apply -f readness-example.yml pod/webserver created service/webserver created [root@k8s-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.100.206.3 IPs: 10.100.206.3 Port: <unset> 80/TCP TargetPort: 80/TCP Endpoints: 10.244.2.39:80 Session Affinity: None Internal Traffic Policy: Cluster Events: <none> [root@k8s-master ~]# kubectl exec -it pods/webserver -c webserver -- /bin/sh / # cd /usr/share/nginx/ /usr/share/nginx # ls html /usr/share/nginx # cd html/ /usr/share/nginx/html # rm -fr index.html /usr/share/nginx/html # ls 50x.html /usr/share/nginx/html # exec attach failed: error on attach stdin: read escape sequence command terminated with exit code 126 [root@k8s-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.100.206.3 IPs: 10.100.206.3 Port: <unset> 80/TCP TargetPort: 80/TCP Endpoints: 10.244.2.39:80 #还在 Session Affinity: None Internal Traffic Policy: Cluster Events: <none> [root@k8s-master ~]# curl 10.100.206.3 <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>有就绪探针
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 [root@k8s-master ~]# kubectl apply -f readness-example.yml pod/webserver created service/webserver unchanged [root@k8s-master ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES webserver 1/1 Running 0 17s 10.244.2.40 k8s-node2 <none> <none> [root@k8s-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.100.206.3 IPs: 10.100.206.3 Port: <unset> 80/TCP TargetPort: 80/TCP Endpoints: 10.244.2.40:80 Session Affinity: None Internal Traffic Policy: Cluster Events: <none> [root@k8s-master ~]# kubectl exec -it pods/webserver -c webserver -- /bin/sh / # rm -fr /usr/share/nginx/html/index.html / # echo timinglee > /usr/share/nginx/html/index.html / # exec attach failed: error on attach stdin: read escape sequence command terminated with exit code 126 [root@k8s-master ~]# curl 10.100.206.3 timinglee业务场景:nginx 进程还活着,但是主页文件丢失返回 403/404,liveness 探针认为进程端口正常不会重启;此时 readiness 探针失败,service 摘除该 pod,不再转发流量。
八、Pod 排错思路总结
kubectl get pods看 pod 状态,确认 Running/Error/CrashLoopBackOff/ImagePullBackOffkubectl get pods -o wide确认调度节点、podIPkubectl describe pod xxx重点看 Events 事件,绝大多数错误都在这里kubectl logs podname [-c 容器名]查看容器内部日志kubectl exec -it podname -- /bin/bash进入容器内部复现问题