📘 Day 06:DaemonSet、StatefulSet、Job、CronJob

🎯 今日目标

  • 部署 DaemonSet 实现每节点一个采集 Pod
  • 部署 StatefulSet 实现有状态应用
  • 理解 StatefulSet Pod 的稳定网络标识
  • 创建 Job 并行计算任务
  • 创建 CronJob 定时任务

🧠 理论精讲(30 分钟)

四种工作负载对比

工作负载 副本特征 Pod 标识 启动/停止顺序 典型场景
Deployment 可多可少,Pod 无差别 随机名(xxx-abcde-xyz) 无顺序,并行 无状态 Web
DaemonSet 每节点一个 节点名相关 无顺序 日志采集、监控 Agent
StatefulSet 固定数量,每个唯一 有序序号(xxx-0, xxx-1) 顺序启动,逆序停止 数据库、消息队列
Job 一次性,完成即止 随机名 无顺序 数据迁移、计算任务
CronJob 按定时规则创建 随机名 无顺序 定时备份、定时清理

StatefulSet 核心特性

1
2
3
4
1. 稳定的网络标识:<sts-name>-<序号>.<headless-svc>.<ns>.svc.cluster.local
2. 稳定的持久存储:每个 Pod 有独立 PVC,Pod 重建后仍绑定同一 PVC
3. 有序部署和缩放:0→1→2→...,缩容时逆序
4. 有序滚动更新:N-1→N-2→...→0

Job 关键参数

参数 含义 默认值
completions 需要成功完成多少次 1
parallelism 最大并行执行数 1
backoffLimit 失败重试次数 6
activeDeadlineSeconds 任务超时时间

🔧 动手实操(120 分钟)

练习 6.1:DaemonSet 日志采集器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 1. 创建一些测试 Pod 分散在不同节点
kubectl create deploy test-app --image=nginx:alpine --replicas=5

# 2. 部署 DaemonSet 日志采集器
cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector
spec:
selector:
matchLabels:
app: log-collector
template:
metadata:
labels:
app: log-collector
spec:
containers:
- name: collector
image: busybox:1.36
command:
- sh
- -c
- |
mkdir -p /host-data
while true; do
echo "[$(date)] Host: $(hostname)" >> /host-data/collector.log
sleep 5
done
volumeMounts:
- name: host-logs
mountPath: /host-data
volumes:
- name: host-logs
hostPath:
path: /tmp/collector-logs
type: DirectoryOrCreate
EOF

# 3. 验证每个节点都有一个 Pod
kubectl get pod -l app=log-collector -o wide
# 预期:3 个 Pod(每节点 1 个)

# 4. 验证数据写入
# 登录任一 worker 节点
ssh k8s-node1
cat /tmp/collector-logs/collector.log
# 看到采集日志

# 5. 查看 DaemonSet 状态
kubectl get ds log-collector
# DESIRED=3 CURRENT=3 READY=3

# 6. 清理
kubectl delete ds log-collector
kubectl delete deploy test-app

练习 6.2:StatefulSet 部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# 1. 先创建 Headless Service(必须!)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: nginx-sts
spec:
clusterIP: None # Headless Service 的关键!
selector:
app: nginx-sts
ports:
- port: 80
targetPort: 80
EOF

# 2. 部署 StatefulSet
cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx-sts
spec:
serviceName: nginx-sts
replicas: 3
selector:
matchLabels:
app: nginx-sts
template:
metadata:
labels:
app: nginx-sts
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Mi
EOF

# 3. 观察顺序创建(0→1→2)
kubectl get pod -l app=nginx-sts -w
# nginx-sts-0 Running
# nginx-sts-1 Running
# nginx-sts-2 Running

# 4. 验证网络标识
kubectl exec nginx-sts-0 -- hostname
# nginx-sts-0

kubectl run dns-test --image=busybox:1.36 --rm -it --restart=Never -- \
nslookup nginx-sts-0.nginx-sts.default.svc.cluster.local
# 返回 Pod IP

# 5. 验证 PVC 自动创建
kubectl get pvc
# 每个 Pod 独立 PVC:data-nginx-sts-0, data-nginx-sts-1, data-nginx-sts-2

# 6. 写入数据验证持久性
kubectl exec nginx-sts-0 -- sh -c 'echo "pod-0-data" > /usr/share/nginx/html/data.txt'

# 7. 删除 Pod 观察重建
kubectl delete pod nginx-sts-0
kubectl get pod nginx-sts-0 -w
# Pod 重建后名称仍然是 nginx-sts-0

# 8. 验证数据仍在(PVC 绑定未变)
kubectl exec nginx-sts-0 -- cat /usr/share/nginx/html/data.txt
# 输出:pod-0-data

# 9. 顺序缩容
kubectl scale sts nginx-sts --replicas=1
kubectl get pod -l app=nginx-sts -w
# 逆序终止:nginx-sts-2 Terminating → nginx-sts-1 Terminating

# 10. 扩容
kubectl scale sts nginx-sts --replicas=3

