--- tags: [k8s, pod, devops] create time: 2026-07-07 15:48 --- # Pod — Kubernetes 最小调度单元 ## 概述 Pod 是 Kubernetes 中**最小的可部署和调度单元**。它不是一个容器,而是一组(一个或多个)共享网络和存储资源的容器的逻辑封装。为什么 Kubernetes 不直接调度容器,而是引入了 Pod 这一抽象层?因为在实际业务中,多个紧密协作的进程往往需要共享同一个 IP 地址、端口空间和卷挂载——比如一个 Web 应用容器和一个负责收集日志的 sidecar 容器。Pod 正是为了解决这种「亲密耦合进程协同运行」的需求而设计的。理解 Pod,是掌握 Kubernetes 一切上层抽象(Deployment、StatefulSet、DaemonSet 等)的基础。 ## Pod 的本质 ### 共享网络命名空间 同一个 Pod 内的所有容器共享**同一个网络命名空间(Network Namespace)**,这意味着: - 它们拥有**相同的 IP 地址** - 它们可以**通过 localhost 互相通信** - 端口空间是共享的,因此同一 Pod 内的容器**不能绑定相同的端口** > [!question] 为什么不直接调度容器? > 因为单个容器通常只运行一个进程(这是容器设计的最佳实践)。但在很多场景下,多个进程需要紧密协作——比如 Nginx + 日志收集器、主应用 + 配置热加载 sidecar。如果让调度器去理解「哪些容器应该放在一起」,复杂度会急剧上升。Pod 将这个决策交给了用户:你来决定哪些容器属于同一个 Pod。 ### Pause 容器 — Pod 的「灵魂」 每个 Kubernetes Pod 启动时,都会先创建一个特殊的**Pause 容器**(也叫 infra 容器),它是 Pod 的第一个容器,也是整个 Pod 的「根进程」。其他业务容器通过加入 Pause 容器的 Network Namespace 和 PID Namespace 来实现共享。 ```mermaid graph TB subgraph Pod P["Pause 容器
(infra container)"] C1["业务容器 A"] C2["业务容器 B
(sidecar)"] C3["业务容器 C"] end P -->|"提供 Network NS"| C1 P -->|"提供 Network NS"| C2 P -->|"提供 Network NS"| C3 P -->|"提供 PID NS (可选)"| C1 P -->|"提供 PID NS (可选)"| C2 P -->|"提供 PID NS (可选)"| C3 ``` Pause 容器的职责非常简单: 1. **持有 Network Namespace** — 确保 Pod 的 IP 地址在所有容器生命周期内保持不变 2. **充当 PID 1** — 回收僵尸进程(zombie reaping) 3. **极轻量** — 通常只有几百 KB,使用 `registry.k8s.io/pause` 镜像 > [!info] Pause 容器的代码只有几百行 > 它的核心逻辑就是一个无限循环的 `pause()` 系统调用。正因为足够简单,它几乎不会出问题,可以稳定地为 Pod 内所有容器提供基础运行环境。 ### 容器与 Pod 的关系(1:N) 一个 Pod 可以包含多个容器,典型模式如下: | 模式 | 说明 | 示例 | |------|------|------| | 单容器 Pod | 最常见的场景,一个 Pod 运行一个应用容器 | 一个 Go Web 服务 | | 多容器 Pod (sidecar) | 主容器 + 辅助容器,辅助容器扩展主容器功能 | Nginx + Filebeat 日志收集 | | 多容器 Pod (adapter) | 辅助容器将主容器的输出转换为标准格式 | 应用日志 → Fluentd 标准格式 | | 多容器 Pod (ambassador) | 辅助容器代理网络请求 | 应用 → Envoy Proxy → 外部服务 | ```yaml # 一个多容器 Pod 的简单示例:Web 服务 + 日志收集 sidecar apiVersion: v1 kind: Pod metadata: name: web-with-logging spec: containers: - name: web image: nginx:1.25 ports: - containerPort: 80 volumeMounts: - name: log-volume mountPath: /var/log/nginx - name: log-collector image: fluent/fluent-bit:latest volumeMounts: - name: log-volume mountPath: /var/log/nginx readOnly: true volumes: - name: log-volume emptyDir: {} ``` 两个容器共享 `log-volume` 卷,Web 容器写入日志,Fluent Bit 容器读取并转发——这是经典的日志收集 sidecar 模式。 ## Pod 生命周期 Pod 的生命周期由**阶段(Phase)**和**条件(Condition)**共同描述。从创建到销毁,Pod 经历以下主要阶段: ```mermaid stateDiagram-v2 [*] --> Pending: kubectl apply / API 创建 Pending --> Running: 至少一个容器启动成功 Pending --> Failed: 拉取镜像失败 / 调度失败 Running --> Succeeded: 所有容器正常退出(exit 0) Running --> Failed: 容器异常退出 / OOMKilled Running --> Unknown: Node 失联, 无法获取状态 Succeeded --> [*] Failed --> [*] Unknown --> Running: Node 恢复通信 Unknown --> Failed: 确认 Pod 已丢失 ``` ### Init Containers Init Containers 是在**主容器启动之前**按顺序运行的容器。它们主要用于完成一些前置条件的检查和准备工作。 **与主容器的区别:** | 特性 | Init Container | 主容器 (App Container) | |------|---------------|----------------------| | 执行顺序 | 严格按顺序依次执行 | 并行启动 | | 失败行为 | 失败后 Pod 重启(遵循 restartPolicy) | 失败后根据探针配置重启 | | 探针支持 | 不支持 liveness/readiness probe | 支持 | | 用途 | 前置条件检查、等待依赖、初始化配置 | 运行业务逻辑 | | 资源计算 | 独立于主容器的资源请求 | 作为整体调度依据 | > [!tip] 何时使用 Init Container? > 当你需要在主容器启动前完成某些「只执行一次」的任务时——比如等待数据库就绪、下载配置文件、执行数据库迁移等——Init Container 是最佳选择。 ```yaml apiVersion: v1 kind: Pod metadata: name: app-with-init spec: initContainers: # 第一个 Init Container:等待数据库就绪 - name: wait-for-db image: busybox:1.36 command: - sh - -c - | until nc -z mysql-service 3306; do echo "Waiting for MySQL..." sleep 2 done echo "MySQL is ready!" # 第二个 Init Container:执行数据库迁移 - name: db-migration image: myapp/migration:v1.2 env: - name: DB_HOST value: "mysql-service" containers: - name: app image: myapp/api:v1.2 ports: - containerPort: 8080 ``` 上述示例中,两个 Init Container **严格按顺序**执行:先等 MySQL 可达,再执行数据库迁移。只有两者都成功(exit 0)后,主容器 `app` 才会启动。 ### 容器探针 Kubernetes 提供三种探针来监控容器的健康状态: | 探针类型 | 作用 | 失败后果 | 典型场景 | |---------|------|---------|---------| | `livenessProbe` | 检测容器是否**存活** | 杀死容器并重启 | 进程死锁、无限循环 | | `readinessProbe` | 检测容器是否**就绪**接收流量 | 从 Service 的 Endpoints 中移除 | 启动预热、临时过载 | | `startupProbe` | 检测容器是否**启动完成** | 杀死容器并重启 | 启动耗时长的应用(如 Java) | > [!warning] startupProbe 与 livenessProbe 的关系 > 当配置了 `startupProbe` 时,在它成功之前,`livenessProbe` 和 `readinessProbe` 都不会执行。这是为了防止启动时间较长的应用被误判为不健康。`startupProbe` 的 `failureThreshold * periodSeconds` 应该大于应用的最大启动时间。 **探针支持的检测方式:** - **httpGet** — 发送 HTTP GET 请求,2xx/3xx 视为成功 - **tcpSocket** — 尝试 TCP 连接,端口可达视为成功 - **exec** — 执行命令,exit code 0 视为成功 - **grpc** — gRPC 健康检查协议(Kubernetes 1.24+) ```yaml apiVersion: v1 kind: Pod metadata: name: probes-demo spec: containers: - name: app image: myapp:v1 ports: - containerPort: 8080 # 启动探针:最多给 60 秒启动时间 (10 次 x 6 秒) startupProbe: httpGet: path: /healthz port: 8080 failureThreshold: 10 periodSeconds: 6 # 存活探针:每 15 秒检测一次,连续 3 次失败则重启 livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 0 # startupProbe 成功后才开始 periodSeconds: 15 failureThreshold: 3 timeoutSeconds: 5 # 就绪探针:每 5 秒检测一次,失败则从 Endpoints 移除 readinessProbe: httpGet: path: /ready port: 8080 periodSeconds: 5 failureThreshold: 3 timeoutSeconds: 3 ``` > [!tip] 最佳实践 > 生产环境中建议同时配置三种探针:`startupProbe` 保护慢启动应用、`livenessProbe` 检测死锁、`readinessProbe` 控制流量切换。`readinessProbe` 的检测频率可以比 `livenessProbe` 更高,因为它的失败不会触发重启。 ### Pod 阶段(Phase)与条件(Condition) **Pod Phase** 是对 Pod 在其生命周期中所处位置的高层概括: | Phase | 说明 | |-------|------| | `Pending` | Pod 已被 API Server 接受,但尚未调度或容器镜像未拉取完成 | | `Running` | Pod 已绑定到节点,且至少有一个容器处于运行状态 | | `Succeeded` | 所有容器正常退出(exit 0),不会再重启 | | `Failed` | 所有容器已终止,且至少有一个容器是非正常退出 | | `Unknown` | 无法获取 Pod 状态,通常是与 Node 的通信中断 | **Pod Conditions** 提供了更细粒度的状态信息,是一个数组,每个 Condition 包含以下字段: ```yaml conditions: - type: PodScheduled # 条件类型 status: "True" # True / False / Unknown lastProbeTime: null # 上次探测时间 lastTransitionTime: "2026-07-07T07:00:00Z" # 上次状态转换时间 reason: "SchedulerCompletedSchedulingReason" message: "Successfully assigned default/my-pod to node-1" ``` 常见的 Condition Type: | Type | 说明 | |------|------| | `PodScheduled` | Pod 已被调度到某个节点 | | `Initialized` | 所有 Init Container 已成功完成 | | `ContainersReady` | 所有容器都已就绪 | | `Ready` | Pod 可以对外提供服务,被纳入 Service Endpoints | ```mermaid graph LR A["PodScheduled
status: True"] --> B["Initialized
status: True"] B --> C["ContainersReady
status: True"] C --> D["Ready
status: True"] ``` > [!info] Condition vs Phase > Phase 是一个全局性的、互斥的状态值(一个 Pod 在同一时刻只有一个 Phase)。而 Conditions 是一组独立的布尔标志,一个 Pod 可以同时有多个 Condition 为 True。Conditions 通常用于精确排查 Pod 启动过程中的具体卡点。 ## 资源管理 ### Requests 与 Limits Kubernetes 通过 `requests` 和 `limits` 两个维度来管理容器的资源: - **requests(请求量)** — 调度器依据此值决定 Pod 放到哪个节点。是容器运行所需的**最小**资源量 - **limits(限制量)** — 容器可使用的**最大**资源量。超出限制时的行为取决于资源类型 ```yaml resources: requests: cpu: "250m" # 0.25 核 memory: "128Mi" # 128 MiB limits: cpu: "500m" # 0.5 核 memory: "256Mi" # 256 MiB ``` > [!question] CPU 超限和 Memory 超限的处理方式为什么不同? > CPU 是**可压缩资源(compressible)**——超出 limit 时会被节流(throttle),进程不会被杀死。而内存是**不可压缩资源(incompressible)**——超出 limit 时进程会被 OOMKilled。这是因为 CPU 可以通过时间片轮转来降级服务,但内存一旦不足,系统无法「回收」已分配的内存页面。 ### QoS(Quality of Service)三级分类 Kubernetes 根据 requests 和 limits 的配置将 Pod 分为三个 QoS 等级: | QoS 等级 | 条件 | OOM 优先级 | 调度优先级 | |----------|------|-----------|-----------| | **Guaranteed** | 每个容器的 requests == limits | 最低(最后被杀) | 最高 | | **Burstable** | 至少一个容器设置了 requests,且 requests < limits | 中等 | 中等 | | **BestEffort** | 所有容器均未设置 requests 和 limits | 最高(最先被杀) | 最低 | ```yaml # Guaranteed — requests 等于 limits containers: - name: critical-app resources: requests: cpu: "1" memory: "1Gi" limits: cpu: "1" memory: "1Gi" --- # Burstable — requests 小于 limits containers: - name: normal-app resources: requests: cpu: "250m" memory: "128Mi" limits: cpu: "1" memory: "512Mi" --- # BestEffort — 未设置任何 requests / limits containers: - name: batch-job image: busybox # 未配置 resources 字段 ``` > [!warning] 生产环境严禁 BestEffort > BestEffort Pod 在节点资源紧张时会被**最先驱逐**。在生产环境中,至少应为所有容器设置合理的 `requests`。 ### OOM(Out of Memory)行为 当节点内存不足时,kubelet 会按照以下顺序选择 Pod 进行驱逐: 1. **BestEffort** Pod(OOM Score 最高) 2. **Burstable** Pod 中,实际内存使用量超过 requests 最多的 3. **Guaranteed** Pod(OOM Score 最低,最后被杀) 同时,Linux 内核的 OOM Killer 也会根据进程的 `oom_score_adj` 值来决定杀哪个进程。Kubernetes 为不同 QoS 等级的容器设置了不同的 `oom_score_adj`: | QoS 等级 | oom_score_adj | |----------|--------------| | Guaranteed | -998 | | Burstable | 2 ~ 1000(按比例) | | BestEffort | 1000 | ### CPU 节流机制 当容器的 CPU 使用超过 limit 时,Linux 内核的 CFS(Completely Fair Scheduler)会通过 **CFS Bandwidth Throttling** 机制限制容器的 CPU 时间片分配。 表现症状: - 容器进程运行变慢,响应延迟升高 - `container_cpu_cfs_throttled_periods_total` 指标持续增长 - 应用程序的 P99 延迟出现周期性毛刺 > [!tip] 避免 CPU 节流 > 如果发现应用延迟升高且 CPU throttling 严重,考虑:① 提高 CPU limit;② 将 limit 设置为与 request 相同(Guaranteed QoS,不会被节流但调度更严格);③ 使用 `CPU Manager Policy: static` 获得独占 CPU 核心。 ## Sidecar 模式 Sidecar 模式是 Pod 多容器设计中最常用的架构模式。通过在 Pod 中添加辅助容器(sidecar),可以在不修改主应用代码的前提下扩展其功能。 ### 日志收集 ```yaml apiVersion: v1 kind: Pod metadata: name: app-logging-sidecar spec: containers: - name: app image: myapp:v2 volumeMounts: - name: shared-logs mountPath: /var/log/app - name: log-shipper image: fluent/fluent-bit:2.2 volumeMounts: - name: shared-logs mountPath: /var/log/app readOnly: true - name: fluentbit-config mountPath: /fluent-bit/etc/ resources: requests: cpu: "50m" memory: "64Mi" limits: cpu: "200m" memory: "128Mi" volumes: - name: shared-logs emptyDir: {} - name: fluentbit-config configMap: name: fluentbit-config ``` ### 服务网格代理(Service Mesh Proxy) 这是 Istio、Linkerd 等服务网格的典型数据面模式——每个应用 Pod 旁注入一个 Envoy sidecar 代理: ```yaml apiVersion: v1 kind: Pod metadata: name: app-with-proxy annotations: sidecar.istio.io/inject: "true" spec: containers: - name: app image: myapp:v3 ports: - containerPort: 8080 # 以下通常由 Istio 自动注入,这里手动展示 - name: istio-proxy image: envoyproxy/envoy:v1.28 args: - proxy - sidecar - --domain - $(POD_NAMESPACE).svc.cluster.local ports: - containerPort: 15001 # Envoy 入口 - containerPort: 15006 # Envoy 出口 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace ``` ### 配置热更新(Reloader Sidecar) 某些应用不支持热加载配置文件,此时可以用一个 sidecar 监听 ConfigMap 变化并通知主容器: ```yaml apiVersion: v1 kind: Pod metadata: name: app-config-reload spec: containers: - name: app image: nginx:1.25 volumeMounts: - name: config-volume mountPath: /etc/nginx/conf.d - name: config-reloader image: jimmidyson/configmap-reload:v0.13 args: - --volume-dir=/config - --webhook-url=http://localhost:8080/-/reload volumeMounts: - name: config-volume mountPath: /config readOnly: true volumes: - name: config-volume configMap: name: nginx-config ``` ## Pod 调度基础 Kubernetes 调度器(kube-scheduler)负责将 Pod 分配到合适的节点上。Pod 本身可以通过以下字段影响调度决策: ### nodeSelector 最简单的调度约束,通过标签匹配将 Pod 调度到特定节点: ```yaml apiVersion: v1 kind: Pod metadata: name: gpu-task spec: nodeSelector: gpu: "true" # 必须调度到带有 gpu=true 标签的节点 disktype: "ssd" containers: - name: ml-trainer image: pytorch:v2 ``` ### nodeName 直接指定节点名称,**跳过调度器**: ```yaml spec: nodeName: node-3 # 直接绑定到 node-3,不经过调度器 ``` > [!warning] 慎用 nodeName > 使用 `nodeName` 会绕过调度器的资源检查、亲和性计算和污点容忍判断。如果目标节点资源不足,Pod 会一直处于 Pending 状态。一般仅用于测试或特殊运维场景。 ### 亲和性(Affinity)简介 亲和性提供了比 `nodeSelector` 更丰富的调度规则: - **nodeAffinity** — 节点亲和性,支持硬性(required)和软性(preferred)规则 - **podAffinity** — Pod 亲和性,将 Pod 调度到与其他 Pod 相近的位置 - **podAntiAffinity** — Pod 反亲和性,将 Pod 调度到与其他 Pod 远离的位置 ```yaml affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: # 硬性要求 nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/arch operator: In values: - amd64 preferredDuringSchedulingIgnoredDuringExecution: # 软性偏好 - weight: 80 preference: matchExpressions: - key: zone operator: In values: - cn-east-1a ``` > [!info] 深入阅读 > 调度器的完整机制(包括 Taint/Toleration、PriorityClass、拓扑分布约束等)将在 [[k8s-scheduler]] 中详细展开。 ## 静态 Pod(Static Pod) 静态 Pod 是由 **kubelet 直接管理**的 Pod,不通过 API Server 创建。kubelet 会监视指定目录(默认为 `/etc/kubernetes/manifests/`)中的 YAML 文件,并自动创建和维护对应的 Pod。 ### 特点 | 特性 | 静态 Pod | 普通 Pod | |------|---------|---------| | 管理者 | kubelet | API Server / Controller Manager | | 存储位置 | 节点本地文件系统 | etcd | | 是否出现在 API Server 中 | 是(kubelet 创建 mirror pod) | 是 | | 是否受控制器管理 | 否 | 是(Deployment、StatefulSet 等) | | 是否可被 kubectl 删除 | 否(需删除文件) | 是 | ### 用途 静态 Pod 最重要的用途是**部署控制平面组件**: ```bash # kubeadm 部署的集群中,控制平面组件都是静态 Pod /etc/kubernetes/manifests/ ├── kube-apiserver.yaml ├── kube-controller-manager.yaml ├── kube-scheduler.yaml └── etcd.yaml ``` ```yaml # /etc/kubernetes/manifests/kube-apiserver.yaml(简化示例) apiVersion: v1 kind: Pod metadata: name: kube-apiserver namespace: kube-system labels: component: kube-apiserver spec: containers: - name: kube-apiserver image: registry.k8s.io/kube-apiserver:v1.30.0 command: - kube-apiserver - --advertise-address=192.168.1.10 - --etcd-servers=https://127.0.0.1:2379 - --service-cluster-ip-range=10.96.0.0/12 ports: - containerPort: 6443 hostNetwork: true ``` > [!info] 为什么控制平面用静态 Pod? > 这是一个「鸡生蛋」的问题:kube-apiserver 是 Kubernetes 集群的核心,如果 kube-apiserver 本身也依赖 API Server 来创建,那集群就无法启动。静态 Pod 由 kubelet 独立管理,不依赖 API Server,因此可以用来部署 API Server 本身。 ## 常见陷阱与最佳实践 ### 镜像拉取策略(imagePullPolicy) | 策略 | 行为 | 适用场景 | |------|------|---------| | `Always` | 每次创建 Pod 都拉取镜像 | 使用 `:latest` 标签时(默认策略) | | `IfNotPresent` | 本地不存在时才拉取 | 使用固定版本标签(如 `:v1.2.3`) | | `Never` | 从不拉取,仅使用本地镜像 | 离线环境或测试场景 | ```yaml containers: - name: app image: myapp:v1.2.3 # 使用固定标签 imagePullPolicy: IfNotPresent # 推荐:避免不必要的拉取 ``` > [!warning] :latest 标签陷阱 > 当镜像标签为 `:latest` 或不指定标签时,`imagePullPolicy` 默认为 `Always`。这意味着每次 Pod 重建都会重新拉取镜像,带来不确定性。**生产环境必须使用固定版本标签**(如 `:v1.2.3` 或 SHA256 digest)。 ### 优雅终止(Graceful Shutdown) 当 Kubernetes 删除一个 Pod 时,会经历以下流程: ```mermaid sequenceDiagram participant User as 用户/API participant API as API Server participant Kubelet as kubelet participant App as 应用进程 User->>API: 删除 Pod API->>Kubelet: 标记 Pod 为 Terminating Note over API: 从 Service Endpoints 移除 Kubelet->>App: 执行 preStop hook App-->>App: 执行清理逻辑 App-->>Kubelet: preStop 完成 Kubelet->>App: 发送 SIGTERM 信号 App-->>App: 开始优雅关闭 alt 在 terminationGracePeriodSeconds 内退出 App-->>Kubelet: 进程正常退出 else 超时未退出 Kubelet->>App: 发送 SIGKILL 强制杀死 end ``` **关键配置项:** ```yaml apiVersion: v1 kind: Pod metadata: name: graceful-demo spec: terminationGracePeriodSeconds: 60 # 默认 30s,给足够时间清理 containers: - name: app image: myapp:v1 lifecycle: preStop: exec: command: - /bin/sh - -c - | # 1. 通知应用停止接收新请求 curl -s http://localhost:8080/admin/drain # 2. 等待正在进行的请求处理完成 sleep 15 # 3. 关闭数据库连接池 echo "Shutting down gracefully..." ``` > [!tip] preStop 的妙用 > preStop hook 在 SIGTERM 之前执行,可以用来做「通知式关闭」——比如先从注册中心注销、停止接收新连接、等待进行中的请求完成。配合 `terminationGracePeriodSeconds` 调大值,可以实现零请求丢失的优雅关闭。 ### PID 1 信号问题 在 Linux 中,PID 1 进程有特殊行为:**默认不响应 SIGTERM 信号**(为了兼容 init 系统)。如果容器的入口进程是 shell 脚本,shell 不会将 SIGTERM 转发给子进程,导致容器无法优雅退出。 **问题示例:** ```dockerfile # 有问题的 Dockerfile FROM node:20 COPY server.js . CMD node server.js # node 进程成为 PID 1,但不一定正确处理信号 ``` **解决方案:** ```dockerfile # 方案 1:使用 exec 形式(推荐) CMD ["node", "server.js"] # node 直接成为 PID 1 # 方案 2:使用 tini 作为 init 进程 RUN apt-get update && apt-get install -y tini ENTRYPOINT ["tini", "--"] CMD ["node", "server.js"] # 方案 3:在 Pod Spec 中设置(Kubernetes 1.28+) # 通过 feature gate: SidecarContainers ``` ```yaml # 方案 3:Pod 级别的 init 进程设置 apiVersion: v1 kind: Pod metadata: name: signal-demo spec: # Kubernetes 1.28+ 支持设置 Pod 的 PID namespace # 确保 PID 1 被正确处理 containers: - name: app image: myapp:v1 ``` ### 其他注意事项 - **不要在同一 Pod 内运行多个不相关的服务** — 这违反了 Pod 的设计初衷,应该拆分为多个 Pod - **使用 Liveness Probe 要谨慎** — 错误的 liveness 探针配置会导致容器反复重启(restart loop),建议先用 readiness 验证探针逻辑 - **设置资源 requests** — 不设 requests 的 Pod 会变成 BestEffort QoS,在节点压力下最先被驱逐 - **避免使用 hostNetwork** — 除非必要(如 CNI 插件、Ingress Controller),否则不要使用 hostNetwork,它会占用宿主机端口并绕过 Kubernetes 网络策略 ## 延伸阅读 - [[k8s-02-architecture]] — Kubernetes 整体架构,理解 Pod 在集群中的位置 - [[k8s-04-deployment-and-replicaset]] — Deployment 如何管理 Pod 的副本与滚动更新 - [[k8s-scheduler]] — 调度器完整机制,包括亲和性、污点容忍、拓扑分布等