Linux Network Namespace 入门

隔离你的网络环境:Linux Network Namespace 入门

你可能想知道,在同一个 Linux 系统里,不同的程序能不能拥有各自独立的网络设置?比如,让一个程序只能访问特定网站,而另一个程序可以自由访问所有网络资源,并且它们之间互不干扰。这正是 Linux Network Namespace 的核心功能。

什么是 Network Namespace?

在 Linux 系统中,默认情况下,所有网络相关的配置,包括网卡、IP 地址、路由规则、防火墙设置等,都属于一个叫做 “init” Network Namespace 的默认环境。当你运行程序时,它们通常在这个默认空间里,共享着相同的网络配置。

Network Namespace 允许你创建完全独立且隔离的网络环境。这意味着每个 Namespace 都拥有:

  • 独立的网络接口: 比如 eth0lo 等,在一个 Namespace 里看到的网卡,在另一个 Namespace 里是不可见的。
  • 独立的 IP 地址: 不同 Namespace 可以使用相同的 IP 地址,因为它们互不影响。
  • 独立的路由表: 决定数据包如何传输到目的地。
  • 独立的 ARP 表: 用于将 IP 地址解析为物理 MAC 地址。
  • 独立的防火墙规则 (iptables): 每个 Namespace 都能有自己一套防火墙策略,彼此独立。

为什么需要 Network Namespace?

Network Namespace 在很多场景下都非常有用:

  • 容器技术: Docker、Kubernetes 等工具正是利用 Network Namespace 为每个容器提供了隔离的网络环境。
  • 网络功能虚拟化 (NFV): 将路由器、防火墙等网络设备以软件形式运行,每个都在独立的 Namespace 中。
  • 测试与开发: 在不影响主系统网络的情况下,安全地测试新的网络配置或应用程序。
  • 安全隔离: 限制应用程序的网络访问范围,提高系统安全性。

网络配置实践解析

现在,我们一步步执行命令,了解如何建立一个独立网络环境并使其与主系统通信的。

1. 创建并进入一个独立网络环境
[root@localhost ~]# ip netns ls

这个命令用来列出当前系统中的所有 Network Namespace。刚开始执行时,可能没有输出,因为你可能只在使用默认的主 Namespace。

[root@localhost ~]# ip netns add game

这条命令创建了一个名为 “game” 的新 Network Namespace。现在,系统有了一个全新的、独立的网络配置区域。

[root@localhost ~]# ip netns ls
game

再次列出 Namespace,你会看到 “game” 已经出现在列表中。

[root@localhost ~]# ip netns exec game bash

ip netns exec 命令的作用是在指定的 Network Namespace 中执行命令。这里,我们告诉系统在 “game” Namespace 里启动一个新的 bash 会话。

此刻,你所处的是一个完全隔离的网络环境。在这个 bash 会话里,你看到和操作的所有网络设备、IP 地址、路由表等,都只属于 “game” Network Namespace。

[root@localhost ~]# ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

进入 “game” Namespace 后执行 ip link,你会发现只有一块名为 lo (回环网卡) 的网卡。这是因为每个新 Namespace 默认只包含一个回环网卡,它是完全独立的,看不到主 Namespace 的其他网卡,比如 ens33

[root@localhost ~]# exit
exit

输入 exit 命令,你将退出 “game” Namespace 内的 bash 会话,返回到主 Namespace。

