Docker底层-Namespaces(网络隔离)

ip netns 是 Linux 的 Network Namespace 管理工具,属于 iproute2 包。用于创建、列出、删除和操作 Network Namespaces。

ip netns 详解

1. 基本概念

ip netns 用于管理 Network Namespaces,让每个 Namespace 拥有独立的网络栈(接口、路由、防火墙规则等)。

2. 基本命令

bash 复制代码
# 查看所有 Network Namespaces
ip netns list

# 创建新的 Network Namespace
ip netns add <name>

# 删除 Network Namespace
ip netns delete <name>

# 在指定的 Network Namespace 中执行命令
ip n

3. 实际使用示例

示例 1:创建和查看 Network Namespace

完整图解:veth pair 连接两个 Network Namespaces

初始状态:创建两个 Network Namespaces

bash 复制代码
┌─────────────────────────────────────────────────────────┐
│                     Linux 主机                           │
│                                                          │
│  ┌──────────────┐              ┌──────────────┐         │
│  │ red Namespace│              │blue Namespace│         │
│  │              │              │              │         │
│  │   (空的)     │              │   (空的)     │         │
│  │              │              │              │         │
│  │  只有 lo     │              │  只有 lo     │         │
│  └──────────────┘              └──────────────┘         │
│                                                          │
└─────────────────────────────────────────────────────────┘
bash 复制代码
# 创建两个 Network Namespaces
sudo ip netns add red
sudo ip netns add blue

# 查看所有 Network Namespaces
ip netns list
# 输出:
# red
# blue

# 查看每个 Namespace 的网络接口
sudo ip netns exec red ip addr show
# 输出:只有 lo(回环接口)

sudo ip netns exec blue ip addr show
# 输出:只有 lo(回环接口)

ip addr show 输出详解

整体含义

这是 lo(loopback,回环)接口的信息,状态为 DOWN(未启动)。

逐行解析

bash 复制代码
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
  • 1::接口索引号
  • lo::接口名称(loopback)
  • <LOOPBACK>:接口类型(回环)
  • mtu 65536:最大传输单元(字节)
  • qdisc noop:队列规则(noop = 无操作,不排队)
  • state DOWN:接口状态(DOWN = 关闭,UP = 启动)
  • group default:接口组
  • qlen 1000:队列长度
bash 复制代码
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  • link/loopback:链路类型(回环)
  • 00:00:00:00:00:00:MAC 地址(回环接口固定为全 0)
  • brd 00:00:00:00:00:00:广播地址(回环接口也是全 0)

关键点

  1. state DOWN:接口未启动,无法通信
  1. 没有 IP 地址:输出中没有 inet 行,说明未配置 IP
  1. 这是新创建的 Network Namespace:只有默认的 lo 接口
bash 复制代码
# 创建 veth pair(虚拟以太网对)
sudo ip link add veth-red type veth peer name veth-blue

┌─────────────────────────────────────────────────────────┐
│                     Linux 主机                           │
│                                                          │
│  ┌──────────────┐              ┌──────────────┐         │
│  │ red Namespace│              │blue Namespace│         │
│  │              │              │              │         │
│  │  只有 lo     │              │  只有 lo     │         │
│  └──────────────┘              └──────────────┘         │
│                                                          │
│  主机上创建了 veth pair:                                │
│                                                          │
│    veth-red  <===========>  veth-blue                   │
│     (一端)     虚拟网线       (另一端)                   │
│                                                          │
│  注意:此时接口还在主机上,不在 Namespace 中!           │
└─────────────────────────────────────────────────────────┘


# 将接口放入各自的 Namespace
sudo ip link set veth-red netns red
sudo ip link set veth-blue netns blue

┌─────────────────────────────────────────────────────────┐
│                     Linux 主机                           │
│                                                          │
│  ┌──────────────┐              ┌──────────────┐         │
│  │ red Namespace│              │blue Namespace│         │
│  │              │              │              │         │
│  │   lo         │              │   lo         │         │
│  │   veth-red   │              │   veth-blue  │         │
│  │   (DOWN)     │              │   (DOWN)     │         │
│  └──────┬───────┘              └──────┬───────┘         │
│         │                              │                 │
│         └──────── veth pair ───────────┘                 │
│              (虚拟网线连接)                               │
│                                                          │
│  注意:接口已移动到各自的 Namespace,但状态是 DOWN      │
└─────────────────────────────────────────────────────────┘


# 在 red Namespace 中配置 IP
sudo ip netns exec red ip addr add 10.0.0.1/24 dev veth-red
sudo ip netns exec red ip link set veth-red up

