> ## Content Index
> Fetch the complete content index at: https://blog.vercanti.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Kubernetes 进阶
- URL: https://blog.vercanti.com/kubernetes-jin-jie/
- Published: 2026-08-28T14:34:25.000Z
- Updated: 2026-08-28T14:56:29.000Z
- Description: 访问模式（accessModes） PV 回收策略（persistentVolumeReclaimPolicy） 无需管理员手动创建 PV，PVC 通过 storageClassName 指定 StorageClass，控制器自动创建匹配的 PV。 Ingress 是集群入口的 HTTP/HTTPS 路由规则，需要配合 Ingress Controller（如 Nginx Ingress）使用。Ingress Controller 本身作为 Deployment 运行在集群中，监听 Ingress 资源变化并动态配置反向代理。 Ingress YAML
- Author: yellowdog
- Tags: DevOps

> 官方文档：<https://kubernetes.io/zh-cn/docs/home/>  
> 适用版本：Kubernetes 1.29+（2026-05-07 核实）

## 存储

### Volume 类型对比

| 类型                    | 生命周期           | 说明                                  | 典型使用场景                        |
| --------------------- | -------------- | ----------------------------------- | ----------------------------- |
| emptyDir              | 与 Pod 相同       | Pod 创建时分配，Pod 删除时数据清除；同一 Pod 内容器可共享 | 容器间临时文件共享、缓存、日志中转             |
| hostPath              | 与 Node 相关      | 挂载宿主机目录或文件，Pod 删除后数据保留在节点上          | 访问宿主机日志、Docker socket；不推荐生产使用 |
| configMap             | 与 ConfigMap 相同 | 将 ConfigMap 的数据挂载为文件                | 配置文件注入                        |
| secret                | 与 Secret 相同    | 将 Secret 数据挂载为文件（内存中的 tmpfs）        | 证书、密钥文件注入                     |
| persistentVolumeClaim | 独立于 Pod        | 引用已有的 PVC，数据持久化存储                   | 数据库、有状态应用                     |

### PV / PVC / StorageClass 三者关系

```
StorageClass（存储类）
    │
    │ 动态供应
    ▼
PersistentVolume（PV）── 静态绑定 ──► PersistentVolumeClaim（PVC）
                                              │
                                              │ 引用
                                              ▼
                                           Pod spec

```

- **PersistentVolume（PV）**：集群管理员预先创建（静态）或由 StorageClass 自动创建（动态）的存储资源，描述实际存储的位置和容量。
- **PersistentVolumeClaim（PVC）**：用户对存储的申请，声明所需容量和访问模式，Kubernetes 自动匹配合适的 PV 进行绑定。
- **StorageClass**：存储的"模板"，定义存储驱动（provisioner）和参数，支持动态按需创建 PV。

**访问模式（accessModes）**

| 模式            | 缩写  | 说明                                |
| ------------- | --- | --------------------------------- |
| ReadWriteOnce | RWO | 只能被单个 Node 以读写方式挂载                |
| ReadOnlyMany  | ROX | 可被多个 Node 以只读方式挂载                 |
| ReadWriteMany | RWX | 可被多个 Node 以读写方式挂载（需要共享文件系统，如 NFS） |

**PV 回收策略（persistentVolumeReclaimPolicy）**

| 策略      | 说明                              |
| ------- | ------------------------------- |
| Retain  | PVC 删除后 PV 保留，需手动处理数据           |
| Delete  | PVC 删除后 PV 及底层存储一并删除（动态供应的默认行为） |
| Recycle | 已废弃，不推荐使用                       |

### 动态供应（Dynamic Provisioning）

无需管理员手动创建 PV，PVC 通过 `storageClassName` 指定 StorageClass，控制器自动创建匹配的 PV。

```yaml
# StorageClass 示例（使用 AWS EBS）
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
reclaimPolicy: Delete
allowVolumeExpansion: true

```

```yaml
# PVC 使用动态供应
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  storageClassName: fast
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

```

