关于容器:容器虚拟化网络漫谈上

5次阅读

共计 13097 个字符,预计需要花费 33 分钟才能阅读完成。

当咱们装置好 Docker 后,它会为咱们解决好所有与网络虚拟化无关的事,但在这背地,Docker 实际上是利用了多个 Linux 提供的个性来实现这所有,这也是当初 Docker 刚公布时被批评为「新瓶装旧酒」的起因,因为实际上 Docker 只是包装了操作系统的能力并提供了一套易用的 API,并没有创造什么新货色。

ps: 当然我并不批准这个观点 :)

这篇文章中会大量应用 ip 这个命令,ip 命令来自于 iproute2 包,个别零碎会默认装置,如果没有的话,请自行装置,此外 ip 命令因为须要批改零碎网络设置所以须要 root 权限,所以请不要在生产环境或者重要的零碎中尝试,以防产生预期外的谬误。

一、Linux Namespace

Namespace 是 Linux 提供的一种对于零碎全局资源的隔离机制;从过程的视角来看,同一个 namespace 中的过程看到的是该 namespace 本人独立的一份全局资源,这些资源的变动只在本 namespace 中可见,对其余 namespace 没有影响。Docker 就是采纳 namespace 机制实现了对网络,过程空间等的隔离。不同的 container 属于不同 namespace,实现了 container 之间的资源相互隔离,互不影响。

通过 namespace 能够隔离容器的过程 PID、文件系统挂载点、主机名等多种资源。不过咱们明天只关注网络 namespace,简称 netns。它能够为不同的命名空间从逻辑上提供独立的网络协议栈,具体包含网络设备、路由表、arp 表、iptables、以及套接字(socket)等。使得不同的网络空间就都如同运行在独立的网络中一样。

首先咱们先尝试创立一个新的的 netns:

ip netns add netns1

接下来咱们检查一下这个 netns 的路由表、Iptables 及网络设备等信息:

[root@centos ~]$ ip netns exec netns1 route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface

[root@centos ~]$ ip netns exec netns0 iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

[root@centos ~]$ ip netns exec netns1 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

能够看到,因为是新创建的 netns,以上所有信息都为空,只存在一个状态为 down 的 lo 设施

通过 netns 咱们能够隔离不同容器之间的协定栈,防止相互影响和净化,接下咱们会尝试如何在不同的 netns 互相通信。

二、Veth

Linux 提供了一种用软件来模仿硬件网卡的办法:Veth(Virtual Ethernet devices),Veth 是 Linux 中一种虚构进去的网络设备,veth 总是成对呈现,所以个别也叫 veth-pair,其作用非常简单:如果 v-a 和 v-b 是一对 veth 设施,v-a 发送的数据会由 v-b 收到。反之亦然,其实说白了,Veth 就是一根“网线”,你从一头发数据,天然能够从另一头收到数据。

veth 的中间都间接连着网络协议栈,所以你创立一个 veth 对,主机上就会多两个网卡,实际上这种虚构设施咱们并不生疏,咱们本机网络 IO 里的 lo 回环设施 (127.0.0.1) 也是这样一个虚构设施。惟一的区别就是 veth 总是成对地呈现。

在 Linux 下咱们能够应用 ip 命令创立一对 veth,应用 ip link add 创立一对 veth0@veth1 的网卡,ip link 示意这是一个链路层的接口:

$ ip link add veth1 type veth peer name veth1-peer

应用 ip link show 来进行查看,此时能够看到,veth1@veth1-peer 相互连接:

[root@centos ~]$ ip link show
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 mq state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:09:10:27 brd ff:ff:ff:ff:ff:ff
5: veth1-peer@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 06:20:02:e7:bf:bd brd ff:ff:ff:ff:ff:ff
6: veth1@veth1-peer: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether aa:c4:57:ee:46:60 brd ff:ff:ff:ff:ff:ff

将 veth1 这头增加到咱们方才创立的 netns1 中:

$ ip link set veth1-peer netns netns1

此时再进行查看会发现 veth1 曾经不见了,因为这个设施曾经到了 netns0 中:

[root@centos ~]$ ip link show
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 mq state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:97:55:37 brd ff:ff:ff:ff:ff:ff
4: veth0@if3: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether de:2d:ab:06:fb:16 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    
[root@centos ~]$ ip netns exec netns1 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
5: veth1-peer@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 06:20:02:e7:bf:bd brd ff:ff:ff:ff:ff:ff link-netnsid 0