┌─────────────────────────────────────────────────────────┐
│                     Linux 主机                           │
│                                                          │
│  ┌──────────────┐              ┌──────────────┐         │
│  │ red Namespace│              │blue Namespace│         │
│  │              │              │              │         │
│  │   lo         │              │   lo         │         │
│  │   veth-red   │              │   veth-blue  │         │
│  │   10.0.0.1   │              │   (DOWN)     │         │
│  │   (UP) ✓     │              │   (未配置)   │         │
│  └──────┬───────┘              └──────┬───────┘         │
│         │                              │                 │
│         └──────── veth pair ───────────┘                 │
│              (虚拟网线连接)                               │
│                                                          │
│  red 端已配置 IP 并启动,blue 端还未配置                  │
└─────────────────────────────────────────────────────────┘


# 在 blue Namespace 中配置 IP
sudo ip netns exec blue ip addr add 10.0.0.2/24 dev veth-blue
sudo ip netns exec blue ip link set veth-blue up

# 测试连通性
sudo ip netns exec red ping 10.0.0.2

┌─────────────────────────────────────────────────────────┐
│                     Linux 主机                           │
│                                                          │
│  ┌──────────────┐              ┌──────────────┐         │
│  │ red Namespace│              │blue Namespace│         │
│  │              │              │              │         │
│  │ ping 命令    │              │              │         │
│  │ 发送数据包   │              │              │         │
│  │              │              │              │         │
│  │   veth-red   │              │   veth-blue  │         │
│  │   10.0.0.1   │              │   10.0.0.2   │         │
│  │   (UP) ✓     │              │   (UP) ✓     │         │
│  └──────┬───────┘              └──────┬───────┘         │
│         │                              │                 │
│         │  ICMP Echo Request           │                 │
│         │  (ping 10.0.0.2)             │                 │
│         └──────────────>───────────────┘                 │
│                            │                             │
│                            │  ICMP Echo Reply            │
│                            │  (pong)                     │
│         <──────────────────┘                             │
│                                                          │
│  数据包通过 veth pair 传输                                │
└─────────────────────────────────────────────────────────┘

详细执行流程
步骤 1:命令执行位置
┌─────────────────────────────────────────────────────────┐
│                     Linux 主机                           │
│                                                          │
│  主机 Shell:                                            │
│  ┌──────────────────────────────────────────────┐      │
│  │ $ sudo ip netns exec red ping 10.0.0.2       │      │
│  │                                              │      │
│  │ 这个命令在主机上执行,但会:                  │      │
│  │ 1. 切换到 red Network Namespace              │      │
│  │ 2. 在 red Namespace 中启动 ping 进程          │      │
│  └──────────────────────────────────────────────┘      │
│                                                          │
│  ┌──────────────┐              ┌──────────────┐         │
│  │ red Namespace│              │blue Namespace│         │
│  │              │              │              │         │
│  │  ping 进程   │              │              │         │
│  │  (PID: 1234) │              │              │         │
│  │              │              │              │         │
│  │   veth-red   │              │   veth-blue  │         │
│  │   10.0.0.1   │              │   10.0.0.2   │         │
│  └──────┬───────┘              └──────┬───────┘         │
│         │                              │                 │
│         └──────── veth pair ───────────┘                 │
└─────────────────────────────────────────────────────────┘

步骤 2:ping 进程的网络视图
在 red Namespace 中,ping 进程看到的网络环境:
┌─────────────────────────────────────────────────────────┐
│  red Network Namespace(ping 进程的视角)                │
│                                                          │
│  ┌──────────────────────────────────────────────┐      │
│  │ ping 进程 (PID: 1234)                       │      │
│  │                                              │      │
│  │ 执行:ping 10.0.0.2                          │      │
│  └──────────────────────────────────────────────┘      │
│                                                          │
│  ping 进程看到的网络接口:                               │
│                                                          │
│  ┌──────────────────────────────────────────────┐      │
│  │ 1. lo (127.0.0.1)                            │      │
│  │ 2. veth-red (10.0.0.1)                       │      │
│  └──────────────────────────────────────────────┘      │
│                                                          │
│ └─────────────────────────────────────────────────────────┘
步骤 3:ping 创建数据包的过程