```yaml
# Pod 引用 PVC
volumes:
  - name: data
    persistentVolumeClaim:
      claimName: my-pvc

```

---

## 网络

### Ingress

Ingress 是集群入口的 HTTP/HTTPS 路由规则，需要配合 Ingress Controller（如 Nginx Ingress）使用。Ingress Controller 本身作为 Deployment 运行在集群中，监听 Ingress 资源变化并动态配置反向代理。

**Ingress YAML 结构**

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - example.com
      secretName: tls-secret    # 包含 tls.crt 和 tls.key 的 Secret
  rules:
    - host: example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-service
                port:
                  number: 80

```

**`spec.rules` 字段**

| 字段                                         | 类型  | 说明                                          |
| ------------------------------------------ | --- | ------------------------------------------- |
| host                                       | 字符串 | 域名，省略则匹配所有 Host                             |
| http.paths\[\].path                        | 字符串 | URL 路径前缀或精确匹配                               |
| http.paths\[\].pathType                    | 字符串 | Prefix（前缀）、Exact（精确）、ImplementationSpecific |
| http.paths\[\].backend.service.name        | 字符串 | 后端 Service 名称                               |
| http.paths\[\].backend.service.port.number | 整数  | 后端 Service 端口                               |

**`spec.tls` 字段**

| 字段         | 类型  | 说明                   |
| ---------- | --- | -------------------- |
| hosts      | 列表  | TLS 生效的域名列表          |
| secretName | 字符串 | 存储 TLS 证书的 Secret 名称 |

### NetworkPolicy

NetworkPolicy 限制 Pod 间的网络通信，默认 Pod 可以互相访问；创建 NetworkPolicy 后仅允许规则匹配的流量通过。需要 CNI 插件支持（如 Calico、Cilium）。

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-allow
  namespace: production
spec:
  podSelector:
    matchLabels:
      role: api             # 该策略作用于带此标签的 Pod
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              role: frontend  # 只允许 frontend Pod 访问
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - podSelector:
            matchLabels:
              role: database
      ports:
        - protocol: TCP
          port: 5432

```

---

## 调度

### nodeSelector / nodeAffinity / podAffinity / podAntiAffinity 对比

| 特性              | 描述                                                                                            | 灵活性 |
| --------------- | --------------------------------------------------------------------------------------------- | --- |
| nodeSelector    | 简单键值对标签匹配，强制要求 Pod 调度到带有指定标签的节点                                                               | 低   |
| nodeAffinity    | 节点亲和性，支持 In、NotIn、Exists 等操作符，可区分硬性（requiredDuringScheduling）和软性（preferredDuringScheduling）要求 | 高   |
| podAffinity     | Pod 亲和性，要求调度到与指定 Pod 相同的节点/拓扑域（如同一区域），常用于低延迟场景                                                | 高   |
| podAntiAffinity | Pod 反亲和性，要求调度到与指定 Pod 不同的节点/拓扑域，常用于高可用（避免单点）                                                  | 高   |

```yaml
# nodeAffinity 示例
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
        - matchExpressions:
            - key: topology.kubernetes.io/zone
              operator: In
              values: ["us-east-1a", "us-east-1b"]
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app: my-app
          topologyKey: kubernetes.io/hostname  # 尽量分散到不同节点

```

### Taints 与 Tolerations

**Taint** 给节点打上"污点"，阻止没有对应 Toleration 的 Pod 调度到该节点。

```bash
# 给节点添加 Taint
kubectl taint nodes node1 key=value:NoSchedule

# 删除 Taint
kubectl taint nodes node1 key=value:NoSchedule-

```

Taint 效果（effect）：

| 效果               | 说明                        |
| ---------------- | ------------------------- |
| NoSchedule       | 不允许调度新 Pod（已运行的 Pod 不受影响） |
| PreferNoSchedule | 尽量不调度，但没有其他节点时仍可调度        |
| NoExecute        | 不允许调度，且驱逐已运行的不容忍 Pod      |