[root@localhost ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:fd:5b:bb brd ff:ff:ff:ff:ff:ff
... (省略部分输出)

回到主 Namespace 后再次执行 ip link,你会看到熟悉的 ens33virbr0 等网卡,这表明你已回到主系统的网络环境。

[root@localhost ~]# ip netns exec game ip link list
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

这个命令再次确认了 “game” Namespace 中只有 lo 网卡。

[root@localhost ~]# ip netns exec game route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref     Use Iface

在 “game” Namespace 中查看路由表,发现它是空的。这意味着 “game” Namespace 目前不知道如何将数据包发送到它自己网络之外的目的地。

[root@localhost ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref     Use Iface
0.0.0.0         192.168.1.2     0.0.0.0         UG    100     0       0 ens33
192.168.1.0     0.0.0.0         255.255.255.0   U     100     0       0 ens33
192.168.122.0   0.0.0.0         255.255.255.0   U     0       0 virbr0

这是主 Namespace 的路由表,包含连接到互联网和本地网络的路由信息。

[root@localhost ~]# ip netns exec game iptables -nL
... (输出为空)
[root@localhost ~]# ip netns exec game iptables -nL -t nat
... (输出为空)

这些命令显示了 “game” Namespace 中的防火墙 (iptables) 规则,它们也是空的,进一步证明了 Namespace 的隔离性。


2. 连接两个网络环境:使用 veth 网卡对

现在,“game” Namespace 是一个独立但无法与外界通信的网络环境。为了让 “game” Namespace 能够与主 Namespace 通信,我们需要建立一个连接。这个连接就是通过 veth (Virtual Ethernet) pair 实现的。

一个 veth pair 是一对虚拟网卡。它们像一根虚拟的网线,一端在主 Namespace,另一端在 “game” Namespace。任何通过一端发送的数据包都会从另一端接收到。

[root@localhost ~]# ip link add veth1_out type veth peer name veth1_in

这条命令创建了一个 veth pair。

  • veth1_out:是这个 veth pair 的一端,它将保留在主 Namespace
  • veth1_in:是这个 veth pair 的另一端,我们计划将其移动到 “game” Namespace。
[root@localhost ~]# ip -br a
...
veth1_in@veth1_out DOWN
veth1_out@veth1_in DOWN

这时,你会在主 Namespace 看到新创建的 veth1_inveth1_out。它们的名字后面带有 @ 和对方的名字,表示它们是相互连接的。

[root@localhost ~]# ip link set veth1_in netns game

这是关键一步!它将 veth1_in 这块网卡从主 Namespace 移动到 “game” Namespace。现在,veth1_out 仍在主 Namespace,而 veth1_in 已经进入 “game” Namespace。

[root@localhost ~]# ip link
...
6: veth1_out@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 46:dc:ea:58:9f:5a brd ff:ff:ff:ff:ff:ff link-netnsid 0

在主 Namespace 中,你现在只能看到 veth1_out 了。

[root@localhost ~]# ip netns exec game ip link ls
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1_in@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 46:3a:95:ba:87:ae brd ff:ff:ff:ff:ff:ff link-netnsid 0

在 “game” Namespace 中,你现在不仅有 lo 网卡,还看到了 veth1_in 网卡。这表明 veth pair 的两端已经分别位于不同的 Namespace 中。


3. 配置 IP 地址并启用网卡

为了让 veth 网卡能够传输数据,我们需要为它的两端都分配 IP 地址,并将其激活。

[root@localhost ~]# ip netns exec game ip addr add 192.168.110.2/24 dev veth1_in

这条命令在 “game” Namespace 中,给 veth1_in 网卡分配了 IP 地址 192.168.110.2,子网掩码为 /24

[root@localhost ~]# ip netns exec game ip link set veth1_in up
[root@localhost ~]# ip netns exec game ip link set lo up

这两条命令分别激活了 “game” Namespace 中的 veth1_in 网卡和 lo 网卡。只有激活的网卡才能发送和接收数据。

[root@localhost ~]# ip addr add 192.168.110.1/24 dev veth1_out

这条命令在主 Namespace 中,给 veth1_out 网卡分配了 IP 地址 192.168.110.1,子网掩码为 /24

[root@localhost ~]# ip link set veth1_out up

激活主 Namespace 中的 veth1_out 网卡。

现在,veth1_out (192.168.110.1) 在主 Namespace,veth1_in (192.168.110.2) 在 “game” Namespace,它们位于同一个 192.168.110.0/24 子网,可以通过这对虚拟网卡直接通信了。


4. 测试网络连通性
[root@localhost ~]# ping -c 5 192.168.110.2

这条命令在主 Namespace 中,尝试 ping “game” Namespace 中的 192.168.110.2。如果配置正确,你会看到 ping 成功,这表示主 Namespace 可以通过 veth1_outveth1_in 通信。

[root@localhost ~]# ip netns exec game ping -c 4 192.168.110.1

这条命令在 “game” Namespace 中,尝试 ping 主 Namespace 中的 192.168.110.1。同样,如果成功,说明 “game” Namespace 可以通过 veth1_inveth1_out 通信。


5. 让独立网络环境连接外部网络:配置路由和 IP 转发

尽管 “game” Namespace 现在可以和主 Namespace 通信了,但它还不能直接访问互联网或主 Namespace 之外的其他网络。这是因为 “game” Namespace 的路由表是空的。我们需要告诉它,如果想访问它不明确目的地的网络,应该把数据包发给谁。

[root@localhost ~]# ip netns exec game ip route add default via 192.168.110.1

这条命令在 “game” Namespace 中添加了一条默认路由。它的作用是:“如果 ‘game’ Namespace 要发送数据包到一个它不明确目的地的网络,那么就把这个数据包发送给 192.168.110.1(也就是主 Namespace 中的 veth1_out)。”

现在,veth1_out 就像一个网关,负责将 “game” Namespace 的数据包转发出去。

[root@localhost ~]# sysctl -p
net.ipv4.ip_forward = 1
[root@localhost ~]# cat /etc/sysctl.conf
# ...
net.ipv4.ip_forward=1

net.ipv4.ip_forward 是一个内核参数,它控制着 Linux 系统是否允许进行 IP 转发。默认情况下,这个功能是关闭的。当你将其设置为 1 时,就允许你的 Linux 主机充当路由器,将从一个网络接口收到的数据包转发到另一个网络接口。

在这里,我们开启了主 Namespace 的 IP 转发功能。这意味着,当 “game” Namespace 的数据包通过 veth1_in 发送到主 Namespace 的 veth1_out 时,主 Namespace 会检查自己的路由表,并将这些数据包转发到正确的目的地(比如互联网)。

[root@localhost ~]# ip netns exec game ping -c 4 192.168.1.148
PING 192.168.1.148 (192.168.1.148) 56(84) bytes of data.
... (ping 成功)

最后,在 “game” Namespace 中 ping 主 Namespace 的 IP 地址 192.168.1.148 (你的 ens33 网卡 IP)。这次 ping 成功了!

这是因为:

  1. “game” Namespace 中的 ping 命令会向 192.168.1.148 发送数据包。
  2. “game” Namespace 发现 192.168.1.148 不在 192.168.110.0/24 这个子网内,所以它会根据默认路由将数据包发送给 192.168.110.1 (也就是主 Namespace 的 veth1_out)。
  3. 主 Namespace 的 veth1_out 收到数据包后,由于 net.ipv4.ip_forward 已经开启,它会查看自己的路由表。
  4. 主 Namespace 发现 192.168.1.148 在它的 ens33 网卡所在的子网,于是将数据包通过 ens33 发送出去。
  5. 192.168.1.148 收到数据包并回复,回复的数据包也会经过主 Namespace 的路由转发,最终回到 “game” Namespace。

通过这些步骤,你成功地创建了一个独立的 Network Namespace “game”,并利用 veth 网卡对和 IP 转发功能,让它能够与主系统以及外部网络进行通信。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值