┌─────────────────────────────────────────────────────────┐
│  red Network Namespace                                  │
│                                                          │
│  ┌──────────────────────────────────────────────┐      │
│  │ ping 进程                                    │      │
│  │                                              │      │
│  │ 1. 解析目标地址:10.0.0.2                    │      │
│  │ 2. 查找路由表:                              │      │
│  │    $ ip route show                          │      │
│  │    10.0.0.0/24 dev veth-red scope link      │      │
│  │                                              │      │
│  │ 3. 确定发送接口:veth-red                    │      │
│  │ 4. 确定源 IP:10.0.0.1(veth-red 的 IP)     │      │
│  │                                              │      │
│  │ 5. 创建 ICMP Echo Request 数据包:          │      │
│  │    ┌──────────────────────────────────┐     │      │
│  │    │ Layer 2 (Ethernet):              │     │      │
│  │    │   Src MAC: veth-red 的 MAC       │     │      │
│  │    │   Dst MAC: veth-blue 的 MAC      │     │      │
│  │    │                                  │     │      │
│  │    │ Layer 3 (IP):                    │     │      │
│  │    │   Src IP: 10.0.0.1               │     │      │
│  │    │   Dst IP: 10.0.0.2               │     │      │
│  │    │                                  │     │      │
│  │    │ Layer 4 (ICMP):                  │     │      │
│  │    │   Type: Echo Request             │     │      │
│  │    │   Data: ping payload             │     │      │
│  │    └──────────────────────────────────┘     │      │
│  └──────────────────────────────────────────────┘      │
│                                                          │
│  数据包发送到网络栈                                      │
│         ↓                                               │
│  ┌──────────────────────────────────────────────┐      │
│  │ Linux 网络栈(red Namespace)                │      │
│  │                                              │      │
│  │ 1. ICMP 层:封装 ICMP 数据                    │      │
│  │ 2. IP 层:添加 IP 头(10.0.0.1 -> 10.0.0.2)│      │
│  │ 3. 路由:查找出口接口(veth-red)            │      │
│  │ 4. ARP:查找目标 MAC(如果需要)              │      │
│  │ 5. 链路层:通过 veth-red 发送                │      │
│  └──────────────────────────────────────────────┘      │
│         ↓                                               │
│  ┌──────────────────────────────────────────────┐      │
│  │ veth-red (10.0.0.1)                          │      │
│  │ 物理发送数据包                                │      │
│  └──────────────────────────────────────────────┘      │
└─────────────────────────────────────────────────────────┘
步骤 4:数据包通过 veth pair 传输
┌─────────────────────────────────────────────────────────┐
│  red Network Namespace                                  │
│                                                          │
│  ┌──────────────────────────────────────────────┐      │
│  │ veth-red (10.0.0.1)                          │      │
│  │                                              │      │
│  │ 数据包从这里发送:                            │      │
│  │ ┌──────────────────────────────────────┐    │      │
│  │ │ Src: 10.0.0.1                        │    │      │
│  │ │ Dst: 10.0.0.2                        │    │      │
│  │ │ ICMP Echo Request                    │    │      │
│  │ └──────────────────────────────────────┘    │      │
│  └──────────────┬───────────────────────────────┘      │
│                 │                                       │
│                 │ 数据包通过 veth pair                  │
│                 │ (内核直接转发,不经过主机网络栈)     │
│                 ↓                                       │
└─────────────────┼───────────────────────────────────────┘
                  │
                  │ veth pair(虚拟网线)
                  │
┌─────────────────┼───────────────────────────────────────┐
│                 ↓                                       │
│  ┌──────────────┴───────────────────────────────┐      │
│  │ veth-blue (10.0.0.2)                         │      │
│  │                                              │      │
│  │ 数据包在这里接收:                            │      │
│  │ ┌──────────────────────────────────────┐    │      │
│  │ │ Src: 10.0.0.1                        │    │      │
│  │ │ Dst: 10.0.0.2                        │    │      │
│  │ │ ICMP Echo Request                    │    │      │
│  │ └──────────────────────────────────────┘    │      │
│  └──────────────────────────────────────────────┘      │
│                                                          │
│  blue Network Namespace                                 │
└─────────────────────────────────────────────────────────┘
要点:
数据包从 veth-red 发送
通过 veth pair 立即到达 veth-blue
不经过主机网络栈,是内核直接转发

步骤 5:blue Namespace 接收并处理
┌─────────────────────────────────────────────────────────┐
│  blue Network Namespace                                 │
│                                                          │
│  ┌──────────────────────────────────────────────┐      │
│  │ veth-blue (10.0.0.2)                         │      │
│  │ 接收数据包                                    │      │
│  └──────────────┬───────────────────────────────┘      │
│                 ↓                                       │
│  ┌──────────────────────────────────────────────┐      │
│  │ Linux 网络栈(blue Namespace)               │      │
│  │                                              │      │
│  │ 1. 链路层:veth-blue 接收                     │      │
│  │ 2. IP 层:检查目标 IP(10.0.0.2)            │      │
│  │ 3. ICMP 层:识别为 ICMP Echo Request          │      │
│  │ 4. 内核 ICMP 处理程序:                       │      │
│  │    - 创建 ICMP Echo Reply                    │      │
│  │    - 交换源/目标 IP                           │      │
│  │    - 通过 veth-blue 发送回复                  │      │
│  └──────────────────────────────────────────────┘      │
│                                                          │
│  注意:blue Namespace 中没有运行 ping 进程!            │
│  ICMP Echo Reply 是由内核自动生成的!                   │
└─────────────────────────────────────────────────────────┘
重要:
blue Namespace 中没有 ping 进程
ICMP Echo Reply 由内核 ICMP 处理程序自动生成
不需要应用程序监听
步骤 6:回复数据包返回