**Toleration** 允许 Pod 容忍节点的污点：

```yaml
tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"
  - key: "node.kubernetes.io/not-ready"
    operator: "Exists"
    effect: "NoExecute"
    tolerationSeconds: 300   # 最多容忍 300 秒后驱逐

```

### PriorityClass

定义 Pod 的调度优先级，高优先级 Pod 在资源不足时可抢占低优先级 Pod。

```yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000          # 数值越大优先级越高
globalDefault: false
description: "用于关键生产服务"

```

```yaml
# Pod 使用 PriorityClass
spec:
  priorityClassName: high-priority

```

---

## 自动扩缩容

### HorizontalPodAutoscaler（HPA）

HPA 根据 CPU、内存或自定义指标自动调整 Deployment/StatefulSet 的副本数。需要集群安装 metrics-server。

```yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70    # CPU 使用率超过 70% 时扩容
    - type: Resource
      resource:
        name: memory
        target:
          type: AverageValue
          averageValue: 512Mi

```

**HPA `spec` 核心字段**

| 字段                 | 类型 | 默认值 | 说明                         |
| ------------------ | -- | --- | -------------------------- |
| scaleTargetRef     | 对象 | 必填  | 指定被扩缩容的目标资源                |
| minReplicas        | 整数 | 1   | 最小副本数，HPA 不会将副本降至此值以下      |
| maxReplicas        | 整数 | 必填  | 最大副本数                      |
| metrics            | 列表 | 必填  | 扩缩容指标列表                    |
| behavior.scaleUp   | 对象 | 无   | 扩容行为配置（稳定窗口、步长）            |
| behavior.scaleDown | 对象 | 无   | 缩容行为配置（稳定窗口默认 5 分钟，防止频繁缩容） |

**metrics 类型**

| 类型                | 说明                       |
| ----------------- | ------------------------ |
| Resource          | 基于 CPU/内存使用率或绝对值         |
| ContainerResource | 针对 Pod 内特定容器的资源指标        |
| Pods              | Pod 级别自定义指标（如每秒请求数）      |
| Object            | 集群对象的指标（如 Ingress 的 QPS） |
| External          | 外部系统指标（如消息队列积压量）         |

---

## StatefulSet

### 与 Deployment 的区别

| 特性      | Deployment        | StatefulSet                                  |
| ------- | ----------------- | -------------------------------------------- |
| Pod 名称  | 随机后缀（如 app-abc12） | 有序且固定（如 app-0、app-1）                         |
| 部署/删除顺序 | 并行，无序             | 有序（0, 1, 2...），删除时反序                         |
| 网络标识    | Pod IP 变化         | 稳定 DNS 名称（通过 Headless Service）如 app-0.my-svc |
| 存储      | 共享或无状态            | 每个 Pod 有独立的 PVC（volumeClaimTemplates）        |

### 适用场景

- **数据库**：MySQL、PostgreSQL（需要主从固定角色）
- **消息队列**：Kafka（Broker ID 与 Pod 序号绑定）
- **分布式协调**：ZooKeeper、etcd（需要固定网络标识）

```yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: "mysql"          # 必须指定 Headless Service 名称
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: password
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: fast
        resources:
          requests:
            storage: 20Gi

```

---

## ConfigMap/Secret 热更新

### Volume 挂载方式（自动更新）

以 Volume 方式挂载的 ConfigMap，Kubernetes 会在 ConfigMap 内容变更后自动同步到容器内的文件（默认同步周期约为 1 分钟，取决于 kubelet 的 `--sync-frequency`）。

```yaml
volumeMounts:
  - name: config
    mountPath: /etc/app/config.yaml
    subPath: config.yaml    # 注意：使用 subPath 时不会自动更新
volumes:
  - name: config
    configMap:
      name: my-config

```

注意：使用 `subPath` 挂载单个文件时，自动更新失效，需重启 Pod。

### 环境变量方式（不自动更新）

