LabHub
学习 学习路径 课程

CKAD — Kubernetes 应用开发者

Pod 为什么不是一个容器

在 LabHub 中继续学习

一句话总结

Pod 不是“装容器的盒子”,而是在同一节点上共享网络命名空间和卷、一起启动和消亡的一组进程的最小部署单元。接受这个定义,就能一次理解 init 容器和 sidecar 为何如此设计。

概念图: 在同一节点上共享网络命名空间和卷、一起启动和消亡的一组进程的最小部署单元 · 无法看到同一文件系统 · 调度可能错位 · 结束

为什么需要它

坚持一个容器对应一个进程,很快会遇到限制。Web 服务器把访问日志写入文件,日志收集器却是另一进程;应用必须有配置文件才能启动,而文件需在启动前下载。把所有内容塞进一个镜像会使其臃肿,改日志收集器也得重建应用镜像。

若拆成完全不同的 Pod,又会破坏两点:无法看到同一文件系统,并且调度可能错位。日志收集器若落在另一节点,就没有文件可读。

因此 Kubernetes 创建了中间层,把调度单元与容器单元分开。调度的是 Pod,运行的是容器。Pod 内容器位于同一节点,可通过 localhost 通信,并通过 emptyDir 看到同一目录。

工作原理

Pod spec 有两个放置容器的位置。

位置 执行时机 失败后
spec.initContainers 依次运行,直到结束 后续 init 和主容器都不启动
spec.containers 所有 init 成功后同时运行 restartPolicy 重启

init 容器的目标是“完成”,用于下载配置、数据库迁移、等待前置服务等。列出三个时,必须第一个结束后才启动第二个。任何一个不结束,Pod 会永远停在 Init:1/3 等状态,主容器甚至不会开始运行

过去存在一个问题:sidecar(日志收集器、代理)必须持续运行,不能放在 init 位置;放进 containers 又会与主容器同时启动,可能在主容器开始写日志后收集器才就绪。Job Pod 中更严重:主容器结束后 sidecar 仍存活,使 Job 永远无法完成。

原生 sidecar解决了这个问题:仍放在 initContainers 列表中,但仅为该容器设置 restartPolicy: Always

spec:
  initContainers:
    - name: logger
      image: busybox:1.36
      restartPolicy: Always     # ← 이 한 줄이 네이티브 사이드카로 만든다
      command: ["sh", "-c", "tail -F /var/log/nginx/access.log"]
  containers:
    - name: web
      image: nginx:1.27

这样三项条件同时成立:比主容器启动、持续存活,并在 Job 主容器结束时一起退出

模式名称也应区分。sidecar 辅助主容器功能(日志、指标);ambassador 作为主容器访问外部时的代理(连接 localhost:6379 后路由到真实集群);adapter 把主容器输出转换成外部所需格式(应用日志 → Prometheus 指标)。

实际现场中的情况

在家庭实验室的 7 节点集群安装 NVIDIA GPU Operator 后,所有 GPU 相关 Pod 都处于如下状态。

gpu-feature-discovery-fpw5l            0/1   Init:0/1
nvidia-dcgm-exporter-gmlvl             0/1   Init:0/1
nvidia-device-plugin-daemonset-k4ggb   0/1   Init:0/1
nvidia-operator-validator-krj69        0/1   Init:0/4

0/10/4 表示一个 init 容器都未通过,主容器甚至还没被提及。查看事件后,原因不在容器内部,而在外部。

Warning FailedCreatePodSandBox  desc = failed to get sandbox runtime:
        no runtime for "nvidia" is configured

故障发生在创建容纳 Pod 的沙箱阶段。失败的不是容器,而是创建容器共享的网络与 IPC 命名空间这一阶段。Pod 是“进程组”的定义在这里完全显现:连组的容器空间都建不起来,其中任何容器都不会启动。

另一次是在同一集群安装 KubeVirt。组件状态全为 AllComponentsReady,VM 却无法启动。检查 virt-launcher Pod spec 后发现,缺少包含 init 容器所需二进制文件的卷挂载。init 无法结束,主容器就永远等待。这已经是该集群第三次证明“状态 Ready”和“实际工作”是不同命题。

下一项实验要做什么

ckad-design 命名空间创建 Pod、标签、注解、命令覆盖、环境变量和 restartPolicy,亲自填写 Job 的 completions/parallelism/backoffLimit 与 CronJob 的 schedule/concurrencyPolicy/startingDeadlineSeconds。后续实验将在 ckad-multi 命名空间手工实现 init 容器顺序、原生 sidecar、ambassador/adapter 模式、共享 emptyDirterminationGracePeriodSeconds