# 11. 清理
kubectl delete sts nginx-sts
kubectl delete svc nginx-sts
# ⚠️ PVC 不会自动删除,需要手动清理
kubectl delete pvc data-nginx-sts-0 data-nginx-sts-1 data-nginx-sts-2

练习 6.3:Job 并行计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 1. 基础 Job
cat <<EOF | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: compute-pi
spec:
template:
spec:
containers:
- name: pi
image: perl:5.34
command:
- perl
- -Mbignum=bpi
- -wle
- print bpi(200)
restartPolicy: Never
backoffLimit: 4
EOF

# 2. 观察 Job 执行
kubectl get job compute-pi -w
# COMPLETIONS 从 0/1 → 1/1

kubectl get pod -l job-name=compute-pi
# Pod 状态 Completed

# 3. 查看计算结果
kubectl logs job/compute-pi
# 输出 π 值

# 4. 并行 Job
cat <<'EOF' | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: parallel-job
spec:
completions: 6
parallelism: 2
template:
spec:
containers:
- name: worker
image: busybox:1.36
command:
- sh
- -c
- |
echo "Task $((JOB_COMPLETION_INDEX+1)) running on $(hostname)"
sleep $(( RANDOM % 10 ))
echo "Task done"
restartPolicy: Never
backoffLimit: 4
EOF

# 5. 观察并行执行
kubectl get pod -l job-name=parallel-job -w
# 每次最多 2 个 Pod 同时运行

kubectl get job parallel-job
# COMPLETIONS: 6/6

# 6. 清理
kubectl delete job compute-pi parallel-job

练习 6.4:CronJob 定时任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 1. 创建每分钟执行的 CronJob
cat <<EOF | kubectl apply -f -
apiVersion: batch/v1
kind: CronJob
metadata:
name: health-checker
spec:
schedule: "*/1 * * * *"
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
containers:
- name: checker
image: busybox:1.36
command:
- sh
- -c
- |
echo "[$(date)] Health check executed"
echo "Checking DNS..."
nslookup kubernetes.default.svc.cluster.local
echo "OK"
restartPolicy: Never
backoffLimit: 2
EOF

# 2. 查看 CronJob
kubectl get cj
kubectl describe cj health-checker

# 3. 等待 1~2 分钟,查看自动创建的 Job
kubectl get jobs
# 看到 health-checker-<timestamp>

# 4. 查看 Job 创建的 Pod
kubectl get pod -l job-name

# 5. 查看日志
kubectl logs job/health-checker-<timestamp>

# 6. 手动触发一次(不再等待定时器)
kubectl create job --from=cronjob/health-checker manual-run

# 7. 查看手动任务的日志
kubectl logs job/manual-run

# 8. 清理
kubectl delete cj health-checker
kubectl delete job manual-run

🐛 排错练习(30 分钟)

场景 1:StatefulSet Pod 一直 Pending

1
2
3
4
5
6
7
8
9
10
# 原因 1:PVC 无法绑定
kubectl get pvc
# STATUS: Pending

kubectl describe pvc <pvc-name>
# 看到 "no persistent volumes available..."

# 解决方案:
# - 检查 StorageClass 是否存在:kubectl get sc
# - 创建 PV 或确保 default StorageClass 可用

场景 2:CronJob 不触发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 排查步骤

# 1. 检查 CronJob 配置
kubectl describe cj <name>
# 查看 Last Schedule Time

# 2. 检查 concurrencyPolicy
kubectl get cj <name> -o yaml | grep concurrencyPolicy
# Allow / Forbid / Replace

# 3. 检查 startingDeadlineSeconds
kubectl get cj <name> -o yaml | grep startingDeadlineSeconds

# 4. 检查 Job 是否被创建
kubectl get jobs --sort-by=.metadata.creationTimestamp

# 常见原因:
# - schedule 语法错误
# - concurrencyPolicy=Forbid 且上一次 Job 未完成
# - startingDeadlineSeconds 过期

🏆 赛题模拟(40 分钟)

⚠️ 严格限时 40 分钟

题目:工作负载综合部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
【操作要求】

1. 部署 StatefulSet:
- 名称:redis-cluster
- 副本数:3
- 镜像:redis:7-alpine
- 配置 redis 启动命令:redis-server --appendonly yes
- 通过 volumeClaimTemplates 为每个 Pod 创建 100Mi PVC
- 对应的 Headless Service 名称为 redis-svc

2. 部署 DaemonSet:
- 名称:node-monitor
- 镜像:busybox:1.36
- 每 10 秒打印节点主机名和当前时间到 stdout

3. 部署 CronJob:
- 名称:redis-backup
- 每 30 分钟执行一次
- 使用 busybox:1.36
- 命令:echo "backup at $(date)"

4. 验证:
- redis-cluster-0/1/2 全部 Running
- node-monitor 在每个节点一个 Pod
- redis-backup CronJob 显示在 kubectl get cj 中

5. 写入测试数据到 redis-cluster-0,删除该 Pod,
重建后验证数据是否保留(通过 PVC 持久化)