通过 `env.valueFrom.configMapKeyRef` 或 `envFrom` 注入的环境变量，在 ConfigMap 更新后不会刷新。必须重启 Pod 才能生效。

**强制触发 Pod 重启的常用方式**：

```bash
# 方式一：滚动重启 Deployment（零停机）
kubectl rollout restart deployment/my-app

# 方式二：修改 Deployment 的 annotation 触发更新
kubectl patch deployment my-app -p \
  '{"spec":{"template":{"metadata":{"annotations":{"restarted-at":"2026-04-11"}}}}}'

```

---

## RBAC（基于角色的访问控制）

### 核心对象关系

```
ServiceAccount（身份）
    │
    │ RoleBinding / ClusterRoleBinding
    ▼
Role（命名空间级权限）/ ClusterRole（集群级权限）

```

| 对象                 | 作用范围      | 说明                                                 |
| ------------------ | --------- | -------------------------------------------------- |
| ServiceAccount     | Namespace | Pod 的身份标识，用于与 API Server 交互                        |
| Role               | Namespace | 定义在特定命名空间内的权限规则                                    |
| ClusterRole        | 集群        | 定义集群范围的权限，或跨命名空间复用                                 |
| RoleBinding        | Namespace | 将 Role 或 ClusterRole 绑定到 ServiceAccount/User/Group |
| ClusterRoleBinding | 集群        | 将 ClusterRole 绑定到集群范围的主体                           |

```yaml
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
  namespace: production

---
# Role：允许读取特定命名空间的 Pod 和 ConfigMap
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: production
rules:
  - apiGroups: [""]
    resources: ["pods", "configmaps"]
    verbs: ["get", "list", "watch"]

---
# RoleBinding：将 Role 绑定到 ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: production
subjects:
  - kind: ServiceAccount
    name: app-sa
    namespace: production
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

```

**最小权限原则**

- 每个应用创建专用 ServiceAccount，不使用 `default`
- 优先使用 `Role` \+ `RoleBinding` 而非 `ClusterRole` \+ `ClusterRoleBinding`
- verbs 只授予必要的操作：`get`、`list`、`watch`（只读），避免授予 `*` 通配符
- 定期审查并清理不再使用的 Role

---

## Helm

Helm 是 Kubernetes 的包管理工具，通过 Chart 封装一组 Kubernetes 资源模板，支持版本管理和参数化配置。

### 常用命令

**helm install**

```bash
helm install <release-name> <chart> [flags]

```

| 参数                  | 说明                           |
| ------------------- | ---------------------------- |
| <release-name>      | 发布名称，集群内唯一                   |
| <chart>             | Chart 名称（repo/chart）或本地路径    |
| \-n / \--namespace  | 部署到指定命名空间                    |
| \-f / \--values     | 指定自定义 values 文件              |
| \--set              | 命令行覆盖单个值，如 \--set replicas=3 |
| \--version          | 指定 Chart 版本                  |
| \--dry-run          | 模拟安装，输出渲染后的 YAML             |
| \--create-namespace | 命名空间不存在时自动创建                 |

**helm upgrade**

```bash
helm upgrade <release-name> <chart> [flags]

```

| 参数              | 说明                                          |
| --------------- | ------------------------------------------- |
| \--install      | release 不存在时自动安装（等同于 install + upgrade 二合一） |
| \--atomic       | 升级失败时自动回滚                                   |
| \--wait         | 等待所有资源就绪后再返回                                |
| \--timeout      | 等待超时时间，默认 5m0s                              |
| \--reuse-values | 复用上次的 values，只覆盖本次指定的参数                     |

**helm rollback**

```bash
helm rollback <release-name> [revision]

```

| 参数           | 说明               |
| ------------ | ---------------- |
| \[revision\] | 目标版本号，省略则回滚到上一版本 |
| \--wait      | 等待回滚完成           |

**helm uninstall**

```bash
helm uninstall <release-name> [-n namespace]

```

| 参数              | 说明                    |
| --------------- | --------------------- |
| \--keep-history | 保留 release 历史记录（默认删除） |

