> ## 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-ji-chu/
- Published: 2026-08-28T14:34:25.000Z
- Updated: 2026-08-28T14:56:27.000Z
- Description: Kubernetes 集群由两类节点组成：Control Plane（控制平面）和 Worker Node（工作节点）。 Control Plane 组件 Worker Node 组件 生产环境推荐声明式，便于版本控制和 GitOps 工作流。 列出资源对象。 查看资源详情及事件（排查问题的首选命令）。 将 YAML/JSON 清单应用到集群（声明式更新）。 删除资源对象。 查看 Pod 中容器的日志。 在运行中的容器内执行命令。 将本地端口转发到 Pod 端口，常用于本地调试。 调整 Deployment/StatefulSet/ReplicaSet
- Author: yellowdog
- Tags: DevOps

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

## 核心概念

### 集群架构

Kubernetes 集群由两类节点组成：Control Plane（控制平面）和 Worker Node（工作节点）。

**Control Plane 组件**

| 组件                 | 职责                                                                    |
| ------------------ | --------------------------------------------------------------------- |
| API Server         | 集群的统一入口，所有操作（kubectl、内部组件通信）均通过 REST API 与它交互                         |
| etcd               | 分布式键值存储，保存集群所有状态数据（配置、资源对象）                                           |
| Scheduler          | 监听未调度的 Pod，根据资源需求、亲和性等规则将其分配到合适的 Node                                 |
| Controller Manager | 运行各类控制器（Deployment Controller、ReplicaSet Controller 等），持续将实际状态收敛到期望状态 |

**Worker Node 组件**

| 组件                | 职责                                            |
| ----------------- | --------------------------------------------- |
| kubelet           | 运行在每个 Node 上的代理，负责接收 Pod 规格并驱动容器运行时启动/维护容器    |
| kube-proxy        | 维护节点上的 iptables/ipvs 规则，实现 Service 的负载均衡和流量转发 |
| Container Runtime | 实际运行容器的引擎，常见实现为 containerd、CRI-O（旧版为 Docker）  |

### Pod、Node、Namespace 的关系

- **Node** 是物理或虚拟机器，是运行 Pod 的宿主机。
- **Pod** 是 Kubernetes 最小调度单元，运行在某个 Node 上，包含一个或多个容器，共享网络栈和存储卷。
- **Namespace** 是逻辑隔离单位，用于将同一集群的资源划分为不同的虚拟空间（如 `dev`、`staging`、`prod`）。Node 本身不属于 Namespace，Pod 和 Service 等资源属于某个 Namespace。

### 声明式 vs 命令式

| 方式               | 描述              | 典型用法                           |
| ---------------- | --------------- | ------------------------------ |
| 命令式（Imperative）  | 直接告诉集群"做什么动作"   | kubectl run、kubectl scale      |
| 声明式（Declarative） | 描述"期望状态"，集群自动收敛 | kubectl apply -f manifest.yaml |

生产环境推荐声明式，便于版本控制和 GitOps 工作流。

---

## kubectl 常用命令

### kubectl get

列出资源对象。

```bash
kubectl get <resource> [-n namespace] [-o wide|yaml|json]

```

| 参数                 | 类型   | 默认值     | 说明                                             |
| ------------------ | ---- | ------- | ---------------------------------------------- |
| <resource>         | 字符串  | 必填      | 资源类型，如 pods、deployments、services、nodes         |
| \-n / \--namespace | 字符串  | default | 指定命名空间；\-A 表示所有命名空间                            |
| \-o / \--output    | 字符串  | 表格      | 输出格式：wide（更多列）、yaml、json、name                  |
| \-l / \--selector  | 字符串  | 无       | 按标签筛选，如 \-l app=nginx                          |
| \--field-selector  | 字符串  | 无       | 按字段筛选，如 \--field-selector status.phase=Running |
| \-w / \--watch     | bool | false   | 监听资源变化，实时输出                                    |

```bash
kubectl get pods -n kube-system -o wide
kubectl get all -A
kubectl get pods -l app=nginx

```

### kubectl describe

查看资源详情及事件（排查问题的首选命令）。

```bash
kubectl describe <resource> <name> [-n namespace]

```