【评分标准】
- StatefulSet + Headless Service 正确(30 分)
- DaemonSet 正确(20 分)
- CronJob 正确(20 分)
- PVC 自动创建(15 分)
- 数据持久性验证(15 分)

📋 命令速查

命令 功能 注解
kubectl get ds 列出 DaemonSet 每个节点运行一个 Pod 副本
kubectl get ds -o wide DaemonSet + 选择器/镜像 确认每个节点是否都有 Pod
kubectl describe ds <name> DaemonSet 详情 查看更新策略(RollingUpdate/OnDelete)
kubectl get sts 列出 StatefulSet StatefulSet 常用 short name: sts
kubectl describe sts <name> StatefulSet 详情 查看 podManagementPolicy、serviceName、volumeClaimTemplates
kubectl get pods -l app=mysql 按标签筛选 Pod StatefulSet Pod 命名:<name>-0, <name>-1, ...
kubectl scale sts <name> --replicas=5 扩缩 StatefulSet 按序号递增/递减创建/删除 Pod
kubectl get pvc 列出 PVC StatefulSet + volumeClaimTemplates 自动为每个 Pod 创建 PVC
kubectl get job 列出 Job 一次性任务,完成后 Pod 状态为 Completed
kubectl describe job <name> Job 详情 查看 completions、parallelism、backoffLimit
kubectl logs job/<name> 查看 Job 日志 Job Pod 执行完不会自动删除,可事后查看日志
kubectl get cronjob 列出 CronJob short name: cj
kubectl describe cronjob <name> CronJob 详情 查看 schedule、lastScheduleTime、suspend 状态
kubectl get jobs --watch 实时监控 Job 创建 观察 CronJob 触发时自动创建的 Job
kubectl create job test-job --image=busybox --dry-run=client -o yaml 生成 Job YAML 快速获取 Job 模板
kubectl create cronjob test-cj --image=busybox --schedule="*/5 * * * *" --dry-run=client -o yaml 生成 CronJob YAML 5 字段 cron 表达式(分/时/日/月/周)
kubectl delete job <name> 删除 Job 级联删除其完成的 Pod
kubectl delete cronjob <name> 删除 CronJob 不会删除正在运行的 Job 和 Pod
kubectl patch cronjob <name> -p '{"spec":{"suspend":true}}' 暂停 CronJob 停止后续调度,保留历史

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:DaemonSet https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
Kubernetes 官方:StatefulSet https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
Kubernetes 官方:Job https://kubernetes.io/docs/concepts/workloads/controllers/job/
Kubernetes 官方:CronJob https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
Kubernetes 官方:工作负载资源 https://kubernetes.io/docs/concepts/workloads/controllers/
Cron 表达式语法 https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-schedule-syntax

📘 Day 07:Pod 资源综合实战

🎯 今日目标

  • 在一个命名空间内从零搭建多类型工作负载
  • 通过故障注入验证 K8s 自愈能力
  • 完成完整的版本发布与回滚流程
  • 能根据业务需求选择正确的工作负载类型

🧠 理论精讲(10 分钟)

工作负载选型决策树

1
2
3
4
5
6
7
需要运行容器?
├── 需要每节点一个?──→ DaemonSet
├── 需要稳定网络标识 + 持久存储?──→ StatefulSet
├── 一次性任务?──→ Job
├── 定时任务?──→ CronJob
├── 无状态、需要滚动更新?──→ Deployment
└── 单个 Pod,不需要自愈?──→ Pod(restartPolicy: Never)

🔧 动手实操(150 分钟)

练习 7.1:从零构建微服务应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# 创建独立命名空间
kubectl create ns microshop

# === 1. 数据库层(StatefulSet) ===
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: db-svc
namespace: microshop
spec:
clusterIP: None
selector:
app: shop-db
ports:
- port: 6379
targetPort: 6379
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: shop-db
namespace: microshop
spec:
serviceName: db-svc
replicas: 1
selector:
matchLabels:
app: shop-db
template:
metadata:
labels:
app: shop-db
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
volumeMounts:
- name: db-data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: db-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Mi
EOF

# === 2. 后端服务(Deployment) ===
cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: microshop
spec:
replicas: 2
selector:
matchLabels:
app: shop-backend
template:
metadata:
labels:
app: shop-backend
spec:
containers:
- name: api
image: nginx:alpine
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 3
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
EOF

kubectl expose deploy backend -n microshop --name=backend-svc --port=80

# === 3. 前端服务(Deployment) ===
kubectl create deploy frontend -n microshop --image=nginx:alpine --replicas=3
kubectl expose deploy frontend -n microshop --name=frontend-svc --port=80

# === 4. 日志采集(DaemonSet) ===
cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-agent
namespace: microshop
spec:
selector:
matchLabels:
app: log-agent
template:
metadata:
labels:
app: log-agent
spec:
containers:
- name: logger
image: busybox:1.36
command:
- sh
- -c
- |
while true; do
echo "[$(date)] Node: $(hostname) - collecting logs"
sleep 10
done
EOF

