Linux 网络虚拟化(Docker 组网模型)

在 Linux 中很多的资源都是全局的。比如进程有全局的进程 ID,网络也有全局的路由表。当一台 Linux 上跑多个进程的时候,如果我们要使用不同的路由策略,这些进程可能会冲突,那就需要将这个进程放在一个独立的 namespace 里面,这样就可以独立配置网络了。

Linux 中 namespace 的作用就是用来隔离内核资源,共有 6 种不同类型的 namespace:

  • user namespace 隔离用户权限
  • mount namespace 修改进程的文件系统视图(chroot 重新挂载根节点)
  • pid namespace 保证了容器的 init 进程是以 1 号进程来启动的
  • network namespace 网络虚拟化
  • uts namespace 隔离了 hostname 和 domain
  • ipc namespace 进程间通信

network namespace 技术是实现网络虚拟化的重要功能,它可以创建多个隔离的网络空间,这些网络空间都有各自独立的私有的网络栈信息,包括:网卡(Network Interface)、回环设备(Loopback Device)、路由表(Routing Table)和 iptables 规则。

关于 network namespace 的增删改查功能已经集成到 Linux 工具的 netns 命令中,下面通过一个 demo 来演示一下 Linux Network Namespace 的功能。

[root@ ~]# ip netns add namespace-1
[root@ ~]# ip netns add namespace-2
[root@ ~]# ip netns exec namespace-1 ip addr
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

创建了两个网络空间,默认情况下都只会有一个回环接口,处于 DOWN 状态。现在要解决一下四个问题:

仅有一个本地回环设备是无法与宿主机或外界通信的,如果想与外界通信,就需要有网卡,这里扮演网卡角色的就是 Linux 中的虚拟设备 veth pair 对。

Veth Pair 设备的特点是:它被创建出来后,总是以两张虚拟网卡(Veth Peer)的形式成对出现的。并且,从其中一个网卡发出的数据包,可以直接出现在与它对应的另一张“网卡”上,哪怕这两个“网卡”在不同的 Network Namespace 里。

当每个 veth 设备在不同的 Network Namespace 的时候,Namespace 之间就可以用这对 veth 设备来进行网络通讯了,这就使得 Veth Pair 常常被用作连接不同 Network Namespace 的“网线”。

下面通过命令创建 veth pair 对,创建成功后可以看到,他们在宿主机上就表现为两张网卡,然后分别把两端移动到两个 network namespace 中,并为虚拟网卡配置 IP。此时在两个 network namespace 中就可以互相 ping 通。

[root@ ~]# ip link add veth0 type veth peer name veth1
[root@ ~]# ip addr
44: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 22:f7:2f:62:e6:5a brd ff:ff:ff:ff:ff:ff
45: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 5e:e4:9f:67:f0:d2 brd ff:ff:ff:ff:ff:ff

[root@ ~]# ip link set veth0 netns namespace-1
[root@ ~]# ip link set veth1 netns namespace-2

[root@iZ2zece2l8yr2f8qhrnr3lZ ~]# ip netns exec namespace-1 ifconfig veth0 172.14.0.2/24 up
[root@iZ2zece2l8yr2f8qhrnr3lZ ~]# ip netns exec namespace-2 ifconfig veth1 172.14.0.3/24 up

虽然现在这两块虚拟网卡可以互相通信了,但是仍然是不能连接外部网络的,并且和宿主机物理网卡也是不能通信的。要想通信有一下几种解决方式:

  • 虚拟网桥(交换机)
  • NAT 网络地址转换

下面介绍第一种,这也就是容器的主机内组网模型:veth pair + bridge 的模式。

Linux Bridge 网桥是一种软件配置,用于连结两个或更多个不同网段。它的行为就像是一台虚拟的二层网络交换机,工作于透明模式(即其他机器不必关注网桥的存在与否)。任意的真实物理设备(例如 eth0)和虚拟设备(例如 veth tap0)都可以连接到网桥。

下面演示下 bridge 网桥的作用,命令用的是 bridge-utils 软件包里的 brctl 工具来管理网桥。首先创建两个 veth pair 对,并分别将各自的一段移动到 network namespace 中,另一端插入到网桥上。

当成功创建一个网桥 test-bridge 并为其配置好 IP 的时候(ip 要在同一个网段),会默认在宿主机上维护一条此网段的路由规则(直连规则,二层网络通信,ARP 广播)。可以看到任何目的地到这个网段 (192.168.1.0/24) 的请求都会经过网桥设备转发,也就是说在宿主机上可以 ping 通。

[root@ ~]# route
Destination Gateway Genmask        Flags Metric Ref  Use Iface
172.14.0.0  0.0.0.0 255.255.255.0  U     0      0    0   test-bridge

由于网络空间中的路由表没有默认网关,因此无法从 172.14 范围之外到达其他计算机。要解决这个问题,需要给网络名称空间一个默认的网关路由。

[root@]# ip netns exec namespace-1 route add default gw 172.14.0.1
[root@]# ip netns exec namespace-2 route add default gw 172.14.0.1

[root@ ~]# ip netns exec namespace-1 route
Destination  Gateway  Genmask        Flags Metric Ref  Use Iface
default      gateway  0.0.0.0        UG    0      0      0 veth1
172.14.0.0   0.0.0.0  255.255.255.0  U     0      0      0 veth1  

梳理下上面所形成的一个网络栈,将两个 network namespace 和 bridge 组成了一个子网,bridge 上的 IP 就是这个子网的网关 IP。network namespace 中的数据包通过 veth 设备到达 bridge,bridge 中的数据包要把数据包转发到 eth0 上,这里需要做两个网络设备接口之间的数据包转发,用到了 Linux 协议栈里的一个常用参数 ip_forward。

sysctl -w net.ipv4.ip_forward=1

# filter(显式地允许 test-bridge 和 eth0 之间的包转发)
:FORWARD DROP [0:0]
-A FORWARD -i test-bridge -o eth0 -j ACCEPT
-A FORWARD -i eth0 -o test-bridge -j ACCEPT

此时,通过一些虚拟网络设备:Veth Pair 虚拟网卡、Bridge 网桥、Routing Table 路由规则,解决了 network namespace 之间的通信,以及 network namespace 与 宿主机之间的通信。但是现在 network namespace 还无法与局域网、外部网络通信。

与外部网络通信,就需要用到 NAT 网络地址转换技术,由于网络空间的 IP 地址都是私有的,经过物理网络时是不能被识别的,这个时候就需要对出去的包做地址伪装,对回来的包再做目标地址转换。

所有从 namespace 内部发出来的包,都要做地址伪装,将源 IP 地址,转换为物理网卡的 IP 地址。如果有多个 namespace,所有的 namespace 共享一个宿主机的 IP 地址,但是在 conntrack 表中,记录下这个出去的连接。

当服务器返回结果到达宿主机时,会根据 conntrack 表中的规则,取出原来的私网 IP,通过 DNAT 将地址转换为私网 IP 地址,通过网桥 bridge 实现对 network namespace 的访问。

iptables 是最常用的一种配置工具。其在 Docker、Kubernetes、Istio 网络中应用甚广,像 Docker 容器的端口映射,Kubernetes Service 的工作模式,Istio 的流量接管等都是通过 iptables 来实现的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容