┌─────────────────────────────────────────────────────────┐
│  blue Network Namespace                                 │
│                                                          │
│  ┌──────────────────────────────────────────────┐      │
│  │ veth-blue (10.0.0.2)                         │      │
│  │                                              │      │
│  │ 内核发送 ICMP Echo Reply:                    │      │
│  │ ┌──────────────────────────────────────┐    │      │
│  │ │ Src: 10.0.0.2                        │    │      │
│  │ │ Dst: 10.0.0.1                        │    │      │
│  │ │ ICMP Echo Reply                      │    │      │
│  │ └──────────────────────────────────────┘    │      │
│  └──────────────┬───────────────────────────────┘      │
│                 │                                       │
│                 │ 数据包通过 veth pair                  │
│                 ↓                                       │
└─────────────────┼───────────────────────────────────────┘
                  │
                  │ veth pair(虚拟网线)
                  │
┌─────────────────┼───────────────────────────────────────┐
│                 ↓                                       │
│  ┌──────────────┴───────────────────────────────┐      │
│  │ veth-red (10.0.0.1)                          │      │
│  │ 接收回复数据包                                │      │
│  └──────────────┬───────────────────────────────┘      │
│                 ↓                                       │
│  ┌──────────────────────────────────────────────┐      │
│  │ Linux 网络栈(red Namespace)                │      │
│  │                                              │      │
│  │ 1. veth-red 接收数据包                        │      │
│  │ 2. IP 层:检查目标 IP(10.0.0.1)             │      │
│  │ 3. ICMP 层:识别为 ICMP Echo Reply            │      │
│  │ 4. 传递给 ping 进程                           │      │
│  └──────────────────────────────────────────────┘      │
│                 ↓                                       │
│  ┌──────────────────────────────────────────────┐      │
│  │ ping 进程                                    │      │
│  │                                              │      │
│  │ 收到 ICMP Echo Reply                         │      │
│  │ 显示:64 bytes from 10.0.0.2: ...            │      │
│  └──────────────────────────────────────────────┘      │
│                                                          │
│  red Network Namespace                                  │
└─────────────────────────────────────────────────────────┘

完整数据流图

bash 复制代码
┌─────────────────────────────────────────────────────────┐
│  主机 Shell                                              │
│  $ sudo ip netns exec red ping 10.0.0.2                 │
└─────────────────────────────────────────────────────────┘
                    │
                    │ 1. 切换到 red Network Namespace
                    ↓
┌─────────────────────────────────────────────────────────┐
│  red Network Namespace                                  │
│  ┌──────────────────────────────────────────────┐      │
│  │ ping 进程启动                                 │      │
│  │ - 解析目标:10.0.0.2                          │      │
│  │ - 查找路由:通过 veth-red                      │      │
│  │ - 源 IP:10.0.0.1                             │      │
│  └──────────────────────────────────────────────┘      │
│                    │                                     │
│                    │ 2. 创建 ICMP Echo Request            │
│                    ↓                                     │
│  ┌──────────────────────────────────────────────┐      │
│  │ 网络栈处理                                    │      │
│  │ - 封装 IP 头(10.0.0.1 -> 10.0.0.2)          │      │
│  │ - 封装以太网头                                 │      │
│  └──────────────────────────────────────────────┘      │
│                    │                                     │
│                    │ 3. 通过 veth-red 发送                │
│                    ↓                                     │
│  ┌──────────────────────────────────────────────┐      │
│  │ veth-red (10.0.0.1)                          │      │
│  │ 发送数据包                                    │      │
│  └──────────────┬───────────────────────────────┘      │
└─────────────────┼───────────────────────────────────────┘
                  │
                  │ 4. 通过 veth pair 传输
                  │ (内核直接转发)
                  │
