|
背景 在Linux虚拟化技术中,网络层面,通常重要的三个技术分别是Network Namespace、veth pair、以及网桥或虚拟交换机技术。今天就通过实验带大家一起学习下Linux网络虚拟化技术。 我们首先了解下Network Namespace,它是由Linux内核提供,是实现网络虚拟化的重要功能。通过创建多个隔离的网络空间,实现网络资源的隔离。 不同的Network Namespace的资源互相不可见,彼此之间无法通信。如下图所示:
ip netns命令 Network Namespace是Linux内核提供的功能,本文借助ip命令来完成各种操作。ip命令来自于iproute2安装包,一般系统默认安装,如果没有的话,读者可自行安装。 ip命令管理的功能很多,和Network Namespace有关的操作都在其子命令ip netns下进行的,可以通过ip netns help查询命令帮助信息 [root@qll253 ~]# ip netns help4 e$ G0 s* ]. r, A# n& k; nUsage: ip netns list2 _1 ^ i( s/ {+ | ip netns add NAME6 C! w$ Y. ]3 R0 h% x% [ 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# A) e q! g d4 j. @7 c' @ e: b/ A ip netns list-id 创建Network Namespace 1、通过 ip netns add 命令创建一个名为ns0的网络命名空间:$ t% v) R$ C( H [root@1ll253 ~]# ip netns add ns0& H) ]% I. f( {# p 2、查询命名空间# L: `- d0 J( Y7 V [root@1ll253 ~]# ip netns list, f7 J$ w# y, P3 A4 y' F9 V ns0. V9 s) g! t/ h5 e' E 3、命名空间所在目录 [root@1ll253 ~]# ls /var/run/netns/- Q5 R2 F3 s! V! I ns0 操作Network Namespace 对于每个 Network Namespace 来说,它会有自己独立的网卡、路由表、ARP 表、iptables 等和网络相关的资源。ip命令提供了ip netns exec子命令可以在对应的 Network Namespace 中执行命令。 1、查看网络命名空间 ns0 的网卡信息[root@1ll253 ~]# ip netns exec ns0 ip addr- g/ r/ c5 Q, p! H7 U( M 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 10004 c: L) Y5 t# j) Y3 e, z, g link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 每个 namespace 在创建时会自动创建一个回环接口lo,默认不启用。它的作用和Linux系统中默认看到的lo一样,都是为了实现loopback通信,如果希望lo口能工作,可以通过下面的步骤2启用它。 2、启用lo回环网卡:[root@1ll253 ~]# ip netns exec ns0 ip link set lo up" n" z# M+ @: `* O/ F 再次检查回环网卡状态: [root@1ll253 ~]# ip netns exec ns0 ip addr+ x$ i6 `9 K; ^* T; r) {1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000# [+ o9 v) A* `: o& C7 z( v3 S link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00! A% G) D: O' ?( I9 @3 T. o% u inet 127.0.0.1/8 scope host lo9 F/ _ u! A$ i D6 W5 d: T! H# E valid_lft forever preferred_lft forever inet6 ::1/128 scope host / r2 m z m, Z& c% E @- t, x+ _2 C valid_lft forever preferred_lft forever 会发现此时回环口卡处于UP状态,并且系统分配127.0.0.1/8的ip地址。 3、在 ns0 中打开一个shell终端[root@1ll253 ~]# ip netns exec ns0 /bin/bash [root@1ll253 ~]# ip addr 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% M7 B, A( h" o+ V! Y% W$ j [root@1ll253 ~]# exit a2 ]- s) o" p/ p; o exit& K4 I t9 l# m, h 通过执行ip netns exec ns0 /bin/bash进入ns0的shell终端,后面所有的命令都在这个Network Namespace中执行,好处是不用每次执行命令时都要带上ip netns exec ,缺点是我们无法清楚知道自己当前所在的shell,容易混淆。 可以采用下面的方法解决: [root@1ll253 ~]# ip netns exec ns0 /bin/bash --rcfile <(echo "PS1=\"ns0> \"")2 D: T1 b2 x( l$ i6 I* {* ons0> 9 Z! z/ E' f1 M7 Y K Network Namespace 之间的通信 默认情况下,network namespace 是不能和主机网络,或者其他 network namespace 通信的。 可以使用 Linux 提供的veth pair来完成通信,veth pair你可以理解为使用网线连接好的两个接口,把两个端口放到两个namespace中,那么这两个namespace就能打通。 接下来我们通过实验进行验证:
1、创建veth pair [root@1ll253 ~]# ip link add type veth [root@1ll253 ~]# ip link' z6 b3 j/ ?& f) k ~7 t' O9 S 14: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000# f- G6 O4 z# {* P+ N link/ether 06:17:62:85:64:fc brd ff:ff:ff:ff:ff:ff 15: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether fe:9a:48:e4:a3:99 brd ff:ff:ff:ff:ff:ff' u1 M( K& Z$ _+ _' `) k [root@1ll253 ~]# 4 [ L/ x. e7 M* [. Z' ? 可以看到,此时系统中新增了一对veth pair:veth0和veth1,需要记住的是veth pair无法单独存在,删除其中一个,另一个也会自动消失。 如果需要指定veth pair两个端点的名称,可以使用下面的命令: [root@1ll253 ~]# ip link add veth001 type veth peer name veth002[root@1ll253 ~]# ip link 12: veth002@veth001: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000" q7 B( r: |! o( e- j$ n0 l link/ether aa:3e:04:da:a7:69 brd ff:ff:ff:ff:ff:ff 13: veth001@veth002: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 3e:5d:5f:4e:06:2b brd ff:ff:ff:ff:ff:ff3 L1 }: a7 a& B( e 2、创建Network Namespace 我们已创建了一个名为ns0的Network Namespace,下面再创建一个名称为ns1的网络命名空间。 [root@1ll253 ~]# ip netns add ns1% }# f5 e9 D: A# |" j: q1 M7 f) a[root@1ll253 ~]# ip netns list ns1! ^; y6 Z3 ]7 X) P9 A( ~9 G ns0 3、把veth pair分别加入到这两个namespace中 将veth0加入到ns0,将veth1加入到ns1,如下所示: [root@1ll253 ~]# ip link set veth0 netns ns0[root@1ll253 ~]# ip link set veth1 netns ns1 4、分别为这对veth pair配置上ip地址,并启用 1)为veth0配置IP,并启用该虚拟网卡 [root@1ll253 ~]# ip netns exec ns0 ip addr add 192.168.1.1/24 dev veth00 C1 ~" Y2 L+ R! ~, W5 Q" @( i[root@1ll253 ~]# ip netns exec ns0 ip link set veth0 up 2)为veth1配置IP,并启用该虚拟网卡 [root@1ll253 ~]# ip netns exec ns1 ip addr add 192.168.1.2/24 dev veth1: W' U( F& K' t' n& p4 k[root@1ll253 ~]# ip netns exec ns1 ip link set veth1 up6 f7 R0 F2 w C2 N. ` 5、查看这对veth pair的状态. O) q0 R" R; Q4 c. m; u
6、验证两个Network Namespace之间的互通. Y5 Z% q- I3 Y6 L3 ]1 ]$ b
可以看到,veth pair成功实现了两个不同Network Namespace之间的网络交互。 网桥虽然veth pair可以实现两个 Network Namespace 之间的通信,但 veth pair 有一个明显的缺陷,就是只能实现两个网络接口之间的通信。如果多个network namespace需要进行通信,则需要借助bridge。 下面我们通过实验来进行讲解:
0、还原网络环境 为方便接下来的实验,我们把刚刚创建的Network Namespace及veth pair删除,保证纯净的网络环境。 [root@1ll253 ~]# ip netns delete ns0[root@1ll253 ~]# ip netns delete ns1 1、创建3个Network Namespace0 M7 J1 ?8 e) I. E* N% E4 M [root@1ll253 ~]# ip netns add ns0: Y6 R, Q- [: ?6 q4 n [root@1ll253 ~]# ip netns add ns1 [root@1ll253 ~]# ip netns add ns2& ~/ O. ], \* D ^ 2、创建3对veth pair4 _7 l5 H9 U* v1 P [root@1ll253 ~]# ip link add type veth& V/ w2 h% U. N+ \) f [root@1ll253 ~]# ip link 16: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether ba:fa:d6:14:e1:32 brd ff:ff:ff:ff:ff:ff 17: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 10004 e# x; ~6 I8 N) C& C# Y a link/ether a2:ef:d9:a5:96:51 brd ff:ff:ff:ff:ff:ff3 t. b; H* y7 M8 u: z; Z 18: veth2@veth3: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether a2:5b:e7:9e:b1:55 brd ff:ff:ff:ff:ff:ff 19: veth3@veth2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 10008 q% _% U/ Y( t! O3 d9 y link/ether 92:91:67:ab:69:ac brd ff:ff:ff:ff:ff:ff/ v: Q: Y) q& b) r 20: veth4@veth5: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000. ]1 j' M& v% I. O link/ether 8a:c8:35:f6:11:3f brd ff:ff:ff:ff:ff:ff3 E" i2 K8 M4 S" }0 A9 D: \: g 21: veth5@veth4: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 10008 X8 K* ~0 P; d7 w ]4 k1 F link/ether 2a:b7:82:d4:49:d5 brd ff:ff:ff:ff:ff:ff 3、创建网桥2 I; v# c( D; _: w // 创建名为 docker0 的网桥 [root@1ll253 ~]# ip link add docker0 type bridge # W4 D/ e5 f2 a- j9 S //启动 docker0 网桥 [root@1ll253 ~]# ip link set dev docker0 up //为docker0网桥配置IP [root@1ll253 ~]# ifconfig docker0 172.17.0.1/16; {* \9 y0 E; G 此时可以通过ifconfig命令查看:
4、绑定网口 Network Namespace、veth pair、bridge 都创建完毕,下面通过命令将每对veth pair的一端绑定在network namespace,另一端绑定在docker0网桥上,用于实现网络互通 1)配置第一个网络命名空间 ns0 // 将veth1添加进ns09 B7 v* m5 e' ]# T- A$ g% R$ P: H. s[root@1ll253 ~]# ip link set dev veth1 netns ns0 //将veth1重命名为eth03 x F. N3 N) q# h! u ] [root@1ll253 ~]# ip netns exec ns0 ip link set dev veth1 name eth0 0 @8 _* j1 a: z% r0 O4 I7 g% y //为ns0中的eth0配置ip" E0 b1 X+ H& `" _" m [root@1ll253 ~]# ip netns exec ns0 ip addr add 172.17.0.101/16 dev eth0 8 n- p2 e6 M$ [% o" b // 启动ns0中的eth0网卡$ @) k5 g5 F0 A$ X. T( H" S5 P+ L [root@1ll253 ~]# ip netns exec ns0 ip link set dev eth0 up+ q( V+ Q% x& w 7 z# G3 U# L- p // 将veth0添加加网桥docker0 [root@1ll253 ~]# ip link set dev veth0 master docker0 6 ^2 B3 k7 E& X$ b // 启动veth0网卡 o6 m F4 {" {7 t2 G' ^* z [root@1ll253 ~]# ip link set dev veth0 up! f# a# Q3 R. _6 T: m7 S4 W 2)配置第二个网络命名空间 ns1 [root@1ll253 ~]# ip link set dev veth3 netns ns14 d9 t. ]4 F/ y; M8 H2 `2 T[root@1ll253 ~]# ip netns exec ns1 ip link set dev veth3 name eth0 [root@1ll253 ~]# ip netns exec ns1 ip addr add 172.17.0.102/16 dev eth03 z* z* i+ K8 x& V) j# l [root@1ll253 ~]# ip netns exec ns1 ip link set dev eth0 up1 K( L: d: E6 X) e9 \ L [root@1ll253 ~]# ip link set dev veth1 master docker0/ K. x; J& H8 j5 Q1 s- }1 u [root@1ll253 ~]# ip link set dev veth3 up 2)配置第三个网络命名空间 ns2 [root@1ll253 ~]# ip link set dev veth5 netns ns2[root@1ll253 ~]# ip netns exec ns2 ip link set dev veth5 name eth0 [root@1ll253 ~]# ip netns exec ns2 ip addr add 172.17.0.103/16 dev eth03 A) c' c- y1 z* |/ B. X# _ [root@1ll253 ~]# ip netns exec ns1 ip link set dev eth0 up# t+ [; C" d3 K [root@1ll253 ~]# ip link set dev veth5 master docker0 [root@1ll253 ~]# ip link set dev veth5 up+ M3 e; f- c( C; x' U 5、查看绑定端口
6、验证多个namespace之间的通信 // 进入ns0 bash终端( l; _- ?6 M2 q4 e [root@1ll253 ~]# ip netns exec ns0 /bin/bash --rcfile <(echo "PS1=\"ns0> \"")2 ]7 O& ~ h: m* g, \' t" a* ? // ping 网桥docker0 ns0> ping -c 1 172.17.0.1 PING 172.17.0.1 (172.17.0.1) 56(84) bytes of data. 64 bytes from 172.17.0.1: icmp_seq=1 ttl=64 time=0.033 ms ...7 ?3 G$ `9 X$ w: [* t6 G' V 6 w: u/ `- S/ S. Y% l, J' g' h // ping ns1上的eth0网卡0 E3 d6 ]" x& r `+ s# g ns0> ping -c 1 172.17.0.102 PING 172.17.0.102 (172.17.0.102) 56(84) bytes of data. 64 bytes from 172.17.0.102: icmp_seq=1 ttl=64 time=0.049 ms4 ?4 P P h0 |$ E; c7 }5 V/ s& L# S ... 0 z$ l" J9 s7 P // ping ns2上的eth0网卡 ns0> ping -c 1 172.17.0.103 PING 172.17.0.103 (172.17.0.103) 56(84) bytes of data. 64 bytes from 172.17.0.103: icmp_seq=1 ttl=64 time=0.038 ms ...& k) t x) n C! `( ? $ O) s; i) G% z- a. ? |
微信公众号
手机版