• Ukieweb

    佳的博客

    曾梦想仗剑天涯,后来工作忙没去。

Linux 使用 ip netns命令操作 network namespace

network namespace 简介

network namespace 是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自的网络栈信息。不管是虚拟机还是容器,运行的时候仿佛自己就在独立的网络中。network namespace 是 linux 内核提供的功能。

这篇文章借助 ip 命令来完成各种操作。ip 命令来自于 iproute2 安装包,一般系统会默认安装,如果没有的话,请 yum install -y iproute 自行安装。

ip netns 

ip 命令管理的功能很多, 和 network namespace 有关的操作都是在子命令 ip netns 下进行的,可以通过 ip netns help` 查看所有操作的帮助信息。

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

[root@model ~]# ip netns help 
Usage: ip netns list
       ip netns add NAME
       ip netns set NAME NETNSID
       ip [-all] netns delete [NAME]
       ip netns identify [PID]
       ip netns pids NAME
       ip [-all] netns exec [NAME] cmd ...
       ip netns monitor
       ip netns list-id
[root@model ~]# ip netns ls

ip netns 创建删除 namespace

创建 network namespace

创建 network namespace 也非常简单,直接使用 ip netns add ns名称。如果相同名字的 namespace 已经存在,命令会报 Cannot create namespace的错误

[root@localhost ~]# ip netns add net1
[root@localhost ~]# ip netns ls
net1

ip netns 命令创建的 network namespace 会出现在 /var/run/netns/ 目录下,如果需要管理其他不是 ip netns 创建的 network namespace,只要在这个目录下创建一个指向对应 network namespace 文件的链接就行。

对于每个 network namespace 来说,它会有自己独立的网卡路由表ARP 表iptables 等和网络相关的资源

删除 network namespace

[root@model ~]# ip netns delete net1
[root@model ~]# ip netns ls
[root@model ~]#

ip netns exec 执行命令

ip 命令提供了 ip netns exec 子命令可以在对应的 network namespace 中执行命令,要执行的可以是任何命令,不只是和网络相关的(当然,和网络无关命令执行的结果和在外部执行没有区别)。

[root@model ~]# ip netns exec  net1 ip add
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

执行 bash 命令了之后,后面所有的命令都是在这个 network namespace 中执行的,好处是不用每次执行命令都要把 ip netns exec NAME 补全

[root@model ~]# ip netns exec net1 /bin/bash --rcfile <(echo "PS1=\"namespace ns1> \"")
namespace ns1> ip add
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
namespace ns1>

启用 namespace 的  lo 接口

每个 namespace 创建的时候自动创建一个 lo 的 interface,它的作用和 linux 系统中默认看到的 lo 一样,都是为了实现 loopback 通信。如果希望 lo 能工作,不要忘记启用它:

[root@model ~]# ip netns exec net1 ip link set lo up
[root@model ~]# ip netns exec net1 ip add
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
[root@model ~]#

两个 network namespace 之间通信

ns1.jpg

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

使用上面提到的方法,我们再创建另外一个 network namespace,这里我们使用 net0 和 net1 两个名字。

创建 veth pair

我们可以使用 ip link add type veth 来创建一对 veth pair 出来,需要记住的是 veth pair 无法单独存在,删除其中一个,另一个也会自动消失

[root@localhost ~]# ip link add type veth

[root@localhost ~]# ip link
4: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether 36:88:73:83:c9:64 brd ff:ff:ff:ff:ff:ff
5: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether fe:7e:75:4d:79:2e brd ff:ff:ff:ff:ff:ff

创建 veth pair 的时候可以自己指定它们的名字,比如 ip link add vethfoo type veth peer name vethbar 创建出来的两个名字就是 vethfoo vethbar 

分配 veth pair

把这对 veth pair 分别放到已经两个 namespace 里面,这个可以使用 ip link set DEV netns NAME 来实现:

[root@localhost ~]# ip link set veth0 netns net0
[root@localhost ~]# ip link set veth1 netns net1

[root@localhost ~]# ip netns exec net0 ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 36:88:73:83:c9:64 brd ff:ff:ff:ff:ff:ff
    
[root@localhost ~]# ip netns exec net1 ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether fe:7e:75:4d:79:2e brd ff:ff:ff:ff:ff:ff

给 veth pair 配置上 ip 地址,并启用它们

[root@localhost ~]# ip netns exec net0 ip link set veth0 up
[root@localhost ~]# ip netns exec net0 ip addr add 10.0.1.1/24 dev veth0

[root@localhost ~]# ip netns exec net0 ip route
10.0.1.0/24 dev veth0  proto kernel  scope link  src 10.0.1.1

[root@localhost ~]# ip netns exec net1 ip link set veth1 up
[root@localhost ~]# ip netns exec net1 ip addr add 10.0.1.2/24 dev veth1

可以看到,最每个 namespace 中,在配置玩 ip 之后,还自动生成了对应的路由表信息,网络 10.0.1.0/24 数据报文都会通过 veth pair 进行传输。

验证它们的连通性

[root@localhost ~]# ip netns exec net0 ping -c 3 10.0.1.2PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=0.039 ms64 bytes from 10.0.1.2: icmp_seq=2 ttl=64 time=0.039 ms64 bytes from 10.0.1.2: icmp_seq=3 ttl=64 time=0.139 ms--- 10.0.1.2 ping statistics ---3 packets transmitted, 3 received, 0% packet loss, time 2004msrtt min/avg/max/mdev = 0.039/0.072/0.139/0.047 ms

多个 namespace 通信(网桥)

net2.jpg

虽然 veth pair 可以实现两个 network namespace 之间的通信,但是当多个 namespace 需要通信的时候,就无能为力了。linux 当然也提供了虚拟交换机的功能,俗称网桥,我们还是用 ip 命令来完成所有的操作。和 bridge 有关的操作也可以使用命令 brctl,这个命令来自 bridge-utils 这个包

首先我们来创建需要的 bridge,简单起见名字就叫做 br0。

[root@localhost ~]# ip link add br0 type bridge
[root@localhost ~]# ip link set dev br0 up

创建 veth pair

下面只演示一个 namespace 的操作,其他 namespace 要做的事情和这个类似。

[root@localhost ~]# ip link add type veth

分配 veth pair

把其中一个 veth(veth1) 放到 net0 里面,设置它的 ip 地址并启用它:

[root@localhost ~]# ip link set dev veth1 netns net0
[root@localhost ~]# ip netns exec net0 ip link set dev veth1 name eth0
[root@localhost ~]# ip netns exec net0 ip addr add 10.0.1.1/24 dev eth0
[root@localhost ~]# ip netns exec net0 ip link set dev eth0 up

连接 bridge

最后,把另一个 veth(veth0)连接到创建的 bridge 上,并启用它:

[root@localhost ~]# ip link set dev veth0 master br0
[root@localhost ~]# ip link set dev veth0 up

查看 bridge 管理的 link

可以通过 bridge 命令(也是 iproute2 包自带的命令)来查看 bridge 管理的 link 信息:bridge link 或者 bridge show

[root@localhost ~]# bridge link
17: veth0 state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 2

测试网络的连通性:

[root@localhost ~]# ip netns exec net0 ping -c 3 10.0.1.3
PING 10.0.1.3 (10.0.1.3) 56(84) bytes of data.
64 bytes from 10.0.1.3: icmp_seq=1 ttl=64 time=0.251 ms
64 bytes from 10.0.1.3: icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from 10.0.1.3: icmp_seq=3 ttl=64 time=0.046 ms
--- 10.0.1.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2008ms


如果对 docker 网络熟悉的话,其实这和 docker 默认的 bridge 网络模型非常相似。当然要实现每个 namespace 对外网的访问还需要额外的配置(设置默认网关,开启 ip_forward,为网络添加 NAT 规则等)。


摘自:https://cizixs.com/2017/02/10/network-virtualization-network-namespace/

0
0
下一篇:Jenkinsfile 流水线 pipeline 使用和设置环境变量

0 条评论

老佳啊

85后,大专学历,中原人士,家里没矿。

由于年轻时长的比较帅气,导致在别人眼里,我一直不谈恋爱的原因是清高,实则是自己的小自卑。最大的人生目标就是找一个相知相爱相容的人,共度余生。

和人相处时如果能感受到真诚,会非常注重彼此的关系,对别人没有什么心机,即使有利益冲突,一般也会以和为贵,因为在这个世界上,物质的东西,从来不会吸引到我。

特别迷恋那些大山大水,如果现在还能隐居,可能早就去了。对那些宏伟的有底蕴的人文景观比较不感冒。

从事于IT行业,却一直对厨房念念不忘,由于身材魁梧,总觉得自己上辈子是个将军,可惜这辈子没当兵,也不会打架。