# === 5. 定时清理(CronJob) ===
cat <<'EOF' | kubectl apply -f -
apiVersion: batch/v1
kind: CronJob
metadata:
name: log-cleanup
namespace: microshop
spec:
schedule: "0 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: cleanup
image: busybox:1.36
command:
- sh
- -c
- echo "Cleaning old logs at $(date)"
restartPolicy: Never
EOF

# 6. 验证全部资源
kubectl get all -n microshop
# 预期:
# - Pod: frontend×3, backend×2, shop-db-0×1, log-agent×3
# - Service: db-svc, backend-svc, frontend-svc
# - DaemonSet: log-agent
# - StatefulSet: shop-db
# - CronJob: log-cleanup

练习 7.2:故障演练

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 故障 1:删除 Pod(验证自愈)
kubectl get pod -n microshop -l app=shop-backend
POD_NAME=$(kubectl get pod -n microshop -l app=shop-backend -o name | head -1)
kubectl delete $POD_NAME -n microshop
kubectl get pod -n microshop -l app=shop-backend -w
# 观察:旧 Pod Terminating,新 Pod 自动创建并 Running

# 故障 2:杀掉容器进程(验证 livenessProbe)
BACKEND_POD=$(kubectl get pod -n microshop -l app=shop-backend -o name | head -1)
kubectl exec $BACKEND_POD -n microshop -- nginx -s stop
# 预期:livenessProbe 失败 → 容器重启
kubectl get $BACKEND_POD -n microshop -w
# RESTARTS 列递增

# 故障 3:缩容 frontend(验证可用性)
kubectl scale deploy/frontend -n microshop --replicas=1
kubectl get pod -n microshop -l app=shop-frontend
# 只保留 1 个

# 故障 4:模拟节点不可用(cordon)
kubectl cordon k8s-node1
# 注意:已有 Pod 不受影响,新 Pod 不调度到 node1

# 恢复
kubectl uncordon k8s-node1
kubectl scale deploy/frontend -n microshop --replicas=3

练习 7.3:版本演练

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1. 记录当前版本
kubectl get deploy -n microshop backend -o jsonpath='{.spec.template.spec.containers[0].image}'
# nginx:alpine

# 2. 更新 backend
kubectl set image deploy/backend -n microshop api=nginx:alpine-slim
kubectl annotate deploy/backend -n microshop kubernetes.io/change-cause="switch to slim image"
kubectl rollout status deploy/backend -n microshop

# 3. 查看历史
kubectl rollout history deploy/backend -n microshop

# 4. 制造一个失败更新
kubectl set image deploy/backend -n microshop api=nginx:9.9.9-invalid
kubectl annotate deploy/backend -n microshop kubernetes.io/change-cause="invalid update"

# 5. 发现失败,立即回滚
kubectl rollout undo deploy/backend -n microshop
kubectl rollout status deploy/backend -n microshop

# 6. 最终验证
kubectl get deploy -n microshop backend
kubectl rollout history deploy/backend -n microshop

🏆 赛题模拟(40 分钟)

⚠️ 严格限时 40 分钟

题目:微服务应用全流程部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
【场景】
为一个电商系统部署基础设施,包含缓存层、API 层、Web 层和监控组件。

【环境要求】
- 新建命名空间:ecommerce

【操作要求】
1. 缓存层:StatefulSet redis-cache(2 副本)
- 镜像 redis:7-alpine
- Headless Service redis-cache-svc
- 每个 Pod 独立 PVC(50Mi)

2. API 层:Deployment api-server(3 副本)
- 镜像 nginx:alpine
- 配置 livenessProbe + readinessProbe
- 资源限制:cpu 100m, memory 128Mi
- 滚动策略:maxSurge=1, maxUnavailable=0
- ClusterIP Service api-svc

3. Web 层:Deployment web-front(3 副本)
- 镜像 httpd:alpine
- ClusterIP Service web-svc

4. 监控层:DaemonSet node-exporter
- 镜像 busybox:1.36
- 每 5 秒输出主机名和时间

5. 备份任务:CronJob data-backup
- 镜像 busybox:1.36
- 每 15 分钟执行备份命令

6. 故障测试:
- 删除一个 api-server Pod → 验证自愈
- 缩容 redis-cache 到 1 → 观察顺序缩容
- 模拟 API 版本更新并回滚

【评分标准】
- 所有资源正确创建(40 分)
- Service 正确关联(15 分)
- 探针配置正确(15 分)
- 故障测试通过(20 分)
- 版本回滚成功(10 分)

🧹 环境清理

1
2
3
# 练习结束后清理
kubectl delete ns microshop
kubectl delete ns ecommerce

📋 命令速查

