Skip to content

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-server

Service 与 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 等能快速定位问题。

基于 VitePress 构建 · 内容以知识共享方式沉淀