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
相关推荐
代码游侠2 小时前
学习笔记——sqlite3 数据库基础
linux·运维·网络·数据库·笔记·学习·sqlite
Ronin3052 小时前
多路转接epoll
linux·网络·多路转接·高效io·epoll模型
隔壁阿布都2 小时前
Docker 离线安装 GitLab 完整步骤
docker·gitlab
2501_939909052 小时前
Docker(3)
运维·docker·容器
XMYX-03 小时前
从 Pod 资源到 JVM 参数:我再生产环境中踩过的 Kubernetes 资源配置那些坑——2025 年度技术总结
jvm·容器·kubernetes
AI+程序员在路上3 小时前
linux下网络IP、网关及路由设置详解
linux·网络·tcp/ip
特种加菲猫3 小时前
局域网通信基石:ARP协议与MAC帧详解
网络·网络协议·tcp/ip
Ares-Wang3 小时前
网络》》FTP、TFTP、Telnet DHCP
运维·服务器·网络
玥轩_5213 小时前
防火墙技术-综合应用实验-2
网络·网络安全·智能路由器·防火墙·交换机·三层交换