| 参数                 | 类型  | 默认值     | 说明   |
| ------------------ | --- | ------- | ---- |
| <resource>         | 字符串 | 必填      | 资源类型 |
| <name>             | 字符串 | 必填      | 资源名称 |
| \-n / \--namespace | 字符串 | default | 命名空间 |

```bash
kubectl describe pod my-pod -n default
kubectl describe node worker-1

```

### kubectl apply

将 YAML/JSON 清单应用到集群（声明式更新）。

```bash
kubectl apply -f <file.yaml>

```

| 参数                 | 类型     | 默认值   | 说明                               |
| ------------------ | ------ | ----- | -------------------------------- |
| \-f / \--filename  | 字符串/目录 | 必填    | 文件路径、目录或 URL；\-f . 应用当前目录所有 YAML |
| \-R / \--recursive | bool   | false | 递归处理目录                           |
| \--dry-run=client  | 字符串    | 无     | 模拟执行，不实际变更集群                     |
| \--prune           | bool   | false | 删除集群中存在但本地清单中已移除的资源              |

```bash
kubectl apply -f deployment.yaml
kubectl apply -f ./manifests/ -R
kubectl apply -f deployment.yaml --dry-run=client

```

### kubectl delete

删除资源对象。

```bash
kubectl delete <resource> <name> [-n namespace]

```

| 参数              | 类型   | 默认值       | 说明                |
| --------------- | ---- | --------- | ----------------- |
| <resource>      | 字符串  | 必填        | 资源类型              |
| <name>          | 字符串  | 必填（或用 -f） | 资源名称              |
| \-f             | 字符串  | 无         | 通过文件删除            |
| \--grace-period | 整数   | 30        | 优雅终止等待秒数；0 强制立即删除 |
| \--force        | bool | false     | 强制删除，跳过优雅终止       |

```bash
kubectl delete pod my-pod
kubectl delete -f deployment.yaml
kubectl delete pod my-pod --grace-period=0 --force

```

### kubectl logs

查看 Pod 中容器的日志。

```bash
kubectl logs <pod> [-c container] [-f] [--previous]

```

| 参数                 | 类型   | 默认值   | 说明                         |
| ------------------ | ---- | ----- | -------------------------- |
| <pod>              | 字符串  | 必填    | Pod 名称                     |
| \-c / \--container | 字符串  | 无     | 多容器 Pod 时指定容器名             |
| \-f / \--follow    | bool | false | 持续跟踪输出（类似 tail -f）         |
| \--previous        | bool | false | 查看上一个已终止容器的日志（容器崩溃重启后排查）   |
| \--tail            | 整数   | 无     | 只输出最后 N 行                  |
| \--since           | 时间段  | 无     | 只输出指定时间段内的日志，如 \--since=1h |

```bash
kubectl logs my-pod -c sidecar -f
kubectl logs my-pod --previous --tail=100

```

### kubectl exec

在运行中的容器内执行命令。

```bash
kubectl exec -it <pod> [-c container] -- /bin/sh

```

| 参数                 | 类型   | 默认值   | 说明            |
| ------------------ | ---- | ----- | ------------- |
| <pod>              | 字符串  | 必填    | Pod 名称        |
| \-i / \--stdin     | bool | false | 保持标准输入打开      |
| \-t / \--tty       | bool | false | 分配伪终端         |
| \-c / \--container | 字符串  | 无     | 多容器 Pod 时指定容器 |
| \--                | 分隔符  | 无     | 之后为传入容器的命令    |

```bash
kubectl exec -it my-pod -- /bin/bash
kubectl exec -it my-pod -c init-container -- /bin/sh

```

### kubectl port-forward

将本地端口转发到 Pod 端口，常用于本地调试。

```bash
kubectl port-forward <pod> <local>:<remote>

```

| 参数               | 类型   | 默认值     | 说明                                    |
| ---------------- | ---- | ------- | ------------------------------------- |
| <pod>            | 字符串  | 必填      | Pod 名称；也可用 svc/<name> 或 deploy/<name> |
| <local>:<remote> | 端口映射 | 必填      | 本地端口:容器端口                             |
| \-n              | 字符串  | default | 命名空间                                  |