接下来为这对 veth 配置 IP 并启动设施

$ ip addr add 172.16.0.1/24 dev veth1
$ ip link set dev veth1 up

# 在不同的 netns 下须要应用 ip netns exec $name 到指定的 netns 下执行
$ ip netns exec netns1 ip addr add 172.16.0.2/24 dev veth1-peer
$ ip netns exec netns1 ip link set dev veth1-peer up

当设施启动后,咱们就能够通过相熟的 ifconfig 查看到它们了:

[root@centos ~]$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.1.48  netmask 255.255.255.0  broadcast 10.0.1.255
        inet6 fe80::5054:ff:fe09:1027  prefixlen 64  scopeid 0x20<link>
        ether 52:54:00:09:10:27  txqueuelen 1000  (Ethernet)
        RX packets 44996  bytes 61990718 (59.1 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8462  bytes 684565 (668.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 2  bytes 256 (256.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2  bytes 256 (256.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

veth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.1  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::a8c4:57ff:feee:4660  prefixlen 64  scopeid 0x20<link>
        ether aa:c4:57:ee:46:60  txqueuelen 1000  (Ethernet)
        RX packets 8  bytes 656 (656.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8  bytes 656 (656.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        
        
[root@centos ~]$ ip netns exec netns1 ifconfig
veth1-peer: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.2  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::420:2ff:fee7:bfbd  prefixlen 64  scopeid 0x20<link>
        ether 06:20:02:e7:bf:bd  txqueuelen 1000  (Ethernet)
        RX packets 8  bytes 656 (656.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8  bytes 656 (656.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

此时的网络拓扑为:

+------------------+              +------------------+
|       host       |              |      netns1      |
|                  |  veth pair   |                  |
|                +-+              +-+                |
| 172.16.0.1/24 | +--------------+  | 172.16.0.2/24  |
|    (veth1)     +-+              +-+ (veth1-peer)   |
|                  |              |                  |
|                  |              |                  |
|                  |              |                  |
+------------------+              +------------------+

当初咱们能够尝试这对 veth 是否能够互相通信:

[root@centos ~]$ ip netns exec netns1 ping 172.16.0.1 -I veth1-peer -c 1
PING 172.16.0.1 (172.16.0.1) from 172.16.0.2 veth1-peer: 56(84) bytes of data.
64 bytes from 172.16.0.1: icmp_seq=1 ttl=64 time=0.031 ms

--- 172.16.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.031/0.031/0.031/0.000 ms

[root@centos ~]$ ping 172.16.0.2 -I veth1 -c 2
PING 172.16.0.2 (172.16.0.2) from 172.16.0.1 veth1: 56(84) bytes of data.
64 bytes from 172.16.0.2: icmp_seq=1 ttl=64 time=0.015 ms

--- 172.16.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.015/0.015/0.015/0.000 ms

如上所见,无论是从 netns 中向宿主机发动通信,还是从宿主机向 netns 中的设施发动通信,都是能够行,到目前为止咱们曾经实现了点对点的通信。

三、Linux Bridge

因为 veth 总是成对呈现,互相绑定,在真实世界中,同一台服务器上可能有几十上百个容器须要互相通信,如果咱们为每个须要互相通信的容器都建设一对 veth,那恐怕不事实,就像真实世界中咱们不会为集群中的每台服务器都互相用网线连贯一样。

在物理世界中咱们应用交换机解决这个问题的,而 Linux 提供了让咱们应用软件模仿交换机能力的性能,即:Linux Bridge,引入了 Linux Bridge 后,咱们不再须要点对点的连贯,而是将所有的 veth 的另外一头都连贯到 Bridge 上,由 Bridge 负责在不同的“对”之间转发数据包。这样各个容器之间就能够相互通信了。

在之前的试验中,咱们创立一个 netns0,而后创立了一对 veth,一头连在 netns0 中,这是一个典型的点对点通信的,接下来咱们尝试应用 Bridge 来逾越多个 netns 进行通信。
首先咱们再创立两个新的 netns:netns2 和 netns 3,并为它们调配和启动网卡:

# 创立两个新的 netns
[root@centos ~]$ ip netns add netns2
[root@centos ~]$ ip netns add netns3

# 创立两对新的 veth
[root@centos ~]$ ip link add veth2 type veth peer name veth2-peer
[root@centos ~]$ ip link add veth3 type veth peer name veth3-peer

# 将 veth 的一头别离放进另一个 netns 中
[root@centos ~]$ ip link set veth2-peer netns netns2
[root@centos ~]$ ip link set veth3-peer netns netns3

# 调配 IP 并启动
[root@centos ~]$ ip netns exec netns2 ip addr add 172.16.0.102/24 dev veth2-peer
[root@centos ~]$ ip netns exec netns2 ip link set veth2-peer up
[root@centos ~]$ ip netns exec netns3 ip addr add 172.16.0.103/24 dev veth3-peer
[root@centos ~]$ ip netns exec netns3 ip link set veth3-peer up

好了,这样咱们就在一台 Linux 就创立进去了两个虚构的网络环境,此时如果咱们间接在 netns2 中向 netns3 申请是不通的,因为 namespace 齐全隔离了不同的网络,接下来咱们须要应用 Bridge 将这两个虚构网络连接起来:

首先须要创立一个 Bridge,并将两对 veth 的另外一头“插到”这个 Bridge 上:

brctl 命令来自于 bridge-utils 包,在某些操作系统上可能须要自行装置。

# 创立一个 Bridge
[root@centos ~]$ brctl addbr br0

# 将方才两对 veth 插到 br0 上
[root@centos ~]$ ip link set dev veth2 master br0
[root@centos ~]$ ip link set dev veth3 master br0

# 同时也 br0 调配一个地址:[root@centos ~]$ ip addr add 172.16.0.100/24 dev br0

# 启动所有的网卡
[root@centos ~]$ ip link set veth2 up
[root@centos ~]$ ip link set veth3 up
[root@centos ~]$ ip link set br0 up

# 查看操作是否胜利
[root@centos ~]$ brctl show
bridge name    bridge id        STP enabled    interfaces
br0        8000.c63e968442c6    no               veth2
                                                   veth3

此时的拓扑构造为:

+------------------+     +------------------+
|      netns2      |     |     netns3       |
| 172.16.0.102/24  |     | 172.16.0.103/24  |
+---(veth2-peer)---+     +---(veth3-peer)---+
          +                        +
          |                        |
          +                        +
+------(veth2)------------------(veth2)------+
|              linux-bridge                  |
|         (br0/172.16.0.100/24)              |
+--------------------------------------------+

以上操作实现后,咱们就能够尝试两个不同 netns 中是否能够互相通信了:

# 在 netns2 中应用 veth2-peer 向 nets3 中的 172.16.0.103 发动 ping
[root@centos ~]$ ip netns exec netns2 ping 172.16.0.103 -I veth2-peer -c 1
PING 172.16.0.103 (172.16.0.103) from 172.16.0.102 veth2-peer: 56(84) bytes of data.
64 bytes from 172.16.0.103: icmp_seq=1 ttl=64 time=0.038 ms

--- 172.16.0.103 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.038/0.038/0.038/0.000 ms

# 在 netns3 中应用 veth3-peer 向 nets2 中的 172.16.0.102 发动 ping
[root@centos ~]$ ip netns exec netns3 ping 172.16.0.102 -I veth3-peer -c 1
PING 172.16.0.102 (172.16.0.102) from 172.16.0.103 veth3-peer: 56(84) bytes of data.
64 bytes from 172.16.0.102: icmp_seq=1 ttl=64 time=0.023 ms

--- 172.16.0.102 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.023/0.023/0.023/0.000 ms

能够看到,通信都是胜利的,到此咱们就实现了不同 netns 下的通信,后续有新的 netns 呈现时,只须要将一头插到 br0 上即可与其余曾经在 br0 上的 netns 实现通信。

四、与内部网络通信

咱们曾经解决了容器之间的通信,看起来所有都很好,然而还有最初一个问题须要解决:容器对外部的通信,咱们能够简略的尝试一下:

[root@centos ~]$  ip netns exec netns3 ping baidu.com -I veth3_p -c 1
ping: baidu.com: Name or service not known

能够发现在 netns 中是无奈与内部通信的,只能是在 br0 绑定的网络之间进行通信,而在真实世界中,向内部发动连贯,或是承受内部连贯都是必要的需要,例如通过 Docker 监听端口,在容器内发动公网申请等。

为了实现这个需要,咱们须要引两样新的工具:路由表和 iptables

路由的概念非常简单:应该将数据发送到哪张网卡?(虚构网卡设施也算),如何进行路由抉择的规定都写在了路由表中,Linux 中能够有多张路由表,最重要和罕用的是 local 和 main,通过 route - n 能够查看本地路由表,本地路由表记录了本网络命名空间 (namespace) 中的网卡设施 IP 的路由规定,而其余的路由表个别都写在 main 中,通过以下命令能够看到之前咱们试验时主动创立的路由表:

[root@centos ~]$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.0.1.1        0.0.0.0         UG    0      0        0 eth0
10.0.1.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 eth0
172.16.0.0      0.0.0.0         255.255.255.0   U     0      0        0 br0

因为 Linux 的网络栈是运行在内核态的,咱们执行的命令都是在用户态执行,所以实践上咱们是无奈干预网络栈行为的。然而 Linux 为了满足各种需要,从内核态中凋谢了一些钩子让用户态能够进行干涉,而 iptables 就是咱们调用这些钩子的工具,对于 iptables 的细节和用法能够参考 iptables(8) – Linux man page,这里不再赘述。

咱们先尝试解决容器向内部地址发动通信申请的需要,这里的外网是指的虚构网络宿主机以外的网络,并不一定须要真的达到公共互联网。咱们持续复用之前创立的试验环境,假如咱们的宿主机 eth0 网卡地址为 10.0.1.48,局域网上另外一台主机的 ip 为 10.0.1.26

首先咱们尝试在 netns2 中向 10.0.1.26 发动 ping,在开始之前咱们先在宿主机上进行尝试确保局域网之间没有通信问题:

[root@centos ~]$ ping 10.0.1.26 -c 1
PING 10.0.1.26 (10.0.1.26) 56(84) bytes of data.
64 bytes from 10.0.1.26: icmp_seq=1 ttl=64 time=0.193 ms

--- 10.0.1.26 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.193/0.193/0.193/0.000 ms

# 进入 netns 尝试
[root@centos ~]$ ip netns exec netns2 ping 10.0.1.26 -I veth2-peer -c 1
PING 10.0.1.26 (10.0.1.26) from 172.16.0.102 veth2-peer: 56(84) bytes of data.

--- 10.0.1.26 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

如咱们意料一样,在宿主机上能够与内部网站通信,而在 netns 内无奈与内部网络间接通信。
此时咱们查看 netns2 的路由表看看:

[root@centos ~]$ ip netns exec netns2 route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.16.0.0      0.0.0.0         255.255.255.0   U     0      0        0 veth2-peer

能够看到,路由表中仅有一条记录,即 Destination 为 172.16.0.0 的路由,而咱们的指标 ip 是 10.0.1.26,很显然这无奈匹配到这条记录,所以失败了。如果你还没遗记的话,咱们的虚构网卡的另一头是连贯到 br0 上的,跟据 veth 的特点,咱们只能与 br0 建立联系,所以咱们尝试在路由表将所有未匹配的申请都转发到 br0,建设一条默认路由:

[root@centos ~]$ ip netns exec netns2 route add default gw 172.16.0.100 veth2-peer
[root@centos ~]$ ip netns exec netns2 route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.16.0.100    0.0.0.0         UG    0      0        0 veth2-peer
172.16.0.0      0.0.0.0         255.255.255.0   U     0      0        0 veth2-peer

咱们持续剖析,当流量到了 br0 后会产生什么,检查一下宿主机上的路由表:

[root@centos ~]$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.0.1.1        0.0.0.0         UG    0      0        0 eth0
10.0.1.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 eth0
172.16.0.0      0.0.0.0         255.255.255.0   U     0      0        0 br0

流量达到在宿主机的 br0 后,默认路由是持续发往下一跳地址即 0.0.0.0,而通过这条路由咱们是能失常达到 10.0.1.26 的,然而这里存在一个问题,10.0.1.26 和咱们发出请求的 br0 (172.16.0.100) 基本不在同一个子网,所以咱们须要一个做一个三层转发,Liunx 自身就反对这个性能,只是默认不开启,能够通过 sysctl net.ipv4.conf.all.forwarding=1 关上。

持续剖析,此时流量的登程门路应该是 veth2-peer -> br0 -> eth0 -> 10.0.1.26,当 10.0.1.26 响应时,它并不意识 172.16.0.0/24 这个网段,所以咱们还须要进行一次 NAT(Network address translation),NAT 的原理非常简单: 当一个外部地址须要与内部地址进行通信时,将进口流量的源地址和端口替换为网关所领有的,能够和外地址通信的地址,当内部流量返回时,通过查看 NAT 表匹配应该把返回的流量路由到外部网络中的哪个地址,这项技术目前被运营商大规模应用以环境公网 IPv4 地址枯竭的问题。

在 Linux 中咱们能够通过 iptables 实现软件 NAT,因为咱们要批改的是进口流量,所以应该做一次 source NAT,即 SNAT:

[root@centos ~]$ iptables -t nat -A POSTROUTING -s 172.16.0.0/24 ! -o br0 -j MASQUERADE
# -t nat:抉择 nat 表,不指定,默认是 filter 表。# -A:Append 新增一条规定,-D Delete,-L List。# POSTROUTING:抉择 POSTROUTING chain,POSTROUTING 代表数据包进口阶段。# -s 172.16.0.0/24:匹配条件,source address 是网段 172.16.0.102/24 中的 IP。# -j MASQUERADE:匹配后执行命令,执行 MASQUERADE,也就是源 IP 地址假装为进口网卡 IP。对于 nat 表来说,可选项有 DNAT/MASQUERADE/REDIRECT/SNAT。

此时咱们再尝试 ping 一下会发现通信曾经能够间接建设了:

[root@centos ~]$ ip netns exec netns2 ping 10.0.1.26 -I veth2-peer -c 1
PING 10.0.1.26 (10.0.1.26) from 172.16.0.102 veth2-peer: 56(84) bytes of data.
64 bytes from 10.0.1.26: icmp_seq=1 ttl=63 time=0.249 ms

--- 10.0.1.26 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.249/0.249/0.249/0.000 ms

解决了从外部与内部网络通信的问题后,最初一个须要思考的问题就是如何让内部网络能够间接与容器进行交互,172.16.0.102 这个 IP 外界是不意识它的,只有这个宿主机晓得它是谁,所以很显然咱们须要再做一次 NAT。

这次的目标是批改入口流量,所以须要做一次 DNAT(Destination Network Address Translation),在进行
SNAT 时,咱们是针对某个段做全局的 NAT,无论端口,然而在进行
DNAT 时,咱们须要申明容器中的端口在宿主机上是对应哪个,不然无奈精确的路由流量。

仍然应用 iptables 进行 NAT:

[root@centos ~]$ iptables -t nat -A PREROUTING  ! -i br0 -p tcp -m tcp --dport 8088 -j DNAT --to-destination 172.16.0.102:80
# -t nat:抉择 nat 表,不指定,默认是 filter 表。# -A:Append 新增一条规定,-D Delete,-L List。# POSTROUTING:抉择 POSTROUTING chain,POSTROUTING 代表数据包进口阶段。# -p 协定,tcp 或 udp
# --dport 8088,指标端口,即宿主机所监听的端口
# -s 172.16.0.0/24:匹配条件,source address 是网段 172.16.0.102/24 中的 IP。# -j DNAT:匹配后执行命令,执行 DNAT,也就是将起源流量转发到 172.16.0.102 上的 80 端口。

执行后咱们能够进行测试,首先在 netns2 中监听 80 端口:

[root@centos ~]$ ip netns exec netns2 nc -lp 80

而后登录到咱们之前测试流出流量的机器 10.0.1.26,进行 telnet:

[root@10.0.1.26 ~]$ telnet 10.0.1.48 8088
Trying 10.0.1.48...
Connected to 10.0.1.48.
Escape character is '^]'.

能够看到,流量正确的导向了 netns2 这个 namespace 下监听的端口。

至此咱们将主机内的虚拟化网络梳理了一番,在下一期咱们将摸索跨主机的虚拟化网络以及 Kubernetes 下各种不同的网络解决方案。

本系列文章均由 FinClip 工程师出品。

正文完
 0