Network Namespace 是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自的网络栈信息。不管是虚拟机还是容器,运行的时候仿佛自己就在独立的网络中。Linux Network Namespace 连接外网从大类上来讲主要有两种方法:网络地址转换(NAT) 和 桥接(bridging),而桥接根据使用的网桥又可以分为使用 linux bridge 和 Open vSwitch 网络等。本文介绍 network namespace 的基本概念和用法。

环境及配置

我们可以模拟一个linux 环境下的两个Namespace 如何 ping 通

network_namespace.png

创建Network Namespace

ip 命令管理的功能很多, 和 Network Namespace 有关的操作都是在子命令 ip netns 下进行的,可以通过 ip netns help 查看所有操作的帮助信息(ip 命令因为需要修改系统的网络配置,默认需要 sudo 权限)。

查看Network Namespace

默认情况下,使用 ip netns 是没有网络 Namespace 的,所以 ip netns ls 命令看不到任何输出。

[vagrant@swarm-manager /]$ sudo ip netns ls

创建 Network Namespace 也非常简单,直接使用 ip netns add 后面跟着要创建的 Namespace 名称。如果相同名字的 Namespace 已经存在,命令会报 Cannot create namespace file "/var/run/netns/xxx": File exists的错误

创建Network Namespace test1、test2

[vagrant@swarm-manager /]$ sudo ip netns add test1
[vagrant@swarm-manager /]$ sudo ip netns add test2
[vagrant@swarm-manager /]$ sudo ip netns list
test2
test1

在 Network Namespace 中执行命令

对于每个 Network Namespace 来说,它会有自己独立的网卡、路由表、ARP 表、iptables 等和网络相关的资源。ip 命令提供了 ip netns exec 子命令可以在对应的 Network Namespace 中执行命令

我们来看下test1 的ip link信息

[vagrant@swarm-manager /]$ sudo ip netns exec test1 ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

我们发现test1是没有ip地址的,并且状态是DOWND

Network Namespace 之间通信

有了不同 network namespace 之后,也就有了网络的隔离,但是如果它们之间没有办法通信,也没有实际用处。要把两个网络连接起来,linux 提供了 veth pair 。可以把 veth pair 当做是双向的 pipe(管道),从一个方向发送的网络数据,可以直接被另外一端接收到;或者也可以想象成两个 namespace 直接通过一个特殊的虚拟网卡连接起来,可以直接通信。

创建veth pair

创建两个veth,分别叫veth-test1veth-test2

[vagrant@swarm-manager /]$ sudo ip link add veth-test1 type veth peer name veth-test2

查看本机的ip link

[vagrant@swarm-manager /]$ sudo 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:75:dc:3d brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:39:1c:7f brd ff:ff:ff:ff:ff:ff
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:0a:08:fe:74 brd ff:ff:ff:ff:ff:ff
8: vethefc71da@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
    link/ether be:1f:49:9a:80:f3 brd ff:ff:ff:ff:ff:ff link-netnsid 0
9: veth-test2@veth-test1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether a6:41:67:d7:46:b8 brd ff:ff:ff:ff:ff:ff
10: veth-test1@veth-test2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 76:b8:c4:97:63:76 brd ff:ff:ff:ff:ff:ff

你会发现本机上多了两个 veth 接口,一个叫veth-test2@veth-test1,另一个叫veth-test1@veth-test2

将veth pair分别放入network namespace

[vagrant@swarm-manager /]$ sudo ip link set veth-test1 netns test1
[vagrant@swarm-manager /]$ sudo ip link set veth-test2 netns test2
[vagrant@swarm-manager /]$

我们再查看一下本机的ip link

[vagrant@swarm-manager /]$ sudo 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:75:dc:3d brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:39:1c:7f brd ff:ff:ff:ff:ff:ff
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:0a:08:fe:74 brd ff:ff:ff:ff:ff:ff
8: vethefc71da@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
    link/ether be:1f:49:9a:80:f3 brd ff:ff:ff:ff:ff:ff link-netnsid 0

你会发现,veth-test2@veth-test1,veth-test1@veth-test2没有了,少了两个。

我们再看一下network namespace test1的ip link

[vagrant@swarm-manager /]$ sudo ip netns exec test1 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
10: veth-test1@if9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 76:b8:c4:97:63:76 brd ff:ff:ff:ff:ff:ff link-netnsid 1

你会发现veth-test1被添加到test1的network namespace里面了,同理,veth-test2也被添加到test2的netwok namespace里面了

分别给veth-test1veth-test2分配ip地址

[vagrant@swarm-manager /]$ sudo ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1
[vagrant@swarm-manager /]$ sudo ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2

分别将veth-test1veth-test2 状态up

[vagrant@swarm-manager /]$ sudo ip netns exec test1 ip link set dev veth-test1 up
[vagrant@swarm-manager /]$ sudo ip netns exec test2 ip link set dev veth-test2 up
[vagrant@swarm-manager /]$

查看network namespace 的ip a

[vagrant@swarm-manager /]$ sudo ip netns exec test1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
10: veth-test1@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 76:b8:c4:97:63:76 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 192.168.1.1/24 scope global veth-test1
       valid_lft forever preferred_lft forever
    inet6 fe80::74b8:c4ff:fe97:6376/64 scope link
       valid_lft forever preferred_lft forever

你会发现状态已经为UP了,并且veth-test1有ip地址了,同理test2也一样

两个Network Namespace相互ping

test1 ping test2的ip地址

[vagrant@swarm-manager /]$ sudo ip netns exec test1 ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.053 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.040 ms
64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=0.040 ms

test2 ping test1的ip地址

[vagrant@swarm-manager /]$ sudo ip netns exec test2 ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.038 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.041 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.058 ms
64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=0.039 ms

这下两个Network Namespace能相互ping同了

参考链接:

linux 网络虚拟化: network namespace 简介

文章目录