```bash
kubectl port-forward my-pod 8080:80
kubectl port-forward svc/my-service 9090:9090 -n staging

```

### kubectl scale

调整 Deployment/StatefulSet/ReplicaSet 的副本数。

```bash
kubectl scale deployment <name> --replicas=N

```

| 参数          | 类型  | 默认值     | 说明    |
| ----------- | --- | ------- | ----- |
| <name>      | 字符串 | 必填      | 资源名称  |
| \--replicas | 整数  | 必填      | 目标副本数 |
| \-n         | 字符串 | default | 命名空间  |

```bash
kubectl scale deployment my-app --replicas=3

```

### kubectl rollout

管理 Deployment 的发布过程。

```bash
kubectl rollout status|history|undo deployment/<name>

```

| 子命令     | 说明                                      |
| ------- | --------------------------------------- |
| status  | 查看当前滚动更新进度                              |
| history | 查看历史版本列表（需要 \--record 或设置 change-cause） |
| undo    | 回滚到上一版本；\--to-revision=N 回滚到指定版本        |
| pause   | 暂停滚动更新                                  |
| resume  | 恢复已暂停的滚动更新                              |

```bash
kubectl rollout status deployment/my-app
kubectl rollout history deployment/my-app
kubectl rollout undo deployment/my-app
kubectl rollout undo deployment/my-app --to-revision=2

```

---

## 核心资源对象

### Pod

Pod 是 Kubernetes 的最小调度单元，封装一个或多个容器。

**基本 YAML 结构**

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  namespace: default
  labels:
    app: my-app
spec:
  containers:
    - name: main
      image: nginx:1.25
      ports:
        - containerPort: 80
      env:
        - name: ENV_VAR
          value: "hello"
      resources:
        requests:
          cpu: "100m"
          memory: "128Mi"
        limits:
          cpu: "500m"
          memory: "256Mi"
      volumeMounts:
        - name: config-vol
          mountPath: /etc/config
      livenessProbe:
        httpGet:
          path: /healthz
          port: 80
        initialDelaySeconds: 10
        periodSeconds: 5
      readinessProbe:
        httpGet:
          path: /ready
          port: 80
        initialDelaySeconds: 5
        periodSeconds: 3
  volumes:
    - name: config-vol
      configMap:
        name: my-config

```

**`spec.containers` 核心字段**

| 字段              | 类型  | 默认值          | 说明                              |
| --------------- | --- | ------------ | ------------------------------- |
| name            | 字符串 | 必填           | 容器名称，同一 Pod 内唯一                 |
| image           | 字符串 | 必填           | 镜像地址，建议指定具体 tag，避免使用 latest     |
| ports           | 列表  | 无            | 声明容器监听的端口（仅文档作用，不影响实际网络）        |
| env             | 列表  | 无            | 环境变量，支持直接赋值或引用 ConfigMap/Secret |
| resources       | 对象  | 无            | CPU/内存的 requests 和 limits       |
| volumeMounts    | 列表  | 无            | 挂载卷到容器内的路径                      |
| livenessProbe   | 对象  | 无            | 存活探针，失败则重启容器                    |
| readinessProbe  | 对象  | 无            | 就绪探针，失败则从 Service 摘除流量          |
| startupProbe    | 对象  | 无            | 启动探针，用于慢启动容器，成功后才开始执行其他探针       |
| command         | 列表  | 无            | 覆盖镜像的 ENTRYPOINT                |
| args            | 列表  | 无            | 覆盖镜像的 CMD                       |
| imagePullPolicy | 字符串 | IfNotPresent | 拉取策略：Always、IfNotPresent、Never  |

**resources.requests vs resources.limits**

| 字段       | 作用                                                       | 调度影响  |
| -------- | -------------------------------------------------------- | ----- |
| requests | Scheduler 用于选择节点的依据，保证容器能获得此资源量                          | 影响调度  |
| limits   | 容器能使用的资源上限，超出 CPU limit 会被限流，超出 Memory limit 会被 OOM Kill | 不影响调度 |

建议始终设置 `requests`，在资源紧张的生产环境也应设置 `limits`。

**多容器 Pod（Sidecar 模式）**

同一 Pod 内的容器共享网络（`localhost` 互通）和存储卷，适合以下模式：

- **Sidecar**：辅助主容器，如日志收集（Fluentd）、配置同步
- **Ambassador**：代理主容器对外通信
- **Adapter**：转换主容器的输出格式

```yaml
spec:
  containers:
    - name: app
      image: my-app:1.0
      volumeMounts:
        - name: log-vol
          mountPath: /var/log/app
    - name: log-collector
      image: fluentd:latest
      volumeMounts:
        - name: log-vol
          mountPath: /var/log/app
  volumes:
    - name: log-vol
      emptyDir: {}

