📘 Day 27:赛题模拟 6-7

🎯 今日目标

完成 2 套高阶赛题,覆盖监控排错和全栈运维。


🏆 赛题 6:监控与故障排查(110 分钟)

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
【场景】现有集群出现问题,需要你排查并建立监控。

【操作要求】(总分 100 分)

Part A: 监控部署(30 分)
1. 使用 Helm 安装 kube-prometheus-stack:
- namespace: monitoring
- Grafana NodePort 30300
- Prometheus NodePort 30900
2. 登录 Grafana 查看集群概览仪表盘
3. 在 Prometheus 中查询:
- 所有节点的内存使用率
- CPU 使用率最高的 5 个 Pod

Part B: 故障排查(40 分)
【每个故障独立,写出完整排查过程】

故障 4.1: Pod 不断重启
- Deployment broken-api 的 Pod 状态 CrashLoopBackOff
- RESTARTS 计数已达 27
→ 请排查原因并修复

故障 4.2: Service 无法访问
- 集群内 curl http://user-svc 返回 503
- kubectl get svc user-svc 显示正常
→ 请排查原因并修复

故障 4.3: PVC 绑定失败
- PVC app-data 状态 Pending 已 10 分钟
- 集群中有多个 PV
→ 请排查原因并修复

故障 4.4: 节点异常
- k8s-node2 状态 NotReady
→ 请排查原因并修复

Part C: 告警配置(30 分)
5. 创建 PrometheusRule:
a. Pod 重启次数 > 5(15分钟)→ warning
b. Pod CrashLoopBackOff 持续 > 2分钟 → critical
c. 节点 NotReady → critical
d. PVC Pending 超过 5 分钟 → warning

6. 在 Prometheus Alerts 页面验证规则生效

【验证清单】
□ Prometheus + Grafana 可访问
□ 4 个故障全部排查并修复
□ 告警规则在 Prometheus 中可见

🏆 赛题 7:全栈运维综合(110 分钟)

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
【场景】从零搭建一个完整的博客平台,包括部署、配置、监控、安全。

【操作要求】(总分 100 分)

Part A: 基础设施(20 分)
1. 创建命名空间 blog-platform
2. 配置 ResourceQuota:
- CPU 请求 4 核,内存 8Gi
- 最多 20 个 Pod
3. 配置 LimitRange:默认 requests cpu=100m mem=128Mi

Part B: 应用部署(30 分)
4. 数据库层:
- StatefulSet blog-db(2 副本,mysql:8.0)
- Headless Service blog-db-svc
- volumeClaimTemplates: 2Gi
- Secret 注入 root 密码

5. 缓存层:
- Deployment blog-cache(2 副本,redis:7-alpine)
- ClusterIP Service cache-svc

6. 应用层:
- Deployment blog-app(3 副本,nginx:alpine)
- ClusterIP Service app-svc
- 通过 ConfigMap 注入:DB_HOST=blog-db-svc, CACHE_HOST=cache-svc
- 通过 Secret 注入:DB_PASSWORD

7. 入口层:
- Ingress 规则:blog.example.com → app-svc:80

Part C: 安全加固(20 分)
8. 创建 NetworkPolicy:
a. blog-app → blog-db:3306
b. blog-app → blog-cache:6379
c. 拒绝其他 Pod 访问数据库和缓存
9. SecurityContext:
- runAsNonRoot, drop ALL cap, readOnlyRootFilesystem=false

Part D: 运维管理(20 分)
10. 配置 HPA:blog-app CPU 60%, min 2, max 8
11. 创建 CronJob db-backup:
- 每天凌晨 2 点执行
- 命令:echo "db backup at $(date)"
12. 创建 DaemonSet log-shipper:
- 每节点一个,采集日志

Part E: 验证与文档(10 分)
13. 验证所有组件正常运行
14. 写出运维手册(排查 Pod 崩溃的步骤)

【验证清单】
□ 所有 Pod Running
□ Ingress 可访问
□ NetworkPolicy 隔离生效
□ HPA 生效
□ CronJob 配置正确
□ DaemonSet 每节点一个 Pod

📋 命令速查

该赛题涉及的核心命令速查:

命令 功能 注解
kubectl create deploy <name> --image=<image> 创建 Deployment 应用部署基础
kubectl scale deploy <name> --replicas=<n> 扩缩副本 手动扩缩
kubectl autoscale deploy <name> --min=2 --max=10 --cpu=80% 创建 HPA 自动扩缩配置
kubectl get hpa 查看 HPA 状态 确认自动扩缩生效
kubectl top pods 查看 Pod 资源用量 HPA 依赖 metrics-server
kubectl taint node <node> <k>=<v>:NoSchedule 添加节点污点 赛题中”限制调度”操作
kubectl label node <node> <k>=<v> 给节点打标签 配合 nodeSelector/affinity
kubectl create sa <name> -n <ns> 创建 ServiceAccount 权限管理
kubectl create role <name> --verb=get,list --resource=pods -n <ns> 创建 Role 命名空间级权限
kubectl create rolebinding <name> --role=<role> --serviceaccount=<ns>:<sa> -n <ns> 绑定 Role 到 SA 完成授权
kubectl auth can-i <verb> <resource> --as=system:serviceaccount:<ns>:<sa> 验证权限 RBAC 配置验证

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:HPA https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/
Kubernetes 官方:RBAC https://kubernetes.io/docs/reference/access-authn-authz/rbac/
Kubernetes 官方:调度 https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/
CKA 模拟题 https://killer.sh

📘 Day 25:赛题模拟 1-3

🎯 今日目标

完成 3 套基础赛题,每套限时 70 分钟,覆盖集群管理 + 工作负载 + 配置管理。


🏆 赛题 1:集群初始化与基础部署(70 分钟)

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
【场景】你作为运维工程师,需要在一台新服务器上初始化 K8s 并部署基础应用。

【操作要求】(总分 100 分)

Part A: 集群初始化(30 分)
1. 安装 containerd、kubeadm、kubelet、kubectl
2. 初始化单节点集群:
- kubeadm init --pod-network-cidr=10.244.0.0/16
- 镜像源 registry.aliyuncs.com/google_containers
3. 安装 Flannel CNI:
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
4. 配置 kubectl 自动补全 + k 别名
5. 验证:kubectl get nodes 显示 Ready

Part B: 工作负载部署(30 分)
6. 创建 Deployment nginx-deploy:
- 镜像 nginx:1.25-alpine
- 4 副本
- 资源:requests cpu=100m mem=128Mi, limits cpu=300m mem=256Mi
- livenessProbe: HTTP GET /, 端口 80
- readinessProbe: HTTP GET /, 端口 80
7. 暴露为 NodePort Service,映射到 31080
8. 创建命名空间 dev,在其中创建 Deployment dev-api(nginx:alpine, 2 副本)

Part C: 配置管理(20 分)
9. 创建 ConfigMap app-config,包含 DB_HOST=mysql、DB_PORT=3306
10. 创建 Secret db-secret,包含 DB_PASSWORD=secret123
11. 创建 Pod config-pod(busybox:1.36),用 envFrom 注入 app-config

Part D: 基础运维(20 分)
12. 将 nginx-deploy 从 4 副本缩容到 2 副本
13. 对 nginx-deploy 执行滚动更新到 nginx:1.26-alpine
14. 回滚 nginx-deploy 到最初版本
15. 输出 nginx-deploy 的 rollout history

【验证清单】
□ kubectl get nodes → Ready
□ 所有 Pod Running
□ curl <NodeIP>:31080 → nginx
□ kubectl get endpoints nginx-deploy → 有 Endpoint
□ kubectl rollout history deploy/nginx-deploy → 有记录

🏆 赛题 2:多工作负载编排(70 分钟)

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
【场景】为一个微服务系统部署三层架构。

【操作要求】(总分 100 分)

Part A: StatefulSet 数据层(30 分)
1. 创建 Headless Service data-svc(端口 6379)
2. 创建 StatefulSet data-cluster(3 副本):
- 镜像 redis:7-alpine
- 命令 redis-server --appendonly yes
- volumeClaimTemplates: 100Mi
3. 验证 PVC 自动创建:data-cluster-data-0/1/2

Part B: Deployment 应用层(25 分)
4. 创建 Deployment api-service(3 副本,nginx:alpine)
5. 配置滚动更新策略:maxSurge=1, maxUnavailable=0
6. 配置 livenessProbe(HTTP GET /, 端口 80)
7. 配置 readinessProbe(同上)
8. 创建 ClusterIP Service api-svc

Part C: DaemonSet + CronJob(25 分)
9. 创建 DaemonSet node-logger(busybox:1.36):
- 每 10 秒输出节点主机名 + 时间
- 使用 hostPath 写日志到 /tmp/node-logs
10. 创建 CronJob data-backup:
- 每 30 分钟执行一次
- 命令:echo "backup $(date)"
- 保留最近 3 个成功的 Job 历史

Part D: 运维操作(20 分)
11. 对 api-service 执行滚动更新并记录 change-cause
12. 缩容 data-cluster 到 2,再扩容回 3
13. 验证 StatefulSet Pod 顺序(2→1 终止,1→2 启动)
14. 手动触发一次 data-backup CronJob

【验证清单】
□ data-cluster-0/1/2 Running, 独立 PVC
□ api-service 3/3 Ready
□ 每节点一个 node-logger Pod
□ kubectl get cj data-backup → SCHEDULE 正确

🏆 赛题 3:配置与存储综合(70 分钟)

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
【场景】为 Web 应用配置完整的配置管理和持久存储方案。