命令 功能 注解
kubectl apply -f <manifest>.yaml 声明式部署资源 综合实战中一次性部署多种资源
kubectl get all 查看所有资源 Pod/Service/Deploy/RS/StatefulSet/DaemonSet/Job 一览
kubectl get pods --show-labels Pod + 标签 验证标签是否与 Service Selector 匹配
kubectl get pods -L app,version 按指定标签列显示 Pod -L 将标签值作为独立列展示
kubectl describe svc <name> Service 详情 查看 Endpoints 是否绑定到正确的 Pod
kubectl get endpoints <svc> 查看 Service 后端 Endpoints 为空说明 Selector 不匹配或 Pod 未就绪
kubectl run tmp --image=busybox --rm -it -- wget -O- http://<svc>:<port> 临时 Pod 测试服务连通性 --rm 退出即删,测试网络首选
kubectl exec <pod> -- env 查看容器环境变量 验证 ConfigMap/Secret 注入是否正确
kubectl exec <pod> -- cat /etc/config/key 查看挂载的配置文件 验证 ConfigMap/Secret 挂载内容
kubectl exec <pod> -- nslookup <svc-name> 验证 DNS 解析 确认 CoreDNS 正常工作
kubectl -n <ns> logs -l app=<name> --tail=20 按标签批量查看日志 -l 按标签选择器筛选 Pod
kubectl top pods --sort-by=cpu 按 CPU 排序 Pod 用量 找出资源消耗最大的 Pod
kubectl get events --sort-by=.metadata.creationTimestamp 按时间排序事件 按时间线排查问题

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:工作负载 https://kubernetes.io/docs/concepts/workloads/
Kubernetes 官方:标签与选择器 https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
Kubernetes 官方:Service https://kubernetes.io/docs/concepts/services-networking/service/
Kubernetes 官方:应用排错 https://kubernetes.io/docs/tasks/debug/debug-application/

📘 Day 04:Pod 生命周期与多容器模式

🎯 今日目标

  • 能画出 Pod 生命周期状态流转图
  • 能创建含 InitContainer 的 Pod
  • 能实现 Sidecar 模式的 Pod
  • 能正确配置三种探针
  • 能排查 Pod CrashLoopBackOff 问题

🧠 理论精讲(30 分钟)

Pod 是什么

Pod 是 K8s 最小的调度单元(不是容器!)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
┌───────────────────────── Pod ─────────────────────────┐
│ │
│ 共享网络命名空间(同一个 IP) │
│ 共享 IPC 命名空间 │
│ 共享 Volume(通过 volumes 声明) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Container│ │ Container│ │ Container│ ← Sidecar │
│ │ (主) │ │ (辅助) │ │ (辅助) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ │ │
│ ┌───────┴────────┐ │
│ │ shared volumes│ │
│ └────────────────┘ │
└─────────────────────────────────────────────────────────┘

Pod 生命周期

1
2
3
4
5
6
7
Pending ──→ Running ──→ Succeeded(正常退出)
│ │
│ ├──→ Failed(异常退出)
│ │
│ └──→ Unknown(节点失联)

└──→ ContainerCreating(拉镜像、挂载卷)

三种多容器模式

模式 说明 典型场景
Sidecar 辅助容器增强主容器 日志采集、配置热更新、代理
Ambassador 代理容器屏蔽外部复杂性 数据库代理、服务发现代理
Adapter 适配容器统一接口 日志格式转换、监控指标标准化

三种探针

探针 作用 失败后果
livenessProbe 检查容器是否还活着 重启容器
readinessProbe 检查容器是否可接收流量 从 Service Endpoint 移除
startupProbe 检查容器是否启动完成 启动期间屏蔽 liveness 和 readiness

🔧 动手实操(120 分钟)

练习 4.1:观察 Pod 完整生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 1. 创建 Pod 并实时观察
kubectl run lifecycle-pod --image=nginx:alpine --restart=Never

# 在另一个终端 watch
kubectl get pod lifecycle-pod -w
# 观察:Pending → ContainerCreating → Running

# 2. 查看详细信息
kubectl describe pod lifecycle-pod
# 重点关注 Events 部分

# 3. 进入容器看运行细节
kubectl exec lifecycle-pod -- cat /etc/nginx/conf.d/default.conf

# 4. 删除并观察终止过程(默认 30 秒优雅终止)
kubectl delete pod lifecycle-pod &
kubectl get pod lifecycle-pod -w
# 观察:Running → Terminating → 消失

# 5. 创建带较长 terminationGracePeriodSeconds 的 Pod
kubectl run graceful-pod --image=nginx:alpine --restart=Never \
--overrides='{"spec":{"terminationGracePeriodSeconds":60}}'

# 验证
kubectl get pod graceful-pod -o jsonpath='{.spec.terminationGracePeriodSeconds}'
kubectl delete pod graceful-pod

练习 4.2:Sidecar 模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 创建 Sidecar Pod:主容器写日志,Sidecar 读取
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: sidecar-demo
spec:
containers:
- name: app
image: busybox:1.36
args:
- /bin/sh
- -c
- |
i=0
while true; do
echo "$(date): log entry $i" >> /var/log/app.log
i=$((i+1))
sleep 2
done
volumeMounts:
- name: logs
mountPath: /var/log