```

---

### Deployment

Deployment 管理无状态应用的副本集，提供滚动更新和回滚能力。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: app
          image: my-app:1.0
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

```

**`spec` 核心字段**

| 字段                   | 类型   | 默认值           | 说明                                              |
| -------------------- | ---- | ------------- | ----------------------------------------------- |
| replicas             | 整数   | 1             | 期望的 Pod 副本数                                     |
| selector             | 对象   | 必填            | 选择受管 Pod 的标签选择器，必须与 template.metadata.labels 匹配 |
| template             | 对象   | 必填            | Pod 模板，定义创建 Pod 时使用的规格                          |
| strategy             | 对象   | RollingUpdate | 更新策略，支持 RollingUpdate 和 Recreate                |
| minReadySeconds      | 整数   | 0             | Pod 就绪后额外等待的秒数，再认为该 Pod 可用                      |
| revisionHistoryLimit | 整数   | 10            | 保留的历史 ReplicaSet 数量，用于回滚                        |
| paused               | bool | false         | 暂停发布，配合 kubectl rollout pause 使用                |

**滚动更新策略参数**

| 参数             | 类型     | 默认值 | 说明                      |
| -------------- | ------ | --- | ----------------------- |
| maxSurge       | 整数或百分比 | 25% | 更新期间允许超出期望副本数的最大 Pod 数量 |
| maxUnavailable | 整数或百分比 | 25% | 更新期间允许不可用的最大 Pod 数量     |

零停机发布建议：`maxSurge: 1`，`maxUnavailable: 0`。

---

### Service

Service 为一组 Pod 提供稳定的访问入口（虚拟 IP + DNS 名称）。

**Service 类型对比**

| 类型           | 访问范围 | 说明                                                      |
| ------------ | ---- | ------------------------------------------------------- |
| ClusterIP    | 集群内部 | 默认类型，分配集群内虚拟 IP，仅集群内可访问                                 |
| NodePort     | 集群外部 | 在每个 Node 上开放一个静态端口（30000-32767），外部通过 NodeIP:NodePort 访问 |
| LoadBalancer | 集群外部 | 需要云平台支持，自动创建外部负载均衡器，分配公网 IP                             |
| ExternalName | 集群内部 | 将 Service 映射到外部 DNS 名称（CNAME），用于访问集群外部服务                |

**`spec.selector` 工作方式**

Service 通过标签选择器动态发现后端 Pod。只要 Pod 带有匹配的标签且处于 Ready 状态，就会加入 Endpoints 列表。

```yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app       # 匹配带有此标签的 Pod
  ports:
    - port: 80        # Service 暴露的端口
      targetPort: 8080  # 转发到 Pod 的端口
  type: ClusterIP

```

**Headless Service**

将 `clusterIP` 设为 `None`，不分配虚拟 IP，DNS 查询直接返回 Pod IP 列表。StatefulSet 场景下常用，客户端可以直接连接到特定 Pod。

```yaml
spec:
  clusterIP: None
  selector:
    app: my-statefulset

```

---

### ConfigMap 与 Secret

**创建方式**

```bash
# 命令行字面量
kubectl create configmap my-config --from-literal=key1=value1 --from-literal=key2=value2

# 从文件创建
kubectl create configmap my-config --from-file=config.properties

# 从目录创建（目录下每个文件成为一个键）
kubectl create configmap my-config --from-file=./configs/

# YAML 方式
kubectl apply -f configmap.yaml

```

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  APP_ENV: production
  config.yaml: |
    server:
      port: 8080

```

Secret 创建方式相同，但内容会经 Base64 编码存储：

```bash
kubectl create secret generic my-secret \
  --from-literal=db-password=s3cr3t \
  --from-file=tls.crt=./certs/tls.crt

