Kubernetes 编排
运维视角的 Kubernetes 手册:集群怎么认识对象、故障怎么自愈、应用怎么暴露、存储配置怎么管理、出了问题按什么顺序排。容器原理与「可上生产清单」见后端·容器与部署。示例语境:kubectl 1.32 / kubeadm 1.32 集群,命令需在真实环境验证。
心智模型:声明式 + 控制器
K8s 的一切基于声明式 API:你提交「期望状态」(deployment 要 3 个副本),控制器(controller-manager 里的一个个 loop)不断把实际状态收敛到期望状态——副本挂了它重建、节点没了它把 Pod 调度走。所以运维动作大多不是「修某个进程」,而是改对象声明。
bash
kubectl get deployment,rs,pods # 一路看:期望/实际是否对齐
kubectl rollout status deploy/nginx # 滚动进行到哪
kubectl rollout undo deploy/nginx # 回滚到上一个版本核心对象地图
| 对象 | 作用 | 典型场景 |
|---|---|---|
| Pod | 最小调度单元(一组共享网络的容器) | 不直接建,交给上层工作负载 |
| Deployment | 无状态应用 + 滚动更新/回滚 | Web、API |
| StatefulSet | 有状态应用,稳定网络标识与顺序 | 数据库、消息队列 |
| DaemonSet | 每个节点保证一个 Pod | 日志采集、监控 agent |
| Job / CronJob | 一次性 / 定时任务 | 迁移、批处理 |
| Service | 稳定的服务入口与负载均衡 | 暴露 Pod 集合 |
| Ingress | 七层 HTTP(S) 路由 | 按域名/路径分流 |
| ConfigMap / Secret | 配置与敏感信息注入 | 环境变量、挂载 |
| PV / PVC / StorageClass | 持久化存储抽象 | 数据库数据盘 |
Deployment 一份完整示例
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
namespace: prod
spec:
replicas: 3
selector:
matchLabels: { app: api }
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels: { app: api }
spec:
containers:
- name: api
image: registry.example.com/team/app:git-abc123
ports: [{ containerPort: 8080 }]
resources:
requests: { cpu: 250m, memory: 256Mi }
limits: { cpu: "1", memory: 512Mi }
startupProbe: # 慢启动应用:先 startup,成功后再启用 liveness
httpGet: { path: /healthz, port: 8080 }
periodSeconds: 5
failureThreshold: 30
readinessProbe: # 就绪才进 Service 后端
httpGet: { path: /readyz, port: 8080 }
livenessProbe: # 失败重启容器
httpGet: { path: /livez, port: 8080 }
periodSeconds: 10
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false探针三条分工记牢:startup 判断「容器是否完成启动」(避免重启风暴)、readiness 决定「流量是否放进来」(就绪才进 Service)、liveness 决定「坏了要不要重启」。杀掉一个健康检查就能观察滚动更新与重启行为。
调度、资源与驱逐
requests用于调度与保证,limits用于硬性上限;超limits会 OOM(内存)或被节流(CPU);- 没有 requests/limits 的 Pod 可能被 kubelet 在资源紧张时优先驱逐;
- 节点打污点(taint),Pod 用容忍(toleration)决定「能不能调度上来」;
nodeSelector/亲和性决定「偏好去哪」; - HPA 按 CPU/自定义指标扩缩容,配合 limits 使用效果稳定。
bash
kubectl taint nodes node-pool=gpu:NoSchedule
kubectl get hpa
kubectl top nodes && kubectl top pods # 需要 metrics-serverService 与 Ingress:怎么把流量送进来
| Service 类型 | 可见范围 | 用途 |
|---|---|---|
| ClusterIP | 集群内 | 服务间调用(默认) |
| NodePort | 节点 IP:端口 | 测试/边缘场景 |
| LoadBalancer | 云 LB | 云环境暴露入口 |
yaml
apiVersion: v1
kind: Service
metadata:
name: api
namespace: prod
spec:
selector: { app: api }
ports: [{ port: 80, targetPort: 8080 }]集群内访问走 DNS:api.prod.svc.cluster.local。跨命名空间要用 namespace 限定,只写服务名最容易「本地通、集群里 404」。
Ingress 是入口层,把域名/路径路由到 Service:
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
spec:
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service: { name: api, port: { number: 80 } }配置与密钥注入
yaml
envFrom:
- configMapRef: { name: app-config }
- secretRef: { name: app-secret }- ConfigMap 管非敏感配置、Secret 管敏感项;Secret 默认只做 base64,生产要开加密(KMS);
- 配置更新后 Pod 内的环境变量不会自动刷新,需要滚动重建或走挂载文件方案;
- Secret 不要塞进镜像,也不要放进 git。
存储:让有状态应用活下来
- PVC 是「申请单」,PV 是「实际分配的盘」,StorageClass 负责按申请动态创建(云盘/NFS/Ceph);
- 应用迁移节点时,同一 PVC 上的 Pod 若只在一个节点可挂,需要 nodeAffinity/拓扑约束配合,否则调度后挂不上盘(Pending)。
bash
kubectl get pvc,pv,sc
kubectl describe pvc data-mysql-0 # Pending 时看 events 找原因排障工作流:一层层往下钻
bash
kubectl get pods -A # ① 全局:哪些异常
kubectl describe pod <name> -n <ns> # ② 事件与条件(拉镜像失败/未调度/探针失败)
kubectl logs -f <pod> -n <ns> # ③ 应用日志
kubectl logs <pod> -n <ns> --previous # ④ 崩溃前的日志(CrashLoop 必看)
kubectl get events --sort-by=.metadata.creationTimestamp -n <ns> # ⑤ 时序事件
kubectl exec -it <pod> -n <ns> -- sh # ⑥ 进容器看现场节点维护与集群安全
bash
kubectl cordon node-1 # 标记不可调度(先停新调度)
kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data # 排空后维护
# 维护完再 uncordon
kubectl uncordon node-1- drain 前确认有 PodDisruptionBudget(PDB),否则关键服务可能被全部赶走、瞬间不可用;
- 最小权限基线:namespace 隔离环境、RBAC 给最小角色、默认拒绝的网络策略(NetworkPolicy 需 CNI 支持);
- 控制面(etcd)备份与恢复演练要定期做,集群挂了才想起备份就晚了。
常见坑速查
| 坑 | 现象 | 解法 |
|---|---|---|
| 探针配置不当 | 重启风暴/流量时断时续 | 分清楚 startup/readiness/liveness,慢启动用 startup |
| 只写 limits 不写 requests | 调度离谱、被驱逐 | requests 按真实需求,limits 给上限 |
| 服务名不带 namespace | 跨空间连不上 | svc.ns.svc.cluster.local 或同空间直用 |
| 配置改了不生效 | 环境变量还是旧的 | 滚动重建,别等「自动刷新」 |
| Secret 明文入库/进镜像 | 泄露风险 | KMS 加密 + 注入方式 + 不入 git |
| ImagePullBackOff | 拉不到镜像 | 仓库可达性、tag 存在、凭证(imagePullSecrets) |
| CrashLoopBackOff | 一直重启 | --previous 看崩溃前日志 |
| drain 后服务全没 | 无 PDB 瞬间不可用 | 先建 PDB 再 drain |
| PVC Pending | 挂不上盘 | describe PVC 看 storageclass/拓扑约束 |
检查清单
- [ ] 工作负载都带 requests/limits 与合适的探针,无无限制 Pod;
- [ ] 有状态应用走 StatefulSet + PVC,数据卷不随 Pod 重建丢失;
- [ ] 流量入口清晰:集群内 Service DNS、外部 Ingress/LB,namespace 正确;
- [ ] 密钥用 Secret + 加密,未入库未进镜像;
- [ ] 节点维护流程(cordon → drain → PDB)演练过,etcd 有备份与恢复预案;
- [ ] 排障顺序沉淀为团队手册,
kubectl get events等能快速定位问题。