bigywater.tech
Kubernetes · 85

pause 容器:Pod 共享的命名空间从哪来

Pod 里的容器为什么能用 localhost 互相访问?pause 容器到底在做什么?杀掉它会怎样?这篇在节点上读命名空间编号、做端口冲突实验、分别杀容器和杀 pause,把“Pod 就是一组共享命名空间的容器”落到实处。

3 个共享
pause 与容器共享 net / ipc / uts 命名空间编号;pid、mnt、cgroup 各不相同
504 kB
pause 进程的常驻内存;镜像只有 268kB
IP 换了 uid 不换
杀掉 pause 沙箱后,Pod IP 变化而 Pod 的 uid 不变

谁和谁共享

实测 · 本机执行输出
  命名空间           pause           a           b   a==pause?  b==pause?
  net       4026534862  4026534862  4026534862   相同         相同
  ipc       4026534994  4026534994  4026534994   相同         相同
  uts       4026534993  4026534993  4026534993   相同         相同
  pid       4026534995  4026534997  4026535000   不同         不同
  mnt       4026534992  4026534996  4026534999   不同         不同
  cgroup    4026532604  4026534998  4026535001   不同         不同
  user      4026531837  4026531837  4026531837   相同         相同
  结论:net / ipc / uts 三个由 pause 创建并共享;pid、mnt、cgroup 每个容器自己一份(默认)
  pause 进程:/pause;State: S (sleeping);VmRSS: 504 kB(几乎不占资源)
  pause 镜像:registry.k8s.io/pause 3.10 afb61768ce381 268kB

读 /proc/<PID>/ns/* 的编号:pause、容器 a、容器 b 的 net(4026534862)、ipc(4026534994)、uts(4026534993)完全一样;pid、mnt、cgroup 三个各不相同。pause 进程就是 /pause,状态 S (sleeping),VmRSS 只有 504 kB;镜像 registry.k8s.io/pause:3.10 只有 268kB。共享的三个命名空间是它在沙箱里先创建出来、容器再加入的。

共享网络的后果

实测 · 本机执行输出
  容器 b 用 localhost:8080 访问容器 a 的 httpd:'hi'
  容器 b 也想监听 8080:httpd: bind: Address already in use 退出码 1
  两个容器看到的 eth0 地址:a=10.244.1.239/24 b=10.244.1.239/24(同一个)
  文件系统各是各的:b 读 /tmp/a-file → cat: can't open '/tmp/a-file': No such file or directory command terminated with
  进程各是各的:b 里 ps 只看到 2 个进程(自己的 sleep 和 ps)

容器 b 用 127.0.0.1:8080 访问到容器 a 的 httpd(返回 hi);b 自己再监听 8080 则失败(bind: Address already in use,退出码 1);两个容器看到同一个 eth0 地址 10.244.1.239/24。但文件系统各自独立(b 读不到 a 的 /tmp/a-file),进程也各自独立(b 里 ps 只有自己的 sleep 和 ps)。共享文件要用卷,共享进程要 shareProcessNamespace(下一篇)。

IP 跟着 pause

实测 · 本机执行输出
  只停容器 a:0.4 秒内 kubelet 重启它(restartCount=1);Pod IP 10.244.1.239 → 10.244.1.239(没变,pause 还活着,网络命名空间还在)
  直接 kill -9 pause 进程(PID 229704):kubelet 2.9 秒内新建了一个沙箱(id d6856072… → 85e6b201…);Pod IP 10.244.1.239 → 10.244.1.240;两个容器的 restartCount=[1, 1];Pod uid 不变:True

只停容器 a(crictl stop):0.4 秒内 kubelet 就重启它,Pod IP 不变——pause 还活着,网络命名空间还在。直接 kill -9 沙箱的 pause 进程:2.9 秒内 kubelet 新建了沙箱(id 从 d6856072… 变成 85e6b201…),Pod IP 变成 10.244.1.240,但 Pod 的 uid 不变。所以“重启容器”和“重建沙箱”是两个层次:前者保留 IP,后者不保留。

分步演示

pause 容器
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0,pause 镜像 3.10);Pod 固定在 worker;PID 取自 crictl inspect / inspectp,命名空间编号取自节点上的 readlink /proc//ns/*;kill -9 直接在节点上对 pause 的 PID 执行;每种情形各一次
    • 没有验证:pause 在 PID 命名空间共享时作为 init 回收僵尸进程的行为(下一篇涉及共享进程);hostNetwork Pod 是否仍有沙箱;kill pause 后 restartCount 的变化(实验中两个容器的 restartCount 都是 1,没有深入解释);沙箱重建时 CNI 的 DEL/ADD 顺序;其他运行时(Kata、gVisor)的沙箱模型;pause 镜像版本与 kubelet 的 --pod-infra-container-image 参数
    京ICP备2026067502号-1京公网安备11010502063487号