```

**注入方式对比**

| 方式          | 使用场景      | 特点                                 |
| ----------- | --------- | ---------------------------------- |
| 环境变量        | 简单键值对     | 容器启动时注入，ConfigMap 更新后不自动刷新，需重启 Pod |
| volumeMount | 配置文件、多行内容 | 以文件形式挂载，ConfigMap 更新后文件会自动同步（有延迟）  |

```yaml
# 环境变量注入
env:
  - name: APP_ENV
    valueFrom:
      configMapKeyRef:
        name: my-config
        key: APP_ENV
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: my-secret
        key: db-password

# 全量注入为环境变量
envFrom:
  - configMapRef:
      name: my-config

# volumeMount 注入
volumeMounts:
  - name: config-vol
    mountPath: /etc/app
volumes:
  - name: config-vol
    configMap:
      name: my-config

```

---

## Health Check（健康检查）

### 三种探针的区别

| 探针             | 失败后行为                                  | 典型使用场景                           |
| -------------- | -------------------------------------- | -------------------------------- |
| livenessProbe  | 重启容器                                   | 检测应用是否陷入死锁、无响应状态                 |
| readinessProbe | 从 Service Endpoints 中摘除该 Pod（不重启）      | 检测应用是否已准备好接收流量                   |
| startupProbe   | 在成功前，liveness/readiness 探针不会执行；失败超限则重启 | 启动慢的应用（如 JVM 应用），避免被 liveness 误杀 |

### 探针类型参数

**httpGet**

| 参数          | 类型     | 默认值  | 说明              |
| ----------- | ------ | ---- | --------------- |
| path        | 字符串    | 必填   | 请求路径            |
| port        | 整数/字符串 | 必填   | 端口号或容器端口名       |
| scheme      | 字符串    | HTTP | 协议：HTTP 或 HTTPS |
| httpHeaders | 列表     | 无    | 自定义请求头          |

**exec**

| 参数      | 类型 | 默认值 | 说明                    |
| ------- | -- | --- | --------------------- |
| command | 列表 | 必填  | 在容器内执行的命令，退出码为 0 表示成功 |

**tcpSocket**

| 参数   | 类型     | 默认值 | 说明               |
| ---- | ------ | --- | ---------------- |
| port | 整数/字符串 | 必填  | TCP 端口号，能建立连接则成功 |

**探针通用配置参数**

| 参数                  | 类型 | 默认值 | 说明                           |
| ------------------- | -- | --- | ---------------------------- |
| initialDelaySeconds | 整数 | 0   | 容器启动后等待多少秒才开始探测              |
| periodSeconds       | 整数 | 10  | 探测间隔秒数                       |
| timeoutSeconds      | 整数 | 1   | 探测超时秒数                       |
| successThreshold    | 整数 | 1   | 连续成功多少次才认为健康（liveness 只能为 1） |
| failureThreshold    | 整数 | 3   | 连续失败多少次才采取行动                 |

```yaml
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10
  timeoutSeconds: 5
  failureThreshold: 3

readinessProbe:
  exec:
    command: ["redis-cli", "ping"]
  initialDelaySeconds: 5
  periodSeconds: 5

startupProbe:
  tcpSocket:
    port: 8080
  failureThreshold: 30    # 最多等待 30 * 10 = 300 秒
  periodSeconds: 10

```

---

## 踩坑与注意事项

### Pod 一直处于 Pending 状态

排查思路：`kubectl describe pod <name>` 查看 Events 字段。

| 常见原因             | 表现                                                            | 解决方法                                |
| ---------------- | ------------------------------------------------------------- | ----------------------------------- |
| 节点资源不足           | Insufficient cpu / Insufficient memory                        | 调整 resources.requests，或扩容节点         |
| 镜像拉取失败           | Failed to pull image / ImagePullBackOff                       | 检查镜像名称、tag、仓库权限，配置 imagePullSecrets |
| NodeSelector 无匹配 | 0/N nodes are available: N node(s) didn't match node selector | 检查 nodeSelector 标签是否存在于节点           |
| PVC 未绑定          | pod has unbound immediate PersistentVolumeClaims              | 检查 PV/StorageClass 是否正确配置           |
| Taint 未容忍        | N node(s) had taints that the pod didn't tolerate             | 为 Pod 添加对应 tolerations              |

### ImagePullBackOff 排查步骤

1. `kubectl describe pod <name>` 查看具体错误信息
2. 确认镜像地址和 tag 正确：`docker pull <image>` 在本地验证
3. 私有仓库需创建 Secret 并配置 `imagePullSecrets`：  
```bash  
kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=user \
  --docker-password=password  