【操作要求】(总分 100 分)

Part A: 配置管理(25 分)
1. 创建 ConfigMap web-config(namespace: web-app):
- APP_ENV=staging
- APP_DEBUG=true
- MAX_UPLOAD_SIZE=10M
2. 创建 Secret web-secret(namespace: web-app):
- DB_PASSWORD=webpass123
- REDIS_PASSWORD=redispwd
- JWT_SECRET=jwt-secret-key

Part B: 存储配置(35 分)
3. 创建 hostPath 类型的 PV(pv-static,1Gi,RWO)
4. 创建 PVC(pvc-web-data,请求 500Mi)
5. 验证 PV 和 PVC 绑定

Part C: 应用部署(25 分)
6. 创建 Deployment web-server(3 副本,nginx:alpine):
- envFrom 注入 web-config
- valueFrom 注入 DB_PASSWORD(命名 DATABASE_PASSWORD)
- 挂载 PVC 到 /usr/share/nginx/html/data
- SecurityContext: runAsUser=1000
7. 创建 NodePort Service,映射到 32080

Part D: 验证(15 分)
8. 向 PVC 挂载目录写入测试文件
9. 删除 Pod 后验证 PVC 数据仍在
10. 验证环境变量注入正确

【验证清单】
□ ConfigMap 和 Secret 存在
□ PV/PVC Bound
□ Pod 环境变量包含 APP_ENV、DATABASE_PASSWORD
□ /usr/share/nginx/html/data 可读写
□ NodePort 可访问

📋 命令速查

该赛题涉及的核心命令速查:

命令 功能 注解
kubectl create deploy <name> --image=<image> --replicas=<n> 创建指定副本数的 Deployment 赛题最常见的开局操作
kubectl expose deploy <name> --port=<p> --target-port=<tp> 为 Deployment 创建 Service 赛题中”暴露服务”的标配命令
kubectl set image deploy/<name> <container>=<new-image> 滚动更新镜像 赛题中”更新应用”操作
kubectl rollout undo deploy/<name> 回滚 Deployment 赛题中”回滚到上一版本”
kubectl scale deploy <name> --replicas=<n> 扩缩副本 赛题中”调整副本数”
kubectl create cm <name> --from-literal=<k>=<v> 创建 ConfigMap 赛题中”创建配置”
kubectl create secret generic <name> --from-literal=<k>=<v> 创建 Secret 赛题中”创建密钥”
kubectl get pods -o wide 查看 Pod 分布 确认 Pod 是否按要求调度到指定节点
kubectl describe pod <pod> | grep -A 5 Conditions 查看 Pod 条件 验证 Pod 是否 Ready
kubectl exec <pod> -- curl -s http://<svc>:<port> 容器内测试服务 验证服务连通性
kubectl logs <pod> --tail=20 查看 Pod 日志 验证应用启动是否正常
kubectl apply -f <file>.yaml 声明式部署 综合赛题一次性部署多个资源

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:kubectl 速查表 https://kubernetes.io/docs/reference/kubectl/quick-reference/
Kubernetes 官方:Deployment https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
Kubernetes 官方:Service https://kubernetes.io/docs/concepts/services-networking/service/
CKA 模拟题 https://killer.sh — 赛题风格最接近的模拟
全国职业院校技能大赛官网 历年容器云赛题规程与样题

📘 Day 26:赛题模拟 4-5

🎯 今日目标

完成 2 套进阶赛题,每套限时 110 分钟,覆盖网络 + 安全 + 调度。


🏆 赛题 4:网络与安全加固(110 分钟)

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
【场景】搭建一个安全的微服务系统,实现网络隔离和精细权限控制。

【操作要求】(总分 100 分)

Part A: 三层网络(30 分)
1. 创建命名空间 net-secure
2. 部署三层应用:
a. frontend: Deployment web-ui(nginx:alpine, 2副本)
ClusterIP Service frontend-svc
b. backend: Deployment api-gateway(httpd:alpine, 3副本)
ClusterIP Service backend-svc
c. database: Pod data-db(redis:7-alpine)
ClusterIP Service db-svc

3. 配置 Ingress(NGINX Controller 已安装):
- / → frontend-svc:80
- /api → backend-svc:80
- rewrite-target: /

Part B: NetworkPolicy(30 分)
4. 创建 Deny-All 默认策略(拒绝所有 ingress)
5. 放行规则:
a. Ingress Controller → frontend-svc:80
b. frontend → backend-svc:80
c. backend → db-svc:6379
d. 所有 Pod → CoreDNS(UDP 53)
6. 验证:
- 外部可访问 frontend
- frontend 可访问 backend
- backend 可访问 db
- frontend 不可直接访问 db(跨层访问被阻止)

Part C: RBAC(25 分)
7. 创建 3 个 SA:sa-viewer, sa-dev, sa-admin
8. 创建 Role viewer-role:pods/deployments/svc get/list/watch
9. 创建 Role dev-role:viewer + create/update + pods/log
10. 创建 Role admin-role:全部权限
11. 分别绑定到对应 SA
12. 验证权限差异

Part D: SecurityContext(15 分)
13. 修改 backend Deployment:
- runAsUser: 1001
- runAsNonRoot: true
- allowPrivilegeEscalation: false
- drop ALL capabilities

【验证清单】
□ Ingress 路由正常工作
□ NetworkPolicy 隔离有效
□ RBAC 权限分级正确
□ backend 以非 root 用户运行

🏆 赛题 5:调度与弹性伸缩(110 分钟)

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
【场景】设计多租户 K8s 平台的调度和资源管理策略。

【操作要求】(总分 100 分)

Part A: 节点池划分(20 分)
1. 给节点打标签:
- k8s-node1: pool=frontend, zone=az1
- k8s-node2: pool=backend, zone=az1
- k8s-master: pool=management, zone=az1(移除 NoSchedule 污点用于测试)

2. 给 k8s-node1 添加污点 frontend=true:NoSchedule
(只有明确声明 toleration 的 Pod 才能调度到 frontend 节点)

Part B: 调度策略实战(30 分)
3. 创建 Deployment frontend-app(3 副本,nginx:alpine):
- nodeAffinity (required): pool=frontend
- toleration: frontend=true:NoSchedule
- podAntiAffinity (required): 按 hostname 分散

4. 创建 Deployment backend-app(2 副本,httpd:alpine):
- nodeAffinity (required): pool=backend
- topologySpreadConstraints: 按 zone 均匀分布,maxSkew=1

5. 观察调度结果并解释

Part C: 资源管理(30 分)
6. 创建命名空间 project-x
7. ResourceQuota project-x-quota:
- requests.cpu: 2
- requests.memory: 4Gi
- pods: 10
8. LimitRange project-x-limits:
- 默认 requests cpu=100m, mem=128Mi
- 默认 limits cpu=500m, mem=512Mi
- max cpu=1, max mem=1Gi

9. 创建 Deployment quota-test(3 副本):
- requests cpu=600m, mem=256Mi(验证是否能创建成功)
- 如果成功,尝试创建第 2 个相同 Deployment

Part D: HPA(20 分)
10. 创建 Deployment hpa-app(1 副本,nginx:alpine):
- requests cpu=50m
11. 配置 HPA:
- 目标 CPU 50%
- min 1, max 6
12. 生成负载或手动验证 HPA

【验证清单】
□ Pod 按节点标签正确分布
□ frontend-app 有 toleration
□ ResourceQuota 生效
□ HPA 显示目标

📋 命令速查

该赛题涉及的核心命令速查:

命令 功能 注解
kubectl create deploy <name> --image=<image> 创建 Deployment 快速部署应用
kubectl expose deploy <name> --type=NodePort --port=<p> --target-port=<tp> 创建 NodePort Service 外部可通过 节点IP:NodePort 访问
kubectl set image deploy/<name> <container>=<new-image> 更新容器镜像 触发滚动更新
kubectl rollout status deploy/<name> 查看更新进度 等待更新完成
kubectl rollout history deploy/<name> 查看部署历史 确认 revision 数
kubectl rollout undo deploy/<name> 回滚 赛题高频操作
kubectl get pv,pvc 查看存储绑定状态 确认 PVC 是否 Bound
kubectl create cm <name> --from-file=<file> 从文件创建 ConfigMap 配置文件注入
kubectl describe pod <pod> Pod 详情 查看挂载卷/环境变量/事件
kubectl exec <pod> -- cat <path> 验证挂载内容 确认配置是否正确注入
kubectl get events --sort-by=.lastTimestamp 查看集群事件 排错必用

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:kubectl 速查表 https://kubernetes.io/docs/reference/kubectl/quick-reference/
Kubernetes 官方:StatefulSet https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
Kubernetes 官方:PV/PVC https://kubernetes.io/docs/concepts/storage/persistent-volumes/
CKA 模拟题 https://killer.sh

📘 Day 24:故障排查实战

🎯 今日目标

  • 掌握 K8s 系统化排错方法
  • 能独立排查 Pod CrashLoopBackOff
  • 能排查 Service 不通的问题
  • 能排查 PVC 绑定失败

🧠 理论精讲(30 分钟)

系统化排错方法论

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
第 1 层:现象确认
kubectl get pods/nodes/svc → 确认哪个对象出问题?

第 2 层:事件查看
kubectl describe <resource> → 看 Events 区域

第 3 层:日志分析
kubectl logs <pod> → 应用日志
journalctl -u kubelet → 系统日志

第 4 层:深入诊断
kubectl exec → 进容器验证
网络: nc / curl / nslookup
存储: ls / df / mount

