前言
概念篇过了理论,这次动手:把一个带健康检查、资源限额、优雅升级能力的生产级 Deployment 从零部署起来。环境用 kind(本地单机 K8s)。
# 5 分钟准备实验环境
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.23.0/kind-linux-amd64
install ./kind /usr/local/bin/kind
kind create cluster --name lab
kubectl cluster-info
一、完整的生产级清单
web.yaml——每一块都是实战标配:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-web
labels:
app: demo-web
spec:
replicas: 3
revisionHistoryLimit: 5 # 保留 5 个历史版本(回滚用)
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 滚动时最多多起 1 个
maxUnavailable: 0 # 滚动时不允许少副本(零中断)
selector:
matchLabels:
app: demo-web
template:
metadata:
labels:
app: demo-web
spec:
containers:
- name: web
image: registry.cn-hangzhou.aliyuncs.com/zy-repo/demo-web:v1.0.0
ports:
- containerPort: 8080
env:
- name: APP_ENV
value: "production"
resources:
requests: # 调度依据( 保证值)
cpu: 100m # 100m = 0.1 核
memory: 128Mi
limits: # 硬顶(超内存会被 OOMKill)
cpu: 500m
memory: 256Mi
startupProbe: # 启动探针: 先等它通过, 再开始健康检查
httpGet: {path: /healthz, port: 8080}
failureThreshold: 30
periodSeconds: 2
livenessProbe: # 存活探针: 失败重启容器
httpGet: {path: /healthz, port: 8080}
periodSeconds: 10
failureThreshold: 3
readinessProbe: # 就绪探针: 失败摘除流量(不重启)
httpGet: {path: /ready, port: 8080}
periodSeconds: 5
lifecycle:
preStop: # 优雅退出: 先等流量排空
exec: {command: ["sleep", "5"]}
terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
name: demo-web
spec:
selector:
app: demo-web
ports:
- port: 80
targetPort: 8080
kubectl apply -f web.yaml
kubectl get pods -o wide
kubectl get deploy,svc
二、三个探针的分工(面试高频)
| 探针 | 失败后果 | 用来发现 |
|---|---|---|
| livenessProbe | 重启容器 | 死锁、进程假死 |
| readinessProbe | 摘除流量(不重启) | 依赖未就绪、过载降级 |
| startupProbe | 推迟上面两个的计时 | 慢启动应用(JVM 老铁都懂) |
流量路径: Service → 只发给 ready 的 Pod
自愈路径: liveness 挂 → kubelet 重启容器 → ready 才回流量
探针方式:httpGet(状态码 2xx/3xx 算过)/ exec(退出码 0 算过)/ tcpSocket(能连通算过)。
三、资源限额的学问
resources:
requests: {cpu: 100m, memory: 128Mi}
limits: {cpu: 500m, memory: 256Mi}
- requests:调度器按它找节点;节点超卖(所有 pod requests 之和 > 容量才拒绝)
- limits:CPU 超限被节流(throttle,变慢不挂);内存超限被 OOMKill(exit code 137)
- QoS 等级:requests == limits 时是
Guaranteed,资源紧张时最后被驱逐
# 观察实际用量
kubectl top pods
# 排查 OOMKill
kubectl describe pod xxx | grep -A2 "Last State"
四、发布与回滚
# 触发滚动更新(改镜像)
kubectl set image deploy/demo-web web=.../demo-web:v1.1.0
# 实时看滚动过程
kubectl rollout status deploy/demo-web
# Waiting for deployment "demo-web" rollout to finish: 2 of 3 updated...
# 零中断的秘密: maxUnavailable=0 + readinessProbe
# 新 Pod 没 ready 前, 老 Pod 一个都不删
# 查看历史与回滚
kubectl rollout history deploy/demo-web
kubectl rollout undo deploy/demo-web # 回上一个
kubectl rollout undo deploy/demo-web --to-revision=2 # 回指定版本
# 暂停/恢复(灰度改多字段时用)
kubectl rollout pause deploy/demo-web
kubectl set image ... ; kubectl set env ...
kubectl rollout resume deploy/demo-web
五、扩缩容
kubectl scale deploy/demo-web --replicas=5 # 手动
# HPA 自动扩缩容(按 CPU)
kubectl autoscale deploy/demo-web --min=3 --max=10 --cpu-percent=70
kubectl get hpa
压测验证:ab -n 100000 -c 200 http://$NODE_IP:$PORT/,看副本数随 CPU 爬升。
六、排障命令流(背下来)
# 1. Pod 卡在 Pending → 资源不够/节点选择器没匹配
kubectl describe pod xxx | tail -20 # 看 Events 段!
# 2. Pod 卡 ImagePullBackOff → 镜像名/仓库认证问题
kubectl describe pod xxx | grep -A5 Events
# 3. CrashLoopBackOff → 容器起来就崩
kubectl logs xxx --previous # 上一次崩溃的日志!
# 4. Service 不通 → 端点列表空?
kubectl get endpoints demo-web # NONE = selector/label 不匹配
kubectl exec -it xxx -- curl localhost:8080 # 容器内自测
# 5. OOM / 重启循环
kubectl get pod xxx -o jsonpath='{.status.containerStatuses[0].restartCount}'
kubectl describe pod xxx | grep -B2 -A5 "State"
# 6. 进入容器 & 看资源
kubectl exec -it xxx -- sh
kubectl top pod xxx
Events 永远是第一现场——90% 的部署问题,describe 最后那段 Events 直接给了答案。
七、常用字段速查
kubectl get all -n default # 一屏看全
kubectl get pod -o wide # 带节点/IP
kubectl get pod -w # watch 模式
kubectl explain deploy.spec.strategy # 现场查字段文档(神器)
kubectl diff -f web.yaml # apply 前看差异
kubectl delete -f web.yaml # 删除
kubectl run debug --rm -it --image=busybox -- sh # 临时调试 Pod
小结
| 需求 | 配置 |
|---|---|
| 不接坏流量 | readinessProbe |
| 假死自愈 | livenessProbe |
| 零中断发布 | maxUnavailable=0 + 探针 |
| 回滚 | rollout undo –to-revision |
| 资源 | requests 调度 / limits 封顶 / 内存超限 OOM |
| 排障 | describe 的 Events → logs –previous → endpoints |
本文是「云原生」系列第 6 篇。