- name: log-reader
image: busybox:1.36
args:
- /bin/sh
- -c
- tail -f /var/log/app.log
volumeMounts:
- name: logs
mountPath: /var/log

volumes:
- name: logs
emptyDir: {}
EOF

# 验证 Sidecar 能读到主容器的日志
kubectl logs sidecar-demo -c log-reader --tail=10

# 查看两个容器的状态
kubectl get pod sidecar-demo
# READY 2/2

# 清理
kubectl delete pod sidecar-demo

练习 4.3:InitContainer 等待依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 第一步:创建需要等待的依赖 Service
kubectl create deploy backend --image=nginx:alpine --replicas=1
kubectl expose deploy backend --port=80

# 第二步:创建带 InitContainer 的 Pod
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
initContainers:
- name: wait-for-backend
image: busybox:1.36
command:
- sh
- -c
- |
echo "Waiting for backend service..."
until wget -q --spider http://backend-service.default.svc.cluster.local; do
echo "Backend not ready yet..."
sleep 2
done
echo "Backend is ready!"
containers:
- name: app
image: busybox:1.36
command:
- sh
- -c
- echo "Main app started!" && sleep 3600
EOF

# 观察 InitContainer 执行
kubectl get pod init-demo -w
# 看到 STATUS 列:Init:0/1 → PodInitializing → Running

# 查看 InitContainer 日志
kubectl logs init-demo -c wait-for-backend

# 清理
kubectl delete pod init-demo
kubectl delete deploy backend
kubectl delete svc backend

练习 4.4:livenessProbe 排错实战

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: liveness-demo
spec:
containers:
- name: unhealthy
image: busybox:1.36
command:
- sh
- -c
- |
touch /tmp/healthy
# 30 秒后删除健康标志文件,模拟程序故障
sleep 30
rm /tmp/healthy
sleep 3600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
EOF

# 持续观察 Pod 状态
kubectl get pod liveness-demo -w

# 另一个终端查看事件
kubectl describe pod liveness-demo | grep -A5 "Events"

# 预期:约 30 + 5*3 = 45 秒后 Pod 被重启
kubectl get pod liveness-demo
# RESTARTS 列从 0 递增

# 清理
kubectl delete pod liveness-demo

练习 4.5:readinessProbe 流量控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: readiness-demo
spec:
replicas: 2
selector:
matchLabels:
app: readiness-demo
template:
metadata:
labels:
app: readiness-demo
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 3
---
apiVersion: v1
kind: Service
metadata:
name: readiness-svc
spec:
selector:
app: readiness-demo
ports:
- port: 80
targetPort: 80
EOF

# 查看 Endpoint 变化
kubectl get endpoints readiness-svc -w
# Pod Ready 后 Endpoint 出现

# 模拟 Pod 不健康:修改 nginx 配置让 / 返回错误
# (略,比赛环境可能需要替代方案)

# 清理
kubectl delete deploy readiness-demo
kubectl delete svc readiness-svc

🐛 排错练习(30 分钟)

场景 1:Pod CrashLoopBackOff

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 创建一个会立即退出的 Pod
kubectl run crash-demo --image=busybox:1.36 --restart=Always -- /bin/false

# 观察状态
kubectl get pod crash-demo
# STATUS: CrashLoopBackOff

# 查看上一次崩溃的日志
kubectl logs crash-demo --previous

# 查看事件
kubectl describe pod crash-demo | grep -A10 Events

# 进入容器调试(如果容器立即退出,无法 exec)
kubectl run debug-pod --image=busybox:1.36 --restart=Never -it --rm -- sh

# 清理
kubectl delete pod crash-demo

场景 2:READY 0/1 但状态 Running

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 创建一个配置了错误端口的 readinessProbe
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: ready-fail
spec:
containers:
- name: nginx
image: nginx:alpine
readinessProbe:
httpGet:
path: /
port: 8080 # 错误端口!nginx 在 80
initialDelaySeconds: 3
periodSeconds: 3
EOF

# 观察
kubectl get pod ready-fail
# STATUS: Running READY: 0/1

kubectl describe pod ready-fail | grep -A5 Readiness
# Warning Unhealthy Readiness probe failed: dial tcp ...:8080: connect: connection refused

# 修复:正确配置端口 → 直接重建 Pod(探针不可变)
kubectl delete pod ready-fail

🏆 赛题模拟(40 分钟)

⚠️ 严格限时 40 分钟

题目:多容器应用 Pod 设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
【操作要求】

1. 创建一个 Pod,名称为 multi-container-app,包含:
- 1 个 InitContainer(名称为 init-setup):
* 镜像 busybox:1.36
* 从 wget 获取一个测试 HTML 文件写入 /data/index.html
* 共享卷 data-volume
- 1 个主容器(名称为 web-server):
* 镜像 nginx:alpine
* 将 /data/index.html 挂载到 /usr/share/nginx/html/index.html
* 配置 readinessProbe:HTTP GET /,端口 80
* 配置 livenessProbe:HTTP GET /,端口 80,
initialDelaySeconds: 10, periodSeconds: 5
- 1 个 Sidecar 容器(名称为 health-checker):
* 镜像 busybox:1.36
* 每 10 秒执行 wget -q --spider http://localhost 并输出状态
* 共享网络命名空间(同 Pod 内自然共享)