第 5 层:关联分析
有没有 NetworkPolicy?RBAC?ResourceQuota?

常见故障速查表

现象 可能原因 排查命令
Pending 资源不足/调度失败 describe pod
CrashLoopBackOff 应用崩溃/OOM logs --previous
ImagePullBackOff 镜像问题 describe pod
ContainerCreating 卷挂载/CNI describe pod
NotReady (Node) kubelet 问题 describe node
Service 不通 selector/label get endpoints
PVC Pending 无 PV/SC describe pvc

🔧 动手实操(120 分钟)

练习 24.1:Pod 故障排查

故障 1:CrashLoopBackOff

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
# 创建故意崩溃的 Pod
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: crash-demo
spec:
containers:
- name: bad-app
image: busybox:1.36
command: ["sh", "-c", "echo 'Starting...'; sleep 5; exit 1"]
EOF

# 排查流程:
# Step 1: 确认状态
kubectl get pod crash-demo
# STATUS: CrashLoopBackOff

# Step 2: 查看事件
kubectl describe pod crash-demo | grep -A15 Events
# Back-off restarting failed container

# Step 3: 查看日志(包括上一次)
kubectl logs crash-demo
kubectl logs crash-demo --previous
# Starting...

# Step 4: 结论 → 应用启动后 exit 1,需要检查应用配置
kubectl delete pod crash-demo

故障 2:OOMKilled

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
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: oom-demo
spec:
containers:
- name: mem-hog
image: busybox:1.36
command:
- sh
- -c
- dd if=/dev/zero of=/dev/shm/big bs=50M count=10
resources:
limits:
memory: "100Mi"
EOF

# 排查
kubectl get pod oom-demo -w
# STATUS: OOMKilled

kubectl describe pod oom-demo | grep -A5 "State"
# Reason: OOMKilled

kubectl delete pod oom-demo

故障 3:ImagePullBackOff

1
2
3
4
5
6
7
8
9
kubectl run bad-image --image=notexist/image:v99 --restart=Never

kubectl get pod bad-image
# STATUS: ImagePullBackOff / ErrImagePull

kubectl describe pod bad-image | grep -A5 Events
# Failed to pull image: notexist/image:v99

kubectl delete pod bad-image

练习 24.2:Service 网络故障排查

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
# 模拟 Service 不通的场景
# 1. 创建后端但故意 label 不匹配
kubectl create deploy web-backend --image=nginx:alpine --replicas=2

# 2. 创建 Service 选错误的 label
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: bad-svc
spec:
selector:
app: non-existent # 故意不匹配!
ports:
- port: 80
EOF

# 3. 排查
kubectl get endpoints bad-svc
# ENDPOINTS: <none> ← 问题!

kubectl get pod -l app=web-backend --show-labels
# 实际 label: app=web-backend

kubectl get svc bad-svc -o jsonpath='{.spec.selector}'
# {"app":"non-existent"}

# 4. 修复
kubectl patch svc bad-svc -p '{"spec":{"selector":{"app":"web-backend"}}}'
kubectl get endpoints bad-svc
# 现在有 ENDPOINTS 了

# 5. 清理
kubectl delete deploy web-backend
kubectl delete svc bad-svc

练习 24.3:节点故障排查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 模拟节点问题
# 1. 对节点加污点使其不可调度
kubectl taint node k8s-node1 test=block:NoSchedule

# 2. 创建 Pod 观察现象
kubectl run taint-test --image=nginx:alpine
kubectl get pod taint-test -o wide
# 被调度到其他节点

# 3. 如果所有节点都有污点?
kubectl describe pod taint-test | grep -A10 Events
# Warning FailedScheduling ...

# 4. 排查节点状况
kubectl describe node k8s-node1 | grep -A10 Taints
kubectl describe node k8s-node1 | grep -A5 Conditions
# MemoryPressure / DiskPressure / PIDPressure

# 5. 恢复
kubectl taint node k8s-node1 test-
kubectl delete pod taint-test

练习 24.4:存储故障排查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 模拟 PVC 无法绑定
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: impossible-pvc
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 100Ti # 不可能有的容量
EOF

# 排查
kubectl get pvc impossible-pvc
# STATUS: Pending

kubectl describe pvc impossible-pvc | grep -A5 Events
# "no persistent volumes available..."

kubectl get pv
# 没有 100Ti 的 PV

kubectl delete pvc impossible-pvc

