Pod 与多容器设计
Pod:最小的调度单元
Pod 是 Kubernetes 中你能直接操作的最小单元。我的理解很简单:一个 Pod 就是一个「逻辑主机」。它里面可以有一个或多个容器,这些容器共享同一个网络栈、同一个 IPC 命名空间,还能挂载相同的存储卷。
为什么不是直接用容器?因为很多时候单个进程搞不定一件事。比如一个 Web 服务,你既要跑 Nginx 又要跑日志收集器,两者需要共享本地磁盘,必须放在同一个 Pod 里。嗯,这个设计在云原生里很常见。
我在项目中遇到过一种情况:新同事把两个需要共享 unix socket 的进程拆成了两个 Pod,结果 socket 连不上。其实只要塞进同一个 Pod,问题就解决了。
多容器共享网络和存储卷
一个 Pod 里多个容器之间的共享能力,说白了就是两点:
- 网络共享:所有容器共用一个 Pod IP、同一组端口空间。容器之间用 localhost 就能互相访问。
- 存储卷共享:通过 Volume 挂载,容器可以读写同一份数据。最常用的是 emptyDir 和 hostPath。
我曾经帮一个团队排查过问题:两个容器都在写同一个 emptyDir 里的日志文件,但因为文件锁没处理好,日志互相覆盖。解决方案是把日志写到不同路径,或者用 sidecar 统一收集。
来,看一个最基础的 Pod YAML 示例:
apiVersion: v1
kind: Pod
metadata:
name: two-container-pod
spec:
containers:
- name: nginx
image: nginx:1.25
volumeMounts:
- name: shared-log
mountPath: /var/log/nginx
- name: log-collector
image: fluentd:latest
volumeMounts:
- name: shared-log
mountPath: /logs
volumes:
- name: shared-log
emptyDir: {}
这个例子里,Nginx 把日志写进 emptyDir,fluentd 从同一目录读到日志然后发送出去。两个容器通过 Volume 实现了数据交换。
Sidecar 与 Init 容器的区别
这就是实战中经常让人混淆的地方。我先画个图,帮你在脑子里搭个模型。
画了这张图,你应该能看出两点核心区别:
- 生命周期不同:Init 容器只在 Pod 启动时按顺序执行,执行完就退出。Sidecar 容器和业务容器一起运行,除非你主动停止它。
- 用途不同:Init 容器适合做初始化工作(比如数据库建表、下载依赖)。Sidecar 适合做辅助功能(日志转发、监控、代理)。
我当年第一次用 Init 容器时犯了个傻:把一个定时任务放在 Init 容器里,结果 Pod 启动完后它自动退出了,定时任务根本没跑。后来才明白,应该用 Sidecar 或者 CronJob。
| 特性 | Init 容器 | Sidecar 容器 |
|---|---|---|
| 启动时机 | 业务容器之前 | 与业务容器同时 |
| 运行时长 | 短任务,完成后退出 | 长期运行 |
| 重启策略 | 失败后重试,直到成功 | 与普通容器一样(Always/OnFailure) |
| 典型场景 | 数据准备、权限检查、配置生成 | 日志聚合、网络代理、安全加固、健康检查 |
| 资源隔离 | 有自己的资源限制,不与其他容器共享 | 与其他容器共享 Pod 资源配额 |
实战中的选型建议
我一般这么判断:
- 如果某个工作必须在业务容器启动前完成,且完成后就不需要了 → Init 容器。
- 如果需要一个辅助进程和主进程长期共生,且两者需要共享网络或存储 → Sidecar。
还有一点我建议你记住:不要把 Init 容器写得太大。它每次 Pod 启动都要跑完,如果 Init 容器执行时间太长,Pod 会一直处于 Init:0/1 状态,不能对外服务。以前我在集群里看到大量 Pod 卡在 Init 阶段,最后查到是因为 Init 容器里装了一个巨大的 Python 包,每次启动都要下载几 GB 数据……
改成 Sidecar 后,用 lifecycle hook 来做延迟初始化,问题就解决了。
小结
Pod 的多容器设计是 Kubernetes 灵活性的基石。你想想看,一个 Pod 就像一个微型的分布式系统:Init 容器做前置工作,Sidecar 做辅助功能,业务容器专注核心逻辑。共享网络和存储让它们之间零障碍通信。嗯,掌握了这个模型,后面讲 Sidecar 注入 Secret 接口时你就知道为什么要在 Pod 里加一个容器来代理凭证——都是同一套思路。