2. 验证:
- 所有容器正常运行(kubectl get pod 显示 2/2 Ready)
- InitContainer 执行成功(查看日志)
- Sidecar 能访问 localhost 的 nginx

3. 排错:
- 修改主容器端口为 8080(通过环境变量 NGINX_PORT=8080 或其他方式)
观察 readiness 探针是否失败

【提交物】
- 完整的 Pod YAML
- 每步骤的验证命令截图或输出
- 遇到的问题和排查过程

【评分标准】
- YAML 结构正确(30 分)
- Pod 状态 2/2 Ready(30 分)
- InitContainer 执行成功(15 分)
- 探针配置正确(15 分)
- 排错分析(10 分)

📋 命令速查

命令 功能 注解
kubectl run nginx --image=nginx:alpine 快速创建 Pod 直接创建单个 Pod(非 Deployment)
kubectl run nginx --image=nginx:alpine --dry-run=client -o yaml > pod.yaml 生成 Pod YAML 最佳 YAML 生成方式,比手写快且不出错
kubectl get pods -o wide Pod + 节点 + IP 定位 Pod 运行位置
kubectl get pods -w 实时监控 Pod 状态变化 观察 Pod 从 Pending → Running 全过程
kubectl describe pod <pod> Pod 详细信息 Events 段包含调度决策、镜像拉取状态、容器启停原因
kubectl logs <pod> -c <container> --tail=20 指定容器最后 20 行日志 多容器模式必须用 -c 指定
kubectl logs <pod> --all-containers=true 所有容器日志 一次性查看 Pod 内全部容器输出
kubectl exec <pod> -- <cmd> 在容器内执行命令 用于健康检查、调试
kubectl exec -it <pod> -- /bin/sh 交互式进入容器 查看文件系统、进程、网络连通性
kubectl port-forward pod/<pod> 8080:80 本地端口转发到 Pod 无需 Service 直接访问 Pod 端口
kubectl delete pod <pod> 删除 Pod 优雅终止(默认 30s)
kubectl delete pod <pod> --force --grace-period=0 强制立即删除 卡在 Terminating 时救急
kubectl delete pod <pod> --now 立即删除 Pod --now = --grace-period=1
kubectl wait --for=condition=Ready pod/<pod> 等待 Pod 就绪 脚本中阻塞直到 Pod Ready
kubectl cp <pod>:<path> <local-path> 从 Pod 复制文件 双向可操作
kubectl top pods Pod 实时资源用量 需安装 metrics-server
kubectl get events --field-selector involvedObject.name=<pod> 查看特定 Pod 的 Event 比 describe 更轻量
kubectl debug -it <pod> --image=busybox --target=<container> 调试容器(临时容器) 1.25+ 支持,不影响原容器运行

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:Pod https://kubernetes.io/docs/concepts/workloads/pods/
Kubernetes 官方:Pod 生命周期 https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
Kubernetes 官方:Init 容器 https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
Kubernetes 官方:探针配置 https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
Kubernetes 官方:边车容器 https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/
Kubernetes 官方:临时容器调试 https://kubernetes.io/docs/tasks/debug/debug-application/debug-running-pod/#ephemeral-container

进程管理-pstree ⚙️ — 树形显示进程关系

作用

pstree 以树状图展示进程间的父子关系,直观呈现系统服务拓扑结构。

语法

1
pstree [选项] [PID|用户]

用法

pstree 以树状展示进程层次。-p 显示 PID,-u 显示进程所有者,-H PID 高亮指定进程及其父链,-A ASCII 字符(非 UTF-8 终端)。-n 按 PID 排序。适合理解进程间启动关系。

常用参数

参数 说明
-p 显示 PID
-u 显示进程所有者
-H PID 高亮指定进程
-A ASCII 字符显示
-n 按 PID 排序
-l 显示长命令行参数
-g 显示进程组 ID (PGID)

示例

1
2
3
4
5
pstree                          # 树形显示所有进程
pstree -p # 显示进程 PID
pstree -u # 显示进程所有者
pstree -H 1234 # 高亮 PID 1234 的进程链
pstree ALICE # 只显示 ALICE 的进程树

来源:菜鸟教程

进程管理-renice ⚙️ — 修改运行进程优先级

作用

renice 修改正在运行进程的 nice 优先级值。

语法

1
renice [选项] 优先级 -p PID...

用法

renice 调整已有进程的 nice 值。-n 19 -p PID 降低优先级。-u 用户 调整用户所有进程的优先级。只有 root 可提高优先级(负 nice)。

常用参数

参数 说明
-n N 设置 nice 值
-p PID 指定进程
-g 组 指定组
-u 用户 指定用户

示例

