bigywater.tech
Kubernetes · 87

hostNetwork、hostPID:Pod 与宿主机的边界

给 Pod 加 hostNetwork / hostPID / hostIPC 到底打通了什么?host 开头的字段彼此独立吗?DNS 为什么会变?hostPort 和 hostNetwork 有什么区别?这篇读命名空间编号、做端口冲突和 DNS 对照,把边界一项项量出来。

各打通一个
hostNetwork 对应 net+uts,hostPID 对应 pid,hostIPC 对应 ipc;mnt 始终是容器自己的
172.18.0.2
hostNetwork Pod 的 IP,就是节点 IP
34 行 vs 6 行
hostPID 与默认 Pod 里 ps 看到的进程行数

命名空间编号对照

实测 · 本机执行输出
                      net          pid          ipc          uts          mnt   与节点相同的
  节点           4026532605   4026532603   4026532602   4026532601   4026532596
  plain        4026534862   4026535272   4026535257   4026535256   4026535271   
  hnet         4026532605   4026535269   4026535253   4026532601   4026535268   net,uts
  hpid         4026534992   4026532603   4026535264   4026535263   4026535280   pid
  hipc         4026535120   4026535278   4026532602   4026535266   4026535277   ipc

读 /proc/self/ns/*:节点的 net=4026532605、pid=4026532603、ipc=4026532602、uts=4026532601。plain 的五个编号全都和节点不同;hnet(hostNetwork)与节点相同的是 net 和 uts;hpid(hostPID)是 pid;hipc(hostIPC)是 ipc。每个开关只打通对应的命名空间,mnt 始终是容器自己的。

hostNetwork

实测 · 本机执行输出
  plain 的 IP=10.244.1.247;hnet 的 IP=172.18.0.2(= 节点 IP:True)
  hnet 里的 hostname=kx-main-worker(节点名);plain 里的 hostname=plain(Pod 名)
  hnet 里 ip addr 的网卡数 15,plain 里 11
  hnet 里 netstat 能看到节点上 kubelet 等已经在监听的端口:'tcp 0 0 127.0.0.1:10248 0.0.0.0:* LISTEN\ntcp 0 0 :::10250 :::* LISTEN\ntcp 0 0 :::10256 :::* LISTEN'
  hnet 里再监听 10250:nc: bind: Address already in use 退出码 1
  plain 里监听 10250:punt! Terminated 退出码 143(自己的网络命名空间,不冲突)
  DNS:hnet(dnsPolicy 默认 ClusterFirst,hostNetwork 下实际退回 Default)的 nameserver <本机局域网IP>;解析 kubernetes.default:;; connection timed out; no servers could be reached
    hnet-dns(dnsPolicy: ClusterFirstWithHostNet)的 nameserver 10.96.0.10;解析:Name: kubernetes.default.svc.cluster.local Address: 10.96.0.1

hostNetwork 下 Pod 的 IP 就是节点 IP(172.18.0.2),hostname 是节点名 kx-main-worker,ip link 能看到 15 个网卡(默认 Pod 里 11 个);netstat 能看到节点上 kubelet 监听的 10250、10248、10256;在里面再监听 10250 失败(Address already in use),默认 Pod 里监听 10250 则不冲突。DNS 也变了:dnsPolicy 默认的 ClusterFirst 在 hostNetwork 下实际退回节点的 DNS(nameserver 192.168.65.254),解析 kubernetes.default 超时;改成 ClusterFirstWithHostNet 后 nameserver 是 10.96.0.10,解析得到 10.96.0.1。

hostPID 与 hostIPC

实测 · 本机执行输出
  plain 里 ps 的行数 6;hpid 里 34(节点上的所有进程)
  hpid 里能看到节点上的进程:'130 /usr/local/bin/containerd\n  294 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id c5dba3b8f72e4ec63450ee8\n  305 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 1113e06634e03d024d66641'
  hpid 里 PID 1:systemd(节点的 init;plain 里的 PID 1 是 sleep)
  hipc 与节点共享 IPC 命名空间(见上表的 ipc 列编号相同);plain 的 ipc 编号与节点不同

hostPID 的 Pod 里 ps 有 34 行(默认 Pod 里 6 行),能看到节点上的 containerd 和 containerd-shim-runc-v2,PID 1 是 systemd(默认 Pod 里是 sleep)。hostIPC 与节点共享 ipc 命名空间(编号相同),同节点进程能通过 SysV 共享内存、信号量、消息队列互通。这两个开关一般只给监控代理、调试工具用。

hostPort 不是 hostNetwork

实测 · 本机执行输出
  Pod hport(hostPort: 8081,nginx 监听 80)在 worker 上;从控制面节点访问 172.18.0.2:8081 → HTTP 200
  worker 的 nat 表里(portmap 插件写的):
    -A PREROUTING -m addrtype --dst-type LOCAL -j CNI-HOSTPORT-DNAT
    -A OUTPUT -m addrtype --dst-type LOCAL -j CNI-HOSTPORT-DNAT
    -A CNI-DN-2c1d17cfc2374c344aad2 -s 10.244.1.0/24 -p tcp -m tcp --dport 8081 -j CNI-HOSTPORT-SETMARK
    -A CNI-DN-2c1d17cfc2374c344aad2 -s 127.0.0.1/32 -p tcp -m tcp --dport 8081 -j CNI-HOSTPORT-SETMARK
  hport 的 Pod IP=10.244.1.250(仍是 Pod 自己的 IP,不是节点 IP);容器里 ip 网卡数 11
  同一个节点上第二个要 hostPort 8081 的 Pod:phase=Failed;NodePorts
    事件:["5s Warning NodePorts pod/hport2 Predicate NodePorts failed: node(s) didn't have free ports for the requested pod ports"]

hostPort: 8081(nginx 监听 80)只是端口映射:从控制面节点访问 172.18.0.2:8081 得到 HTTP 200,worker 的 nat 表里有 portmap 插件写的 CNI-HOSTPORT-DNAT 链和 CNI-DN-… 链里 --dport 8081 的规则;Pod IP 仍是自己的 10.244.1.250,容器里还是 11 个网卡。同一节点上第二个要 hostPort 8081 的 Pod 直接 Failed,事件是 Predicate NodePorts failed: node(s) didn't have free ports for the requested pod ports(这里是用 nodeName 绕过调度器,由 kubelet 的准入检查拒绝)。

分步演示

宿主机命名空间
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0),所有 Pod 用 nodeName 固定在 worker;命名空间编号取自容器里的 readlink /proc/self/ns/* 和节点上的 /proc/1/ns/*;节点 IP 172.18.0.2;DNS 对比用 busybox 的 nslookup;hostPort 的访问从控制面节点用 curl;每种情形各一次
    • 没有验证:hostNetwork Pod 与 NetworkPolicy 的关系;hostPID 下发信号杀节点进程的权限;SysV IPC 实际共享的功能演示;PodSecurity 对这些字段的限制(下面有专门一篇);hostUsers: false(用户命名空间);hostNetwork 与 Service 访问的 SNAT
    京ICP备2026067502号-1京公网安备11010502063487号