🏆 赛题模拟(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
【场景】以下每个故障独立出现。针对每个故障写出:
1. 排查步骤(具体命令)
2. 可能的根因
3. 解决方案

【故障列表】

故障 1:Pod 状态 CrashLoopBackOff
- Deployment web-app 的 Pod 不断重启
- kubectl get pod 显示 RESTARTS=15

故障 2:Service 无法访问
- 集群内 curl http://api-svc 超时
- kubectl get svc api-svc 正常
- kubectl get endpoints api-svc 为空

故障 3:PVC 一直 Pending
- 创建了 PVC,状态始终 Pending
- kubectl get sc 为空

故障 4:Pod 调度失败
- 4 节点集群,创建 10 副本 Deployment
- 第 8 个 Pod 一直是 Pending
- kubectl describe pod 显示 Insufficient cpu

故障 5:DNS 解析失败
- Pod 内 nslookup kubernetes.default 返回 server can't find
- CoreDNS Pod Running 正常

【评分标准】
- 每个故障:排查步骤(10分) + 根因分析(5分) + 解决方案(5分)
- 总计 100 分

📋 命令速查

命令 功能 注解
kubectl describe pod <pod> | tail -30 Pod Events(排错第一入口) 80% 的故障在 Events 里能找到原因
kubectl get events --sort-by=.lastTimestamp 按时间排序所有事件 全局视角查看集群正在发生什么
kubectl get events -w 实时监听事件 操作时开一个终端 watch,观察连锁反应
kubectl get events --field-selector type=Warning 只看 Warning 事件 过滤 Normal 噪音,聚焦异常
kubectl get pods --field-selector=status.phase=Pending 筛选 Pending Pod 调度失败/镜像拉取失败
kubectl get pods --field-selector=status.phase=Failed 筛选 Failed Pod CrashLoopBackOff/Error/Completed(exit≠0)
kubectl get pods --field-selector=status.phase!=Running 筛选非 Running Pod 一次性找出所有问题 Pod
kubectl describe pod <pod> | grep -A 5 "State:|Ready:|Restart" 容器状态摘要 快速确认容器是 Waiting/Running/Terminated
kubectl describe pod <pod> | grep -B 2 "Exit Code" 查看容器退出码 Exit Code 137=OOMKilled, 143=SIGTERM, 1=应用错误
kubectl logs <pod> --previous 上一次崩溃的日志 CrashLoopBackOff 时当前容器可能还没产生日志
kubectl -n kube-system logs kube-apiserver-<node> apiserver 日志 集群入口故障,大量 5xx/超时根因在此
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50 CoreDNS 日志 DNS 解析超时/失败时的排查
kubectl -n kube-system logs -l k8s-app=calico-node --tail=50 CNI 日志 网络不通、Pod IP 分配失败
journalctl -u kubelet --since "5 min ago" --no-pager kubelet 近 5 分钟日志 无需 --no-pager 短输出更易读
kubectl cluster-info dump | grep -i "error|failed" | head -30 集群诊断 + 错误过滤 输出所有组件的日志摘要
kubectl get componentstatuses 控制平面组件健康 1.19+ 建议用 --raw='/readyz?verbose'
kubectl get nodes -o json | jq '.items[] | {name:.metadata.name, conditions:.status.conditions}' 节点 Conditions JSON 输出 结构化的节点健康状况

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:排错指南 https://kubernetes.io/docs/tasks/debug/
Kubernetes 官方:排错 Pod https://kubernetes.io/docs/tasks/debug/debug-application/debug-pods/
Kubernetes 官方:排错 Service https://kubernetes.io/docs/tasks/debug/debug-application/debug-service/
Kubernetes 官方:排错集群 https://kubernetes.io/docs/tasks/debug/debug-cluster/
Kubernetes 官方:节点健康监控 https://kubernetes.io/docs/tasks/debug/debug-cluster/kubectl-node-summary/
kubectl 排错速查表 https://kubernetes.io/docs/reference/kubectl/quick-reference/

📘 Day 23:日志收集与 EFK

🎯 今日目标

  • 理解 K8s 日志层级(容器→节点→集群)
  • 部署 Fluent Bit 做日志采集
  • 掌握 kubectl logs 的全部选项
  • 能排查日志丢失/配置错误

🧠 理论精讲(30 分钟)

K8s 日志三层架构

1
2
3
4
5
6
7
8
9
10
11
┌──────────────────────────────────────┐
│ Pod (Container stdout/stderr) │ ← 容器日志
│ ↓ 写入 │
│ Node (/var/log/containers/*.log) │ ← 节点层
│ ↓ 采集 │
│ Log Agent (DaemonSet: Fluent Bit) │ ← 采集层
│ ↓ 转发 │
│ Elasticsearch / Loki / Kafka │ ← 存储层
│ ↓ 查询 │
│ Kibana / Grafana │ ← 展示层
└──────────────────────────────────────┘

kubectl logs 进阶

选项 用途
--tail=N 最后 N 行
-f / --follow 实时跟踪
--since=5m 最近 5 分钟
--previous / -p 上一次容器的日志
--timestamps 显示时间戳
--all-containers 所有容器日志

🔧 动手实操(120 分钟)

练习 23.1:kubectl logs 精通

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
# 1. 创建一个多容器 Pod
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: log-demo
spec:
containers:
- name: app
image: busybox:1.36
command:
- sh
- -c
- |
i=0
while true; do
echo "[$(date +%T)][INFO] Application log entry $i"
i=$((i+1))
sleep 2
done
- name: sidecar
image: busybox:1.36
command:
- sh
- -c
- |
while true; do
echo "[$(date +%T)][DEBUG] Sidecar heartbeat"
sleep 5
done
EOF

# 2. 基础操作
kubectl logs log-demo -c app --tail=5
kubectl logs log-demo -c sidecar --tail=3

# 3. 跟踪日志
kubectl logs log-demo -c app -f &
# Ctrl+C 停止

# 4. 查看所有容器日志
kubectl logs log-demo --all-containers --tail=10

# 5. 查看最近 2 分钟的日志
kubectl logs log-demo -c app --since=2m

# 6. 带时间戳
kubectl logs log-demo -c app --timestamps --tail=5

# 7. 查看上一次崩溃的日志
# 先模拟崩溃
kubectl run crash-log --image=busybox:1.36 --restart=Always -- /bin/sh -c 'echo "About to crash"; exit 1'

sleep 15
kubectl logs crash-log --previous
# 输出:About to crash

# 清理
kubectl delete pod log-demo crash-log

练习 23.2:使用 stern 多 Pod 日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# stern 是比 kubectl logs 更好的多 Pod 日志工具

# 1. 安装 stern
# macOS
brew install stern
# Linux
wget https://github.com/stern/stern/releases/download/v1.28.0/stern_1.28.0_linux_amd64.tar.gz
tar -xzf stern_1.28.0_linux_amd64.tar.gz
sudo mv stern /usr/local/bin/

# 2. 创建多副本 Deployment
kubectl create deploy stern-test --image=busybox:1.36 --replicas=3 -- \
sh -c 'while true; do echo "[$(hostname)] log at $(date +%T)"; sleep 3; done'

# 3. stern 同时查看所有副本日志
stern stern-test --tail=5
# 按颜色区分不同 Pod!

# 4. 按标签过滤
stern -l app=stern-test --since=1m

# 5. 清理
kubectl delete deploy stern-test

练习 23.3:Fluent Bit 日志采集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1. 添加 Fluent Helm 仓库
helm repo add fluent https://fluent.github.io/helm-charts
helm repo update

# 2. 安装 Fluent Bit
helm install fluent-bit fluent/fluent-bit \
--namespace logging \
--create-namespace \
--set config.outputs.es.enabled=false \
--set config.outputs.stdout.enabled=true \
--set config.outputs.stdout.match="*"

# 3. 查看 Fluent Bit Pod
kubectl get pods -n logging
# fluent-bit-xxx(每个节点一个)

# 4. 查看 Fluent Bit 采集的日志(输出到 stdout)
kubectl logs -n logging -l app.kubernetes.io/name=fluent-bit --tail=20

# 5. 验证日志 Pipeline
kubectl get daemonset -n logging
kubectl get configmap -n logging
kubectl describe configmap -n logging fluent-bit

练习 23.4:节点日志直接查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 所有容器的 stdout/stderr 日志在这里
# SSH 到任一 worker 节点:
ls /var/log/containers/
# 每个容器一个 symlink → /var/log/pods/

# 2. 容器日志存储格式
ls /var/log/pods/
# <namespace>_<pod-name>_<pod-uid>/<container-name>/

# 3. 查看 kubelet 日志
sudo journalctl -u kubelet -n 50 --no-pager

# 4. 查看容器运行时日志(containerd)
sudo journalctl -u containerd -n 30 --no-pager

# 5. 查看内核日志
sudo dmesg | tail -30

🐛 排错练习(30 分钟)

场景 1:Pod 日志为空

1
2
3
4
5
6
7
# 可能原因:
# 1. 应用没有输出到 stdout/stderr(写到了文件)
kubectl exec <pod> -- ls /var/log/app/

# 2. 日志被轮转删除了
# 3. 应用还没开始输出
kubectl logs <pod> -f

场景 2:日志过多导致磁盘满

1
2
3
4
5
6
7
8
9
# 检查节点磁盘
df -h

# 检查容器日志大小
du -sh /var/log/containers/* | sort -rh | head -10

# 配置 kubelet 日志轮转(/var/lib/kubelet/config.yaml)
# containerLogMaxSize: "10Mi"
# containerLogMaxFiles: 5

🏆 赛题模拟(40 分钟)

⚠️ 严格限时 35 分钟

题目:日志采集与排查

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. 部署一个会持续产生日志的应用:
- Deployment log-gen(3 副本,busybox:1.36)
- 每 2 秒输出一条带时间戳的日志
- 日志格式:[LEVEL][TIMESTAMP] message

2. 日志操作:
a. 查看某个 Pod 最后 20 条日志
b. 实时跟踪所有 log-gen Pod 的日志(用 stern 或 kubectl logs -f)
c. 查看最近 3 分钟的日志
d. 模拟 Pod 崩溃,用 --previous 查看崩溃前日志

3. 部署 Fluent Bit(DaemonSet 方式):
- 输出到 stdout(便于验证)
- 在 Fluent Bit 日志中确认采集到了 log-gen 的日志

4. 排查:
- 某个 Pod 日志为空的原因(模拟:应用写日志到文件而非 stdout)
- 给出解决方案

【评分标准】
- log-gen 部署正确(15 分)
- kubectl logs 操作全对(25 分)
- Fluent Bit 部署 + 验证(30 分)
- 排查分析(30 分)

📋 命令速查

命令 功能 注解
kubectl logs <pod> -f 实时跟踪 Pod 日志 等于 tail -f
kubectl logs <pod> --tail=100 最后 100 行日志 避免刷屏
kubectl logs <pod> --since=10m 最近 10 分钟日志 时间范围过滤
kubectl logs <pod> --timestamps 带时间戳的日志 确定日志时间线
kubectl logs <pod> -c <container> 指定容器日志 多容器 Pod 必须用 -c
kubectl logs <pod> --all-containers=true 所有容器日志 一次性查看 Pod 所有容器
kubectl logs <pod> --previous 查看上一次崩溃的日志 容器重启后的历史日志
kubectl logs -l app=<name> --tail=20 按标签批量查看日志 -l 按标签选择器筛选
kubectl logs -l app=<name> --all-containers=true --since=5m 批量日志 + 时间过滤 组合选项精确定位
kubectl stern "app-*" -n <ns> 多 Pod 日志流(stern 工具) 比 kubectl logs -l 更好用的实时多 Pod 日志,需安装 stern
journalctl -u kubelet -f 实时查看 kubelet 节点日志 Pod 启停失败根因在 kubelet
journalctl -u containerd -f 实时查看 containerd 日志 容器运行时层面排错
crictl logs <container-id> 容器日志(CRI 层) kubectl logs 不可用时的备选
kubectl -n logging logs -l app=fluentd --tail=50 查看 Fluentd 日志 日志收集管道故障排查
kubectl -n logging logs -l app=elasticsearch --tail=50 查看 Elasticsearch 日志 ES 集群健康状态检查

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:日志架构 https://kubernetes.io/docs/concepts/cluster-administration/logging/
Kubernetes 官方:kubectl logs https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#logs
stern 多 Pod 日志工具 https://github.com/stern/stern
Fluentd Kubernetes 集成 https://docs.fluentd.org/container-deployment/kubernetes
Elasticsearch 官方文档 https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
EFK Stack 部署指南 https://github.com/fluent/fluentd-kubernetes-daemonset (Fluentd DaemonSet 官方示例,原 kubernetes/cluster/addons 已在 v1.24+ 移除)

📘 Day 22:Prometheus 监控体系

🎯 今日目标

  • 用 Helm 部署 kube-prometheus-stack
  • 理解 Prometheus 数据采集链路
  • 查看集群核心指标(CPU/Memory/Network)
  • 自定义告警规则

🧠 理论精讲(30 分钟)

Prometheus Stack 架构

1
2
3
4
5
6
7
8
9
┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│ Prometheus │←──│ ServiceMon. │ │ Grafana │
│ (采集+存储) │ │ (动态目标) │ │ (可视化) │
└──────┬───────┘ └──────────────┘ └──────────────┘

├──→ AlertManager(告警路由)

└──→ node_exporter(节点指标)
kube-state-metrics(K8s 对象指标)

核心指标速查

指标 含义
container_cpu_usage_seconds_total CPU 累计使用
container_memory_working_set_bytes 内存使用量
kube_pod_status_phase Pod 状态
kube_deployment_status_replicas_ready Deploy 就绪副本
node_filesystem_avail_bytes 节点磁盘可用

🔧 动手实操(120 分钟)

练习 22.1:安装 kube-prometheus-stack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 添加 Helm 仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# 2. 安装(使用 NodePort 暴露 Grafana)
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set grafana.service.type=NodePort \
--set grafana.service.nodePort=30300 \
--set prometheus.service.type=NodePort \
--set prometheus.service.nodePort=30900 \
--set alertmanager.service.type=NodePort \
--set alertmanager.service.nodePort=30903

# 3. 等待所有 Pod 就绪
kubectl get pods -n monitoring -w
# prometheus-xxx, grafana-xxx, alertmanager-xxx, operator-xxx, node-exporter-xxx, kube-state-metrics-xxx

# 4. 查看 Service
kubectl get svc -n monitoring

练习 22.2:访问 Prometheus 和 Grafana

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 获取 Grafana 登录密码
kubectl get secret -n monitoring monitoring-grafana \
-o jsonpath='{.data.admin-password}' | base64 -d
echo

# 2. 访问 Grafana(NodePort 30300)
echo "Grafana: http://<任意节点IP>:30300"
echo "User: admin"
echo "Password: <上面获取的密码>"

# 3. 访问 Prometheus(NodePort 30900)
echo "Prometheus: http://<任意节点IP>:30900"

# 4. 在 Prometheus 中查询一些指标:
# - up(所有目标状态)
# - kube_node_info(节点信息)
# - container_memory_usage_bytes(容器内存)

练习 22.3:ServiceMonitor 示例

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
# 1. 部署一个带 metrics 的应用
kubectl create ns app-metrics

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: metrics-app
namespace: app-metrics
labels:
app: metrics-app
spec:
replicas: 2
selector:
matchLabels:
app: metrics-app
template:
metadata:
labels:
app: metrics-app
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9113"
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
- name: exporter
image: nginx/nginx-prometheus-exporter:0.11
args:
- -nginx.scrape-uri=http://localhost/nginx_status
ports:
- containerPort: 9113
name: metrics
EOF

kubectl expose deploy metrics-app -n app-metrics --port=9113 --name=metrics-app-svc

# 2. 创建 ServiceMonitor
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: metrics-app-monitor
namespace: monitoring
spec:
selector:
matchLabels:
app: metrics-app
namespaceSelector:
matchNames:
- app-metrics
endpoints:
- port: metrics
interval: 30s
EOF

# 3. 在 Prometheus Targets 中验证新目标已出现
kubectl port-forward -n monitoring svc/monitoring-prometheus 9090:9090 &
# 浏览器打开 http://localhost:9090/targets

练习 22.4:自定义告警规则

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
# 创建 PrometheusRule
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: custom-alerts
namespace: monitoring
spec:
groups:
- name: pod-alerts
rules:
- alert: HighPodRestarts
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "Pod {{ \$labels.pod }} has high restart rate"
description: "Pod {{ \$labels.pod }} in {{ \$labels.namespace }} restarted {{ \$value }} times in 15min"

- alert: PodCrashLooping
expr: kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"} > 0
for: 2m
labels:
severity: critical
annotations:
summary: "Pod {{ \$labels.pod }} is crash looping"
EOF

# 验证规则
kubectl get PrometheusRule -n monitoring
kubectl describe PrometheusRule custom-alerts -n monitoring

🐛 排错练习(30 分钟)

场景:Prometheus 无法采集指标

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 检查 ServiceMonitor 是否创建
kubectl get servicemonitor -A

# 2. 检查 Prometheus 配置是否已加载
kubectl port-forward -n monitoring svc/monitoring-prometheus 9090:9090
# 访问 http://localhost:9090/config 查看 scrape_configs

# 3. 检查 Target 状态
# http://localhost:9090/targets

# 4. 标签是否匹配
kubectl get servicemonitor <name> -o yaml | grep -A10 selector
kubectl get svc <name> -o yaml | grep -A5 labels

🏆 赛题模拟(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
【操作要求】

1. 使用 Helm 部署 kube-prometheus-stack 到 monitoring 命名空间
- Grafana NodePort 30300
- Prometheus NodePort 30900

2. 部署示例应用:
- Deployment demo-app(nginx:alpine,2 副本)
- 暴露 80 和 metrics 端口

3. 配置 ServiceMonitor 采集 demo-app 的指标

4. 自定义 PrometheusRule:
- 规则 1:Pod 重启次数 > 3(15分钟内)
- 规则 2:Deployment 副本不达期望数超过 5 分钟

5. 在 Grafana 中:
- 导入 Node Exporter Full 仪表盘(ID: 1860)
- 查看集群 CPU/内存/磁盘使用情况
- 截图保存

6. 验证:
- Prometheus Targets 中包含 demo-app
- 自定义告警规则生效

【评分标准】
- Prometheus Stack 部署成功(25 分)
- ServiceMonitor 正确配置(20 分)
- PrometheusRule 正确(20 分)
- Grafana 仪表盘可用(20 分)
- 整体验证(15 分)

📋 命令速查

命令 功能 注解
kubectl get --raw /metrics 查看 apiserver 指标 原生 Prometheus 格式,kube-state-metrics 的补充
kubectl top nodes 查看节点实时资源用量 依赖 metrics-server
kubectl top pods -A --sort-by=cpu 按 CPU 排序 Pod 用量 --sort-by=memory 可改为内存排序
kubectl port-forward -n monitoring svc/prometheus-server 9090:80 本地访问 Prometheus UI 无 Ingress 时的快捷方式
kubectl port-forward -n monitoring svc/grafana 3000:80 本地访问 Grafana 默认账密 admin/admin
kubectl -n monitoring logs -l app=prometheus --tail=50 查看 Prometheus 日志 Prometheus 启动失败时首要排查
kubectl -n monitoring exec -it prometheus-<pod> -- promtool query instant http://localhost:9090 'up' Prometheus CLI 查询 promtool 是 Prometheus 自带的调试工具
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts 添加 Prometheus Helm 仓库 kube-prometheus-stack 包含 Prometheus+Grafana+AlertManager+NodeExporter
helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring --create-namespace 一键安装监控全家桶 Helm Chart 安装是最快捷的方式
kubectl get servicemonitor -A 列出 ServiceMonitor Prometheus Operator CRD,定义采集目标
kubectl get prometheusrules -A 列出告警规则 Prometheus Operator CRD
kubectl get alertmanager -A 列出 AlertManager 实例 Prometheus Operator CRD
kubectl -n kube-system logs -l k8s-app=metrics-server --tail=20 查看 metrics-server 日志 kubectl top 不可用时的排错入口

📚 参考来源

来源 链接 / 说明
Prometheus 官方文档 https://prometheus.io/docs/
Prometheus Operator 文档 https://prometheus-operator.dev/
kube-prometheus-stack Helm Chart https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack
Grafana 官方文档 https://grafana.com/docs/
Kubernetes 官方:监控 https://kubernetes.io/docs/tasks/debug/debug-cluster/resource-metrics-pipeline/
PromQL 教程 https://prometheus.io/docs/prometheus/latest/querying/basics/

📘 Day 20:ServiceAccount、镜像安全与 Pod Security

🎯 今日目标

  • 理解 Pod 默认挂载 SA Token 的含义
  • 能用 imagePullSecrets 拉取私有镜像
  • 能用 SecurityContext 控制容器权限
  • 理解 privileged/restricted/baseline 三个级别

🧠 理论精讲(30 分钟)

ServiceAccount 自动挂载

1
2
3
4
5
6
7
8
# 每个 Pod 默认会自动挂载 SA Token:
# /var/run/secrets/kubernetes.io/serviceaccount/token
# /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# /var/run/secrets/kubernetes.io/serviceaccount/namespace

# 可通过以下方式禁用:
spec:
automountServiceAccountToken: false

SecurityContext 可控制的内容

配置 说明
runAsUser / runAsGroup 指定容器运行用户
runAsNonRoot 强制非 root 运行
privileged 特权模式(尽量不用)
allowPrivilegeEscalation 是否允许提权
readOnlyRootFilesystem 根文件系统只读
capabilities Linux Capabilities 管理

Pod Security Standards(PSS)

级别 说明 适用场景
Privileged 无限制 系统组件
Baseline 禁止已知风险(hostPath、特权) 普通应用
Restricted 严格限制(非 root、只读根文件系统) 安全要求高

🔧 动手实操(120 分钟)

练习 20.1:ServiceAccount 与 Token 管理

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
# 1. 查看 Pod 默认挂载的 SA Token
kubectl run sa-test --image=busybox:1.36 --restart=Never -- sleep 3600

kubectl exec sa-test -- ls /var/run/secrets/kubernetes.io/serviceaccount/
# ca.crt namespace token

kubectl exec sa-test -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | head -3

# 2. 禁用自动挂载
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: no-sa-mount
spec:
automountServiceAccountToken: false
containers:
- name: app
image: busybox:1.36
command: ["sleep", "3600"]
EOF

kubectl exec no-sa-mount -- ls /var/run/secrets/kubernetes.io/serviceaccount/ 2>&1
# ls: /var/run/secrets/kubernetes.io/serviceaccount/: No such file or directory

# 3. 创建自定义 SA
kubectl create sa custom-sa
kubectl run custom-sa-pod --image=busybox:1.36 --restart=Never --overrides='
{
"spec": {
"serviceAccountName": "custom-sa"
}
}' -- sleep 3600

kubectl get pod custom-sa-pod -o jsonpath='{.spec.serviceAccountName}'
# custom-sa

# 清理
kubectl delete pod sa-test no-sa-mount custom-sa-pod
kubectl delete sa custom-sa

练习 20.2:SecurityContext 安全上下文

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
# 1. 非 root 用户运行
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: non-root-pod
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
containers:
- name: app
image: nginx:alpine
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
EOF

# 验证用户
kubectl exec non-root-pod -- id
# uid=1000 gid=3000

# 2. 设置 ReadOnlyRootFilesystem
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: readonly-pod
spec:
containers:
- name: app
image: nginx:alpine
securityContext:
readOnlyRootFilesystem: true
volumeMounts:
- name: nginx-run
mountPath: /var/run
- name: nginx-cache
mountPath: /var/cache/nginx
volumes:
- name: nginx-run
emptyDir: {}
- name: nginx-cache
emptyDir: {}
EOF

kubectl exec readonly-pod -- touch /test-file
# touch: /test-file: Read-only file system

# 3. Capabilities 管理
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: caps-pod
spec:
containers:
- name: app
image: busybox:1.36
command: ["sleep", "3600"]
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
- CHOWN
EOF

# 清理
kubectl delete pod non-root-pod readonly-pod caps-pod

练习 20.3:私有镜像仓库拉取

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
# 1. 创建 Docker Registry Secret
kubectl create secret docker-registry private-registry \
--docker-server=registry.cn-hangzhou.aliyuncs.com \
--docker-username=your-username \
--docker-password=your-password \
--docker-email=your@email.com

# 2. 方式一:在 Pod 中指定
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: private-image-pod
spec:
imagePullSecrets:
- name: private-registry
containers:
- name: app
image: registry.cn-hangzhou.aliyuncs.com/your-ns/your-image:tag
EOF

# 3. 方式二:绑定到 ServiceAccount(推荐)
kubectl patch serviceaccount default -p '{"imagePullSecrets":[{"name":"private-registry"}]}'

# 验证
kubectl get sa default -o yaml | grep -A3 imagePullSecrets

# 4. 清理
kubectl delete pod private-image-pod
kubectl delete secret private-registry
# 恢复默认 SA
kubectl patch serviceaccount default --type=json \
-p='[{"op":"remove","path":"/imagePullSecrets"}]'

🐛 排错练习(30 分钟)

场景 1:镜像拉取失败(ErrImagePull / ImagePullBackOff)

1
2
3
4
5
6
7
8
9
10
11
12
# 排查步骤
# 1. 查看错误详情
kubectl describe pod <pod-name> | grep -A10 Events

# 2. 是否是私有镜像?
# → 检查是否配置了 imagePullSecrets

# 3. Secret 是否正确?
kubectl get secret <secret-name> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | python3 -m json.tool

# 4. 镜像名是否正确?
# registry/namespace/image:tag

场景 2:Pod 启动后立即退出(Permission Denied)

1
2
3
4
5
6
# 可能是因为 SecurityContext 限制了权限
kubectl logs <pod-name>
# Permission denied

# 检查 SecurityContext
kubectl get pod <pod-name> -o yaml | grep -A15 securityContext

🏆 赛题模拟(40 分钟)

⚠️ 严格限时 35 分钟

题目: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
【操作要求】

1. 创建命名空间 secure-workspace

2. 创建 ServiceAccount secure-runner:
- 禁用默认 Token 自动挂载

3. 创建私有仓库 Secret(模拟):
- Server: registry.internal.com
- Username: ci-bot
- Password: ci-token-123
- 将此 Secret 绑定到 secure-runner SA

4. 创建 Deployment secure-app(2副本,nginx:alpine):
- 使用 secure-runner SA
- SecurityContext:
* runAsUser: 1001
* runAsNonRoot: true
* allowPrivilegeEscalation: false
* readOnlyRootFilesystem: false(nginx 需要写临时文件)
* drop ALL capabilities
- 定义 resources.requests 和 limits
- livenessProbe + readinessProbe

5. 验证:
- SA 没有自动挂载 Token
- 容器以 uid 1001 运行
- 容器不能以 root 运行

【评分标准】
- SA 配置正确(15 分)
- 私有仓库 Secret + 绑定(20 分)
- SecurityContext 配置(35 分)
- 探针配置(15 分)
- 安全验证(15 分)

📋 命令速查

命令 功能 注解
kubectl get sa -A 列出所有 ServiceAccount 每个 NS 有默认 default SA
kubectl describe sa <name> -n <ns> SA 详情 查看关联的 Secrets 和镜像拉取密钥
kubectl create sa <name> -n <ns> 创建 ServiceAccount SA 创建后需绑定 Role 才有权限
kubectl create token <sa> -n <ns> 生成 SA 临时 Token(1.24+) 有时效性,用于外部访问 apiserver
kubectl create token <sa> -n <ns> --duration=1h 指定 Token 有效期 默认 1h,最长 48h
kubectl get pod <pod> -o jsonpath='{.spec.serviceAccountName}' 查看 Pod 使用的 SA 默认使用 default SA
kubectl get podsecurity 查看 Pod Security Admission 配置 1.25+ 替代 PSP,三个等级:privileged/baseline/restricted
kubectl label ns <ns> pod-security.kubernetes.io/enforce=restricted 设置命名空间安全等级 restricted 最严格,禁止特权容器、hostPath 等
kubectl label ns <ns> pod-security.kubernetes.io/warn=baseline 设置安全警告等级 仅警告不拒绝
kubectl get secret | grep <sa>-docker 查找镜像拉取密钥 私有仓库认证
kubectl create secret docker-registry <name> --docker-server=<url> --docker-username=<user> --docker-password=<pass> 创建镜像拉取密钥 在 Pod spec 中通过 imagePullSecrets 引用
kubectl patch sa default -n <ns> -p '{"imagePullSecrets":[{"name":"<secret>"}]}' 给默认 SA 添加镜像拉取密钥 该 NS 所有使用 default SA 的 Pod 自动携带
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}' 列出所有 Pod 的镜像 审计镜像版本
kubectl set image deploy/<name> <container>=<image>@sha256:<digest> 使用镜像摘要更新 比 tag 更安全,防止标签篡改

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:ServiceAccount https://kubernetes.io/docs/concepts/security/service-accounts/
Kubernetes 官方:Pod Security Admission https://kubernetes.io/docs/concepts/security/pod-security-admission/
Kubernetes 官方:Pod 安全标准 https://kubernetes.io/docs/concepts/security/pod-security-standards/
Kubernetes 官方:镜像拉取密钥 https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
Kubernetes 官方:镜像安全最佳实践 https://kubernetes.io/docs/concepts/security/

📘 Day 21:安全综合实战

🎯 今日目标

  • 综合 RBAC + SecurityContext + NetworkPolicy 构建安全体系
  • 完成一次完整的安全审计
  • 排查安全相关故障

🧠 理论精讲(10 分钟)

K8s 安全 4C 模型

1
2
3
4
5
6
Cloud → Cluster → Container → Code
↓ ↓ ↓ ↓
云安全 集群安全 容器安全 应用安全
(防火墙) (RBAC) (Seccomp) (输入校验)
(NetworkPolicy)
(etcd 加密)

🔧 动手实操(150 分钟)

练习 21.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
kubectl create ns secure-stack

# === 1. ServiceAccount ===
kubectl create sa app-runner -n secure-stack

# === 2. RBAC(最小权限) ===
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-role
namespace: secure-stack
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
resourceNames: ["app-config"] # 只能访问特定 ConfigMap
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-runner-binding
namespace: secure-stack
subjects:
- kind: ServiceAccount
name: app-runner
namespace: secure-stack
roleRef:
kind: Role
name: app-role
apiGroup: rbac.authorization.k8s.io
EOF

# === 3. Deploy + SecurityContext ===
kubectl create configmap app-config -n secure-stack \
--from-literal=ENV=production

cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-web
namespace: secure-stack
spec:
replicas: 2
selector:
matchLabels:
app: secure-web
template:
metadata:
labels:
app: secure-web
spec:
serviceAccountName: app-runner
automountServiceAccountToken: false
securityContext:
runAsUser: 1001
runAsNonRoot: true
fsGroup: 1001
containers:
- name: web
image: nginx:alpine
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: false
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /
port: 80
readinessProbe:
httpGet:
path: /
port: 80
EOF

kubectl expose deploy secure-web -n secure-stack --port=80

# === 4. NetworkPolicy ===
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: secure-web-policy
namespace: secure-stack
spec:
podSelector:
matchLabels:
app: secure-web
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- protocol: TCP
port: 80
egress:
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
EOF

# 验证部署
kubectl get all -n secure-stack
kubectl get networkpolicy -n secure-stack

练习 21.2:安全审计检查清单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1. 检查特权容器
kubectl get pods --all-namespaces -o json | \
jq '.items[] | select(.spec.containers[].securityContext.privileged==true) | .metadata.name'

# 2. 检查以 root 运行的容器
kubectl get pods --all-namespaces -o json | \
jq '[.items[] | select(.spec.containers[].securityContext.runAsNonRoot!=true)] | length'

# 3. 检查未设资源限制的 Pod
kubectl get pods --all-namespaces -o json | \
jq '.items[] | select(.spec.containers[].resources.requests==null) | "\(.metadata.namespace)/\(.metadata.name)"'

# 4. 检查过于宽泛的 RBAC 权限
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.subjects[]?.kind=="User" and .subjects[]?.name=="system:anonymous")'

# 5. 检查 Secret 是否明文(检查 etcd 加密状态)
kubectl get --raw=/api/v1/secrets | jq '.items[].type' | sort | uniq -c

# 6. 检查是否有 Pod 挂载了 hostPath
kubectl get pods --all-namespaces -o json | \
jq '.items[] | select(.spec.volumes[]?.hostPath!=null) | "\(.metadata.namespace)/\(.metadata.name)"'

🏆 赛题模拟(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
【初始环境】:已有的 Deployment app-insecure 存在安全问题

【操作要求】

1. 安全审计(找出以下问题):
- 容器以 root 运行
- 没有资源限制
- 使用 default SA(权限过大)
- 没有 NetworkPolicy
- 挂载了 hostPath

2. 安全加固:
a. 创建专用 SA app-secure,禁用 auto-mount
b. 创建最小权限 Role(只读自己的 ConfigMap)
c. SecurityContext:
- runAsUser 1001, runAsNonRoot
- drop ALL capabilities
- readOnlyRootFilesystem(需补充 emptyDir 给 tmp)
d. 添加资源限制
e. 移除 hostPath,改用 emptyDir 或 PVC
f. 创建 NetworkPolicy:
- Ingress:只允许同命名空间 + Ingress Controller
- Egress:只允许 DNS + 同命名空间

3. 验证:
- kubectl auth can-i 验证 SA 权限
- kubectl exec 验证非 root 运行
- 验证 NetworkPolicy 隔离

【评分标准】
- 安全审计发现所有问题(20 分)
- SA + RBAC 配置(20 分)
- SecurityContext 加固(25 分)
- NetworkPolicy 配置(20 分)
- hostPath 移除(15 分)

📋 命令速查

命令 功能 注解
kubectl auth can-i --list --as=system:serviceaccount:<ns>:<sa> 列出 SA 的完整权限 RBAC 问题排查第一命令
kubectl get role,rolebinding,clusterrole,clusterrolebinding -A RBAC 全貌 安全审计时快速扫描所有权限配置
kubectl get sa -A 所有命名空间的 SA 检查冗余 SA
kubectl get pods -o json | jq '.items[] | {name:.metadata.name, sa:.spec.serviceAccountName, securityContext:.spec.securityContext, containerSecurity:.spec.containers[].securityContext}' 审计 Pod 安全上下文 jq 一次性提取安全相关字段
kubectl get pods -o json | jq '[.items[] | select(.spec.containers[].securityContext.privileged==true)]' 查找特权容器 安全审计:特权容器可以逃逸
kubectl get pods -o json | jq '[.items[] | select(.spec.hostNetwork==true)]' 查找使用 hostNetwork 的 Pod 可以监听节点网络接口,高风险
kubectl get pods -o json | jq '[.items[] | select(.spec.volumes[]?.hostPath)]' 查找挂载 hostPath 的 Pod 可以访问节点文件系统
kubectl -n kube-system get cm kubeadm-config -o jsonpath='{.data.ClusterConfiguration}' | grep -A 5 "apiServer" 查看 apiserver 启动参数 确认准入控制器和加密配置
kubectl get --raw /apis/authorization.k8s.io/v1/selfsubjectaccessreviews 自检 API 访问 编程式权限检查的 API 版

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:安全总览 https://kubernetes.io/docs/concepts/security/
Kubernetes 官方:安全最佳实践 https://kubernetes.io/docs/concepts/security/security-checklist/
Kubernetes 官方:RBAC 最佳实践 https://kubernetes.io/docs/concepts/security/rbac-good-practices/
NSA/CISA Kubernetes 加固指南 https://media.defense.gov/2022/Aug/29/2003066362/-1/-1/0/CTR_KUBERNETES_HARDENING_GUIDANCE_1.2_20220829.PDF
CIS Kubernetes Benchmark https://www.cisecurity.org/benchmark/kubernetes

📘 Day 19:RBAC 权限控制

🎯 今日目标

  • 理解 RBAC 的四个核心概念
  • 能创建 Role 并绑定到用户/ServiceAccount
  • 会用 kubectl auth can-i 验证权限
  • 能排查 Permission Denied 错误

🧠 理论精讲(30 分钟)

RBAC 四要素

1
2
3
4
5
Subject(谁)────→ RoleBinding ────→ Role(能做什么)
│ │
├── User ├── apiGroups
├── Group ├── resources
└── ServiceAccount └── verbs
概念 作用域 说明
Role 命名空间 定义在某 NS 下的权限
ClusterRole 集群 定义集群级别权限
RoleBinding 命名空间 将 Role 绑定到主体
ClusterRoleBinding 集群 将 ClusterRole 绑定到主体

常见 verbs

verb 含义 对应 kubectl
get 查看单个资源 kubectl get pod xxx
list 列出资源 kubectl get pods
watch 监听资源变化 kubectl get pods -w
create 创建 kubectl create/apply
update 修改 kubectl edit/patch
delete 删除 kubectl delete

🔧 动手实操(120 分钟)

练习 19.1:创建 ServiceAccount + Role + RoleBinding

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
# 1. 创建命名空间
kubectl create ns rbac-demo

# 2. 创建 ServiceAccount
kubectl create sa developer -n rbac-demo

# 3. 创建 Role(只读 Pod)
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: rbac-demo
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
EOF

# 4. 创建 RoleBinding
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-pod-reader
namespace: rbac-demo
subjects:
- kind: ServiceAccount
name: developer
namespace: rbac-demo
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
EOF

# 5. 验证权限
kubectl auth can-i get pods -n rbac-demo --as=system:serviceaccount:rbac-demo:developer
# yes

kubectl auth can-i create pods -n rbac-demo --as=system:serviceaccount:rbac-demo:developer
# no

kubectl auth can-i delete pods -n rbac-demo --as=system:serviceaccount:rbac-demo:developer
# no

# 6. 查看完整权限列表
kubectl auth can-i --list -n rbac-demo --as=system:serviceaccount:rbac-demo:developer

练习 19.2:ClusterRole + ClusterRoleBinding

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
# 1. 创建 ClusterRole(集群级别只读)
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-viewer
rules:
- apiGroups: [""]
resources: ["nodes", "namespaces", "pods", "services"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets"]
verbs: ["get", "list", "watch"]
EOF

# 2. 创建 ServiceAccount
kubectl create sa auditor -n rbac-demo

# 3. ClusterRoleBinding
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: auditor-viewer
subjects:
- kind: ServiceAccount
name: auditor
namespace: rbac-demo
roleRef:
kind: ClusterRole
name: cluster-viewer
apiGroup: rbac.authorization.k8s.io
EOF

# 4. 验证集群级别权限
kubectl auth can-i get nodes --as=system:serviceaccount:rbac-demo:auditor
# yes

kubectl auth can-i get deploy --as=system:serviceaccount:rbac-demo:auditor
# yes

kubectl auth can-i delete nodes --as=system:serviceaccount:rbac-demo:auditor
# no

练习 19.3:创建受限 kubeconfig

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
# 1. 获取 SA 的 Token
kubectl create token developer -n rbac-demo
# 复制输出的 token

# 或者创建长期有效的 token(K8s 1.24+)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: developer-token
namespace: rbac-demo
annotations:
kubernetes.io/service-account.name: developer
type: kubernetes.io/service-account-token
EOF

# 获取 token
TOKEN=$(kubectl get secret developer-token -n rbac-demo -o jsonpath='{.data.token}' | base64 -d)

# 2. 获取集群 CA 证书
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > /tmp/ca.crt

# 3. 构建 kubeconfig
kubectl config set-cluster dev-cluster \
--server=$(kubectl config view --raw -o jsonpath='{.clusters[0].cluster.server}') \
--certificate-authority=/tmp/ca.crt \
--embed-certs=true \
--kubeconfig=/tmp/dev-kubeconfig

kubectl config set-credentials developer \
--token=$TOKEN \
--kubeconfig=/tmp/dev-kubeconfig

kubectl config set-context dev-context \
--cluster=dev-cluster \
--namespace=rbac-demo \
--user=developer \
--kubeconfig=/tmp/dev-kubeconfig

kubectl config use-context dev-context --kubeconfig=/tmp/dev-kubeconfig

# 4. 使用受限配置测试
kubectl get pods -n rbac-demo --kubeconfig=/tmp/dev-kubeconfig
# 正常返回

kubectl create deploy test --image=nginx:alpine -n rbac-demo --kubeconfig=/tmp/dev-kubeconfig
# Error: forbidden

练习 19.4:实战 RBAC 排错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. 排查 "cannot get resource" 错误
# 错误信息:Error from server (Forbidden): pods is forbidden

# 排查步骤
kubectl auth can-i get pods --as=<user>
# 如果是 no → 检查 Role/RoleBinding
kubectl get rolebinding -A | grep <user>
kubectl describe rolebinding <name> -n <ns>

# 2. 查看某个 SA 拥有的所有权限
kubectl auth can-i --list --as=system:serviceaccount:rbac-demo:developer -n rbac-demo

# 3. 检查是否有 ClusterRoleBinding(影响更大)
kubectl get clusterrolebinding -o wide | grep <user>

🐛 排错练习(30 分钟)

常见 RBAC 错误排查

1
2
3
4
5
6
7
8
9
# 错误 1: "User system:serviceaccount:default:default cannot create resource"
# → 默认 SA 没有写权限,需要创建专用的 SA + RoleBinding

# 错误 2: "cannot list resource in API group"
# → Role 中 apiGroups 配置错误,检查资源属于哪个 API 组
kubectl api-resources | grep <resource>

# 错误 3: "cannot get resource at cluster scope"
# → 命名空间级别的 Role 不能访问集群级别资源,需用 ClusterRole

🏆 赛题模拟(40 分钟)

⚠️ 严格限时 35 分钟

题目:RBAC 权限体系设计

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. 创建命名空间 project-alpha

2. 创建 3 个 ServiceAccount:
- sa-admin(管理员)
- sa-developer(开发者)
- sa-viewer(只读用户)

3. 创建 3 个 Role / ClusterRole:
a. Role admin-role(namespace: project-alpha):
- 对 pods/deployments/services/configmaps/secrets 有全部权限
b. Role developer-role(namespace: project-alpha):
- 对 pods/deployments/services/configmaps 有 get/list/watch/create/update
- 对 pods/log 有 get/list
- 对 secrets 无权限
c. ClusterRole viewer-role:
- 对所有命名空间的 pods/deployments/services 有 get/list/watch

4. 绑定:
- sa-admin → admin-role(RoleBinding)
- sa-developer → developer-role(RoleBinding)
- sa-viewer → viewer-role(ClusterRoleBinding)

5. 验证:
- sa-admin 能创建/删除 Pod
- sa-developer 能创建 Pod 但不能查看 Secret
- sa-viewer 能查看所有命名空间的 Pod
- sa-viewer 无法创建 Pod

【评分标准】
- SA 创建(10 分)
- Role/ClusterRole 权限粒度正确(40 分)
- RoleBinding/ClusterRoleBinding 正确(20 分)
- 权限验证(30 分)

📋 命令速查

命令 功能 注解
kubectl auth can-i create pods 检查当前用户权限 快速验证 RBAC 配置是否正确
kubectl auth can-i create pods --as=system:serviceaccount:<ns>:<sa> 检查某 SA 权限 调试 ServiceAccount 权限问题
kubectl auth can-i --list 列出当前用户所有权限 输出完整的资源-动词矩阵
kubectl auth can-i '*' '*' 检查是否集群管理员 返回 yes 说明拥有全部权限
kubectl get role -A 列出所有 Role 命名空间级权限
kubectl get rolebinding -A 列出所有 RoleBinding 查看 Role 与用户/SA 的绑定关系
kubectl get clusterrole 列出 ClusterRole 集群级权限(节点、PV、StorageClass 等)
kubectl get clusterrolebinding 列出 ClusterRoleBinding 集群级绑定关系
kubectl describe role <name> -n <ns> Role 详情 查看具体允许的资源和动词
kubectl describe clusterrole <name> ClusterRole 详情 系统自带 cluster-admin/edit/view 的权限范围
kubectl create role <name> --verb=get,list,watch --resource=pods -n <ns> 快速创建 Role --verb--resource 即可,无需手写 YAML
kubectl create rolebinding <name> --role=<role> --user=<user> -n <ns> 绑定 Role 到用户 给真实用户授权
kubectl create rolebinding <name> --role=<role> --serviceaccount=<ns>:<sa> -n <ns> 绑定 Role 到 SA 给 ServiceAccount 授权
kubectl create clusterrole <name> --verb=get,list --resource=nodes 创建 ClusterRole 集群级资源必须用 ClusterRole
kubectl create clusterrolebinding <name> --clusterrole=<role> --serviceaccount=<ns>:<sa> 绑定 ClusterRole 到 SA 跨命名空间的 SA 绑定集群级权限
kubectl get sa -A 列出所有 ServiceAccount 每个 NS 有默认 default SA
kubectl get secrets | grep <sa>-token 查找 SA 的 Token Secret 1.24+ 不再自动创建,需手动 kubectl create token <sa>
kubectl create token <sa> -n <ns> 创建 SA 临时 Token 1.24+ 推荐方式,有时效性

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:RBAC https://kubernetes.io/docs/reference/access-authn-authz/rbac/
Kubernetes 官方:鉴权概述 https://kubernetes.io/docs/reference/access-authn-authz/authorization/
Kubernetes 官方:使用 RBAC 授权 https://kubernetes.io/docs/reference/access-authn-authz/rbac/#command-line-utilities
Kubernetes 官方:ServiceAccount https://kubernetes.io/docs/concepts/security/service-accounts/
Kubernetes 官方:kubectl auth can-i https://kubernetes.io/docs/reference/access-authn-authz/authorization/#checking-api-access

📘 Day 18:调度综合实战

🎯 今日目标

  • 综合使用调度策略实现多层级部署
  • 设计命名空间级别资源隔离
  • 故障自愈 + 自动伸缩全链路验证

🧠 理论精讲(10 分钟)

多租户资源隔离架构

1
2
3
4
5
6
7
8
9
10
11
12
13
┌────────────────────────────────────────────┐
│ K8s Cluster │
│ │
│ ┌── ns: team-a ──┐ ┌── ns: team-b ──┐ │
│ │ ResourceQuota │ │ ResourceQuota │ │
│ │ CPU: 4, Mem: 8G │ │ CPU: 2, Mem: 4G │ │
│ │ │ │ │ │
│ │ NodeSelector: │ │ NodeSelector: │ │
│ │ node-group=a │ │ node-group=b │ │
│ │ │ │ │ │
│ │ HPA + PDB │ │ HPA + PDB │ │
│ └─────────────────┘ └─────────────────┘ │
└────────────────────────────────────────────┘

🔧 动手实操(150 分钟)

练习 18.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
# 1. 准备节点分组
kubectl label node k8s-node1 node-group=team-a
kubectl label node k8s-node2 node-group=team-b

# 2. 创建租户命名空间
kubectl create ns team-a
kubectl create ns team-b

# 3. Team A 的 ResourceQuota + LimitRange
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a
spec:
hard:
requests.cpu: "3"
requests.memory: "4Gi"
pods: "15"
---
apiVersion: v1
kind: LimitRange
metadata:
name: team-a-limits
namespace: team-a
spec:
limits:
- type: Container
default:
cpu: "200m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
EOF

# 4. Team B 的 ResourceQuota
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-b-quota
namespace: team-b
spec:
hard:
requests.cpu: "2"
requests.memory: "3Gi"
pods: "10"
---
apiVersion: v1
kind: LimitRange
metadata:
name: team-b-limits
namespace: team-b
spec:
limits:
- type: Container
default:
cpu: "150m"
memory: "192Mi"
defaultRequest:
cpu: "75m"
memory: "96Mi"
EOF

# 5. Team A 部署应用到专属节点
cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-a
namespace: team-a
spec:
replicas: 3
selector:
matchLabels:
app: app-a
template:
metadata:
labels:
app: app-a
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-group
operator: In
values:
- team-a
containers:
- name: app
image: nginx:alpine
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
EOF

# 6. Team B 部署
cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-b
namespace: team-b
spec:
replicas: 2
selector:
matchLabels:
app: app-b
template:
metadata:
labels:
app: app-b
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-group
operator: In
values:
- team-b
containers:
- name: app
image: httpd:alpine
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "300m"
memory: "256Mi"
EOF

# 7. 验证配额
kubectl describe quota -n team-a
kubectl describe quota -n team-b

# 8. 验证 Pod 分布
kubectl get pod -n team-a -o wide
kubectl get pod -n team-b -o wide

🏆 赛题模拟(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
【场景】公司两个团队共享 K8s 集群

【操作要求】

1. 命名空间与标签:
- ns: dev-team, prod-team
- 节点标签 tier: k8s-node1→dev, k8s-node2→prod

2. dev-team 配置:
- ResourceQuota: CPU 2 核, Memory 4Gi, Pod ≤ 10
- LimitRange: 默认 requests cpu 100m/mem 128Mi
- Deployment dev-app: 2 副本, nginx:alpine
* nodeAffinity: tier=dev
* HPA: CPU 50%, min 2, max 5

3. prod-team 配置:
- ResourceQuota: CPU 4 核, Memory 8Gi, Pod ≤ 20
- LimitRange: 默认 requests cpu 200m/mem 256Mi
- Deployment prod-api: 3 副本, httpd:alpine
* nodeAffinity: tier=prod
* podAntiAffinity: 按 hostname 分散
* HPA: CPU 70%, min 3, max 10
- Deployment prod-worker: 2 副本, busybox (sleep 3600)
* nodeAffinity: tier=prod

4. 验证:
- 两个团队配额互不干扰
- dev-app 全部在 dev 节点
- prod 所有 Pod 在 prod 节点
- prod-api 分散在不同节点
- HPA 工作正常

【评分标准】
- 命名空间和标签(10 分)
- ResourceQuota 正确(15 分)
- LimitRange 正确(10 分)
- nodeAffinity 正确(20 分)
- podAntiAffinity 正确(15 分)
- HPA 配置(20 分)
- 整体隔离验证(10 分)

📋 命令速查

命令 功能 注解
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints[*].key 自定义列查看节点污点 快速扫描所有节点的污点分布
kubectl get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,NODE-SELECTOR:.spec.nodeSelector 自定义列查看 Pod 调度策略 同时显示 Pod 所在节点和 nodeSelector
kubectl get pods -o wide --field-selector=spec.nodeName=<node> 筛选某节点上的 Pod 迁移 Pod 前确认受影响范围
kubectl get pods -o wide --field-selector=status.phase=Pending 筛选 Pending Pod 快速定位未调度的 Pod
kubectl describe pod <pod> | grep -A 5 "Node-Selectors|Tolerations|Affinity" 查看 Pod 调度要求 综合排错时快速了解 Pod 的调度偏好
kubectl patch deploy <name> -p '{"spec":{"template":{"spec":{"nodeSelector":{"key":"value"}}}}}' 给 Deployment 添加 nodeSelector 触发滚动更新将 Pod 迁移到匹配节点
kubectl patch deploy <name> -p '{"spec":{"template":{"spec":{"tolerations":[{"key":"key","operator":"Equal","value":"value","effect":"NoSchedule"}]}}}}' 给 Deployment 添加 Toleration 允许 Pod 调度到有对应污点的节点
kubectl get events --sort-by=.metadata.creationTimestamp | tail -20 最近 20 条事件 综合实战中快速了解集群正在发生什么

📚 参考来源

来源 链接 / 说明
Kubernetes 官方:调度器 https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/
Kubernetes 官方:高级调度 https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/
Kubernetes 官方:Pod 优先级与抢占 https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/
Kubernetes 官方:资源管理 https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
0%