**其他常用命令**

```bash
# 添加仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# 查看已安装的 release
helm list -A

# 查看 release 历史
helm history my-release

# 查看渲染后的 YAML（不实际部署）
helm template my-release ingress-nginx/ingress-nginx -f values.yaml

# 查看 Chart 的默认 values
helm show values ingress-nginx/ingress-nginx

```

### values.yaml 覆盖

优先级从低到高：Chart 默认 values → `-f values.yaml` → `--set`。

```bash
# 使用自定义 values 文件安装
helm install ingress-nginx ingress-nginx/ingress-nginx \
  -n ingress-nginx \
  --create-namespace \
  -f custom-values.yaml

# 多个 values 文件叠加（后者覆盖前者）
helm install my-app ./my-chart -f base.yaml -f prod.yaml

# 命令行覆盖嵌套字段
helm install my-app ./my-chart --set image.tag=1.2.3 --set service.type=LoadBalancer

```

### 常用 Chart

| Chart                                      | 仓库                                                 | 用途                               |
| ------------------------------------------ | -------------------------------------------------- | -------------------------------- |
| ingress-nginx/ingress-nginx                | https://kubernetes.github.io/ingress-nginx         | Nginx Ingress Controller         |
| cert-manager/cert-manager                  | https://charts.jetstack.io                         | 自动申请/续签 TLS 证书（支持 Let's Encrypt） |
| prometheus-community/kube-prometheus-stack | https://prometheus-community.github.io/helm-charts | Prometheus + Grafana 监控套件        |

---

## 踩坑与注意事项

### PVC 数据残留问题

删除 StatefulSet 时，`volumeClaimTemplates` 创建的 PVC 不会自动删除（设计如此，防止数据误删）。

```bash
# 查看残留 PVC
kubectl get pvc -n <namespace>

# 手动删除 PVC（确认数据已备份）
kubectl delete pvc data-mysql-0 data-mysql-1 data-mysql-2

```

如果 PV 的回收策略是 `Retain`，删除 PVC 后 PV 仍保留，需要手动删除或重新绑定。

### ConfigMap 更新后 Pod 不重启

环境变量方式注入的 ConfigMap 不会自动刷新，必须触发 Pod 重启。推荐做法：

1. 在 CI/CD 流水线中将 ConfigMap 的 hash 作为 Deployment annotation，ConfigMap 变更时 annotation 值变化，自动触发滚动更新：  
```yaml  
annotations:  
  checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}  
```
2. 或使用 `kubectl rollout restart deployment/<name>` 手动触发。

### Ingress 404 排查步骤

1. **确认 Ingress Controller 正常运行**：  
```bash  
kubectl get pods -n ingress-nginx  
kubectl logs -n ingress-nginx <ingress-nginx-pod>  
```
2. **确认 Ingress 资源已创建**：  
```bash  
kubectl get ingress -A  
kubectl describe ingress <name> -n <namespace>  
```
3. **确认 ingressClassName 匹配**：Ingress 的 `spec.ingressClassName` 必须与 Controller 的 class 一致（通常为 `nginx`）。
4. **确认后端 Service 和 Pod 正常**：  
```bash  
kubectl get svc,endpoints -n <namespace>  
```  
Endpoints 列表为空说明 selector 未匹配到 Pod。
5. **确认路径规则**：`pathType: Prefix` 下 `/api` 能匹配 `/api/v1`；`pathType: Exact` 则只能精确匹配。
6. **检查 annotation**：`nginx.ingress.kubernetes.io/rewrite-target` 配置不当会导致路径重写错误。

### 其他常见坑