1
2
3
renice -n 10 -p 1234            # 降低 PID 1234 的优先级
renice -n 19 -p 5678 9012 # 将多个进程设为最低优先级
renice -n 5 -u ALICE # 调整 ALICE 所有进程的优先级

来源:菜鸟教程

进程管理-time ⚙️ — 测量命令执行时间

作用

time 统计命令执行耗时,输出 real(实际)、user(用户 CPU)、sys(系统 CPU)三段时间。

语法

1
time 命令

用法

time 在命令执行完毕后输出统计:REAL 从开始到结束的总耗时,USER 用户态 CPU 时间,SYS 内核态 CPU 时间。-p POSIX 格式。-f 格式 自定义输出格式。脚本性能分析和基准测试的基础工具。

常用参数

参数 说明
-p POSIX 格式输出
-f 格式 自定义输出格式
-a 追加到文件
-o 文件 输出到文件

示例

1
2
3
time sleep 2                          # 测量 sleep 2 秒的实际耗时
time ls -la # 测量 ls 命令的执行时间
time -p make # POSIX 格式输出编译耗时

来源:菜鸟教程

进程管理-top ⚙️ — 实时进程监控

作用

top 实时动态显示系统进程活动和资源占用,按 CPU 或内存排序,排查系统性能问题的首选工具。

语法

1
top [选项]

用法

top 交互式界面:按 P 按 CPU 排序,M 按内存排序,K 输入 PID 杀进程,R 调整优先级(renice),1 查看每个 CPU 核心,Q 退出。-d N 刷新间隔秒数,-u 用户 只监控指定用户,-p PID 监控指定进程。

常用参数

参数 说明
-d N 刷新间隔(秒)
-u 用户 只监控指定用户
-p PID 监控指定进程
-H 线程模式
-b 批处理模式
-n N 刷新次数后退出

示例

1
2
3
4
5
top                             # 启动实时监控
top -d 5 # 每 5 秒刷新
top -u ALICE # 只监控 ALICE 的进程
top -p 1234 # 监控指定 PID
top -bn 3 > TOP.LOG # 批处理模式输出 3 次到文件

来源:菜鸟教程

📖 课程位置

本命令在以下课程中讲解:Day 3:进程查看与管理 | Day 5:本周串联实操

进程管理-uptime ⚙️ — 查看系统运行时间

作用

uptime 一行显示当前时间、系统运行时长、登录用户数、1/5/15 分钟平均负载。

语法

1
uptime [选项]

用法

uptime 输出的平均负载若持续超过 CPU 核数表明系统过载。例如 8 核 CPU 负载持续 > 8 说明有瓶颈。-p 显示友好格式的运行时长,-s 自启动时间点。

常用参数

参数 说明
-p 显示友好格式的运行时长
-s 自启动时间点

示例

1
2
uptime           # 查看运行时长和平均负载
uptime -p # 显示友好格式的运行时长(如 up 1 hour, 15 minutes)

来源:菜鸟教程

📖 课程位置

本命令在以下课程中讲解:Day 3:系统资源监控 | Day 5:本周串联实操

进程管理-watch ⚙️ — 周期性执行命令

作用

watch 按固定间隔重复执行命令并刷新输出,默认 2 秒。

语法

1
watch [选项] 命令

用法

watch 以指定间隔执行命令,全屏刷新输出。-n 1 每秒刷新,-d 高亮变化行,-t 不显示标题。常用于持续监控:watch -n 1 'df -h' 监控磁盘,watch -n 1 'ps aux | grep nginx' 监控进程。

常用参数

参数 说明
-n N 刷新间隔(秒)
-d 高亮变化行
-t 不显示标题
-e 命令失败时暂停
-g 输出变化时退出(–chgexit)
-x 命令带更多参数

示例

1
2
3
4
watch -n 1 'df -h'                   # 每秒刷新监控磁盘使用
watch -n 5 'ps aux | grep nginx' # 每 5 秒监控 nginx 进程
watch -d 'free -h' # 高亮变化行监控内存
watch -n 60 'ls -l' # 每分钟查看文件变化

来源:菜鸟教程

进程管理-htop ⚙️ — 交互式进程查看器

作用

htop 是 top 的增强版,彩色界面、鼠标支持、树形视图和更直观的操作(需额外安装)。

语法

1
htop [选项]

用法

htop 交互更友好:方向键导航,F1-F10 快捷键操作,F5 树形视图,F6 排序,F9 杀进程。-t 树形模式,-u USER 只显示指定用户进程。彩色显示 CPU/内存/交换分区使用条。

常用参数

参数 说明
-t 树形视图
-u USER 只显示指定用户
-p PID 监控指定进程
-d N 刷新间隔(十分之一秒)
--no-color 单色模式

示例

1
2
3
4
htop                            # 启动交互式进程查看器
htop -t # 树形视图
htop -u ALICE # 只显示 ALICE 的进程
htop -d 10 # 每 1 秒刷新(10 个十分之一秒)

来源:菜鸟教程

0%