欢迎光临
我们一直在努力

从物理机到 Pod:探秘 K8s 最小调度单元底层的命名空间隔离机制

在现代云计算环境中,Kubernetes (K8s) Pod 是最小的部署和调度单元。一个 Pod 看起来就像一台独立、拥有自己 IP 地址的虚拟机,但它在物理上与其他 Pod 共享宿主机内核。这种“看起来是独立”的能力,正是由 Linux 内核提供的核心隔离技术——命名空间 (Namespaces) 实现的。

本文将深入探讨 Namespaces 如何为 Pod 中的容器提供隔离环境,并提供实操代码演示如何手动创建这些隔离环境。

1. 命名空间:隔离的六大支柱

Namespaces 的核心目标是封装全局系统资源,并为进程提供一个隔离的视图。当一个容器(Pod中的应用程序)启动时,它通常会在多个命名空间中启动,使其无法看到宿主机上的全局资源。

K8s Pods 主要依赖以下关键命名空间来实现隔离:

命名空间 隔离的资源
PID (Process ID) 进程 ID 空间。使容器内部的进程 ID 独立于宿主机。
NET (Network) 网络栈、路由表、防火墙规则、网络接口。为 Pod 提供独立的 IP 地址和端口。
MNT (Mount) 文件系统挂载点。确保容器内的文件系统变动不影响宿主机。
UTS (Unix Time-sharing System) 主机名和域名。允许容器拥有自己的主机名。
IPC (Inter-Process Communication) System V IPC 资源。隔离进程间通信机制。
USER 用户和用户组 ID。允许容器内部的用户(如 root)映射到宿主机上的非特权用户。

2. 实操演示:手动创建 PID 隔离环境

容器运行时(如 containerd 或 Docker)在启动容器时,会自动创建这些命名空间。我们可以使用 Linux 内置的 unshare 命令来手动模拟这个过程,从而理解 PID 隔离的本质。

在宿主机上,我们首先查看当前 Shell 的 PID:

# 1. 检查当前 Shell 的 PID
echo "宿主机 PID: $$"
# 宿主机 PID: 12345

# 2. 查看宿主机上的进程列表(过滤出 init 进程)
ps -fp 1
# UID   PID  PPID C STIME TTY          TIME CMD
# root    1     0 0 May15 ?        00:00:20 /sbin/init

现在,我们使用 unshare 创建一个新的 PID 命名空间,并执行一个新的 Shell (bash)。–pid 用于隔离 PID,–fork 用于创建新进程:

# 3. 创建 PID 命名空间并进入
sudo unshare --pid --fork bash

# 4. 在新命名空间内检查 PID
echo "新环境 PID: $$"
# 新环境 PID: 1

# 5. 在新命名空间内查看进程列表
ps aux
# 只有 bash 进程,且它的 PID 是 1!
# USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
# root         1  0.0  0.0  14556  4308 pts/0    S    20:00   0:00 bash

# 6. 退出新 Shell
exit

# 7. 回到宿主机,确认 PID 隔离成功
echo "回到宿主机 PID: $$"
# 回到宿主机 PID: 12345 (原值)

原理分析: 在新的 PID 命名空间内,我们执行的 bash 进程成为了该空间内的“init”进程,被分配了 PID 1。它完全无法看到宿主机上真实的 PID 12345 或其他进程,实现了进程级的完美隔离。

3. 实操演示:手动创建 Network 隔离环境

网络隔离(NET Namespace)是 K8s Pod 能够拥有独立 IP 地址的关键。所有 Pod 内的容器(包括 Pause 容器和应用容器)都会共享同一个 NET Namespace,这也是 Pod 概念诞生的原因。

我们使用 ip netns 命令来创建和管理网络命名空间:

# 1. 检查宿主机网络接口
# 你会看到 eth0, docker0, lo 等接口
ip a | grep 'inet'

# 2. 创建一个新的网络命名空间
sudo ip netns add k8s-pod-net

# 3. 在新命名空间内查看网络接口
# 此时只应该看到默认的 loopback 接口(lo),且状态可能是 DOWN
sudo ip netns exec k8s-pod-net ip a

# 4. 激活 lo 接口
sudo ip netns exec k8s-pod-net ip link set lo up

# 5. 再次查看接口,确认没有宿主机的 eth0 或其他接口
sudo ip netns exec k8s-pod-net ip a | grep 'inet'
# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
#     inet 127.0.0.1/8 scope host lo

# 6. 尝试 ping 外部网络 (会失败,因为没有配置网桥)
# sudo ip netns exec k8s-pod-net ping -c 1 8.8.8.8

# 7. 清理命名空间
sudo ip netns delete k8s-pod-net

原理分析: 当 K8s 启动 Pod 时,它首先创建一个 Pause 容器,这个 Pause 容器就位于自己的 NET Namespace 中。然后,K8s 通过 Veth Pair(虚拟以太网对)将这个隔离的网络命名空间与宿主机的网络网桥(例如 CNI 网桥)连接起来,配置 IP 地址和路由,从而实现了 Pod 级别的独立网络栈。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » 从物理机到 Pod:探秘 K8s 最小调度单元底层的命名空间隔离机制
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址