┌─────────────────┼───────────────────────────────────────┐
│                 ↓                                       │
│  ┌──────────────┴───────────────────────────────┐      │
│  │ veth-blue (10.0.0.2)                         │      │
│  │ 接收数据包                                    │      │
│  └──────────────┬───────────────────────────────┘      │
│                 │                                       │
│                 │ 5. 网络栈处理                         │
│                 ↓                                       │
│  ┌──────────────────────────────────────────────┐      │
│  │ blue Namespace 网络栈                        │      │
│  │ - 检查目标 IP:10.0.0.2 ✓                    │      │
│  │ - 识别 ICMP Echo Request                     │      │
│  │ - 内核自动生成 ICMP Echo Reply                │      │
│  └──────────────────────────────────────────────┘      │
│                 │                                       │
│                 │ 6. 通过 veth-blue 发送回复            │
│                 ↓                                       │
│  ┌──────────────────────────────────────────────┐      │
│  │ veth-blue (10.0.0.2)                         │      │
│  │ 发送 ICMP Echo Reply                         │      │
│  └──────────────┬───────────────────────────────┘      │
└─────────────────┼───────────────────────────────────────┘
                  │
                  │ 7. 通过 veth pair 返回
                  │
┌─────────────────┼───────────────────────────────────────┐
│                 ↓                                       │
│  ┌──────────────┴───────────────────────────────┐      │
│  │ veth-red (10.0.0.1)                          │      │
│  │ 接收回复                                      │      │
│  └──────────────┬───────────────────────────────┘      │
│                 │                                       │
│                 │ 8. 网络栈处理                         │
│                 ↓                                       │
│  ┌──────────────────────────────────────────────┐      │
│  │ red Namespace 网络栈                         │      │
│  │ - 检查目标 IP:10.0.0.1 ✓                    │      │
│  │ - 识别 ICMP Echo Reply                       │      │
│  │ - 传递给 ping 进程                           │      │
│  └──────────────────────────────────────────────┘      │
│                 │                                       │
│                 │ 9. ping 进程接收                      │
│                 ↓                                       │
│  ┌──────────────────────────────────────────────┐      │
│  │ ping 进程                                    │      │
│  │ 显示:64 bytes from 10.0.0.2: ...            │      │
│  └──────────────────────────────────────────────┘      │
│                                                          │
│  red Network Namespace                                  │
└─────────────────────────────────────────────────────────┘

完整示例:创建两个"容器"并连接

复制代码
#!/bin/bash
# 创建两个 Network Namespaces 并连接它们

# 1. 创建 Namespaces
sudo ip netns add container1
sudo ip netns add container2

# 2. 创建 veth pair
sudo ip link add veth1 type veth peer name veth2

# 3. 将接口放入各自的 Namespace
sudo ip link set veth1 netns container1
sudo ip link set veth2 netns container2

# 4. 配置 IP 地址
sudo ip netns exec container1 ip addr add 10.0.0.1/24 dev veth1
sudo ip netns exec container2 ip addr add 10.0.0.2/24 dev veth2

# 5. 启动接口
sudo ip netns exec container1 ip link set veth1 up
sudo ip netns exec container2 ip link set veth2 up

# 6. 启动回环接口
sudo ip netns exec container1 ip link set lo up
sudo ip netns exec container2 ip link set lo up

# 7. 测试连通性
echo "从 container1 ping container2:"
sudo ip netns exec container1 ping -c 3 10.0.0.2

echo "从 container2 ping container1:"
sudo ip netns exec container2 ping -c 3 10.0.0.1

# 8. 查看路由表
echo "container1 的路由表:"
sudo ip netns exec container1 ip route show

echo "container2 的路由表:"
sudo ip netns exec container2 ip route show

# 9. 清理
sudo ip netns delete container1
sudo ip netns delete container2
相关推荐
雪可问春风20 小时前
docker环境部署
运维·docker·容器
双份浓缩馥芮白21 小时前
【Docker】Linux 迁移 docker 目录(软链接)
linux·docker
为何创造硅基生物21 小时前
ESP32S3的RGB屏幕漂移问题
网络
好运的阿财21 小时前
process 工具与子agent管理机制详解
网络·人工智能·python·程序人生·ai编程
周杰伦fans21 小时前
C# required 关键字详解
开发语言·网络·c#
洛水水1 天前
深入理解网络编程核心:Reactor、IOCP 与异步 IO 模型详解
网络·iocp
favour_you___1 天前
epoll惊群问题与解决
服务器·网络·tcp/ip·epoll
北方的流星1 天前
华三网络设备的路由重定向配置
运维·网络·华三
kobe_OKOK_1 天前
S7 adapter Docker run
运维·docker·容器
一个欠登儿程序员1 天前
在国产服务器上通过 Docker 部署 Windows 虚拟机
服务器·windows·docker