```  
```yaml  
spec:  
  imagePullSecrets:
    - name: regcred  
```
4. 检查节点网络是否能访问镜像仓库

### 其他常见坑

- **环境变量中引用 Secret**：Secret 的 value 已经是明文，不需要 Base64 解码，Kubernetes 会自动处理。
- **ConfigMap 大小限制**：单个 ConfigMap 数据上限为 1MB，超大配置文件建议用 Volume 挂载外部存储。
- **Service 和 Pod 标签必须严格匹配**：selector 中的每个标签键值对都必须出现在 Pod 的 labels 中。
- **`kubectl apply` 与 `kubectl create` 的区别**：`create` 用于首次创建，资源已存在则报错；`apply` 创建或更新，推荐生产使用。

---

## 最佳实践

**始终设置 `resources.requests` 和 `resources.limits`**：没有 `requests` 的 Pod 会被调度到资源不足的节点，没有 `limits` 的 Pod 可能耗尽节点资源导致其他 Pod 被驱逐。

```yaml
resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
  limits:
    cpu: "500m"
    memory: "512Mi"

```

**用 `livenessProbe` 和 `readinessProbe` 保障流量切换**：`livenessProbe` 失败时 kubelet 重启容器，`readinessProbe` 失败时 Service 摘除该 Pod 的流量，两者配合实现零停机滚动更新。

**命名空间隔离不同环境**：用 `dev`/`staging`/`prod` 命名空间隔离资源，配合 RBAC 限制各命名空间的操作权限，避免误操作生产资源。

**`kubectl apply` 优于 `kubectl create`**：`apply` 是声明式更新，支持 GitOps 工作流；`create` 只能用于首次创建，资源已存在时报错。所有资源文件纳入 Git 版本控制。

**使用 `Deployment` 而非直接管理 `Pod`**：裸 Pod 在节点故障后不会自动重建，`Deployment` 通过 ReplicaSet 保证副本数，并提供滚动更新和回滚能力。

---

## 常见陷阱

### 陷阱：Pod 一直处于 `Pending` 状态

**现象：** `kubectl get pods` 显示 Pod 长时间 Pending，无法调度到节点。  
**原因：** 常见原因：节点资源不足（CPU/内存）、节点 taint 与 Pod 无匹配 toleration、PVC 未绑定、nodeSelector 无匹配节点。  
**解决：** `kubectl describe pod <name>` 查看 Events 字段，根据 `Insufficient cpu`、`no nodes are available` 等提示定位原因。

### 陷阱：`ConfigMap` / `Secret` 更新后 Pod 内不生效

**现象：** 更新了 ConfigMap，但 Pod 内挂载的文件仍是旧值。  
**原因：** 以 `subPath` 挂载的 Volume 不会自动同步更新；环境变量注入的值在 Pod 启动时已固化。  
**解决：** 避免 `subPath`；使用环境变量时需滚动重启 Pod（`kubectl rollout restart deployment/<name>`）使新配置生效。

### 陷阱：`Service` 无法访问 Pod

**现象：** Service ClusterIP 可达但请求超时，或返回 `connection refused`。  
**原因：** Service 的 `selector` 标签与 Pod 的 `labels` 不匹配，导致 Endpoints 列表为空。  
**解决：** `kubectl get endpoints <service-name>` 检查 Endpoints，若为空则检查 selector 与 Pod labels 是否一致（区分大小写）。

---

## 参见

[Kubernetes进阶](https://blog.vercanti.com/kubernetes-jin-jie/)  
[Docker高级指南](https://blog.vercanti.com/docker-gao-ji-zhi-nan/)  
[GitHub Actions完全指南](https://blog.vercanti.com/github-actions-wan-quan-zhi-nan/)