- **HPA 不生效**：检查 metrics-server 是否安装，`kubectl top pods` 能否正常输出。Deployment 必须设置 `resources.requests.cpu`，否则 HPA 无法计算利用率百分比。
- **StatefulSet 滚动更新卡住**：某个 Pod 一直 Pending 或 CrashLoopBackOff 会阻塞后续 Pod 的更新（有序策略）。用 `kubectl rollout status statefulset/<name>` 监控，出现问题需先修复该 Pod。
- **Helm release 状态为 failed**：执行 `helm rollback` 或 `helm uninstall` 后重新安装。`--atomic` 参数可以在失败时自动回滚，适合 CI/CD 场景。
- **Secret 更新后 Volume 挂载不刷新**：虽然理论上 Secret Volume 也会自动同步，但使用 `subPath` 挂载时同样不会更新。避免对频繁变更的 Secret 使用 `subPath`。

---

## 最佳实践

**HPA 与 VPA 不要同时作用于同一资源维度**：HPA 基于 CPU/内存自动扩缩副本数，VPA 自动调整单 Pod 的 resource requests；两者同时控制 CPU 会互相干扰。可以让 HPA 管 CPU 水平扩展，VPA 只管内存的垂直调整（`updateMode: "Initial"` 避免重建 Pod）。

**StatefulSet 使用 `podManagementPolicy: Parallel` 加速批量操作**：默认有序（`OrderedReady`）策略在扩缩容时依次等待每个 Pod ready，并发场景下改为 `Parallel` 可大幅缩短时间（注意应用本身需支持并发启动）。

**Helm Chart 用 `--atomic` 防止残留失败 release**：CI/CD 中加 `--atomic` 标志，升级失败时自动回滚到上一个成功版本，避免留下 `failed` 状态的 release 阻塞后续部署。

**网络策略（NetworkPolicy）默认拒绝，按需开放**：新命名空间默认无网络策略，所有 Pod 互通。生产环境先应用 deny-all 策略，再逐步开放需要的端口和方向，减少横向移动风险。

**用 `PodDisruptionBudget` 保障滚动更新期间最小可用副本**：`minAvailable: 1` 确保即使在节点维护或滚动更新时，始终至少有 1 个副本处于 Ready 状态对外服务。

---

## 常见陷阱

### 陷阱：HPA 不生效，副本数不变

**现象：** 负载升高但 `kubectl get hpa` 显示 `<unknown>/50%`，副本数不增加。  
**原因：** metrics-server 未安装或 Pod 未设置 `resources.requests.cpu`，HPA 无法获取利用率百分比。  
**解决：** 安装 metrics-server（`kubectl top pods` 可用），确保 Deployment 的 Pod spec 中有 `resources.requests.cpu`。

### 陷阱：StatefulSet 滚动更新卡在某个 Pod

**现象：** `kubectl rollout status statefulset/<name>` 长时间等待，某个 Pod 一直 CrashLoopBackOff。  
**原因：** 有序策略下，前一个 Pod 未 Ready 则后续 Pod 不会更新，问题 Pod 阻塞整个滚动更新。  
**解决：** `kubectl describe pod <stucked-pod>` 查看错误原因修复应用问题，或 `kubectl rollout undo statefulset/<name>` 回滚。

### 陷阱：Helm upgrade 后旧版本 ConfigMap/Secret 残留

**现象：** Helm upgrade 后应用读取到旧配置，`kubectl describe pod` 显示挂载的仍是旧 ConfigMap。  
**原因：** Helm 不重启未变更的 Deployment，即使 ConfigMap 已更新，已运行的 Pod 不会自动感知变化。  
**解决：** 在 Deployment 的 Pod template annotations 中加入 ConfigMap 的 checksum，ConfigMap 变更时 annotation 变化触发滚动重启：

```yaml
annotations:
  checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}

```

---

## 参见

[Kubernetes基础](https://blog.vercanti.com/kubernetes-ji-chu/)  
[Docker高级指南](https://blog.vercanti.com/docker-gao-ji-zhi-nan/)  
[GitHub Actions完全指南](https://blog.vercanti.com/github-actions-wan-quan-zhi-nan/)  
[Prometheus与Grafana监控](https://blog.vercanti.com/prometheus-yu-grafana-jian-kong/)