不可错过!5张图带你搞懂容器网络原理

使用容器总是感觉像使用魔法一样。对于那些理解底层原理的人来说容器很好用,但是对于不理解的人来说就是个噩梦。很幸运的是,我们已经研究容器技术很久了,甚至成功揭秘容器只是隔离并受限的 Linux 进程,运行容器并不需要镜像,以及另一个方面,构建镜像需要运行一些容器。

现在是时候解决容器网络问题了。或者更准确地说,单主机容器网络问题。本文会回答这些问题:

  • 如何虚拟化网络资源,让容器认为自己拥有独占网络?

  • 如何让容器们和平共处,之间不会互相干扰,并且能够互相通信?

  • 从容器内部如何访问外部世界(比如,互联网)?

  • 从外部世界如何访问某台机器上的容器呢(比如,端口发布)?

最终结果很明显,单主机容器网络是已知的 Linux 功能的简单组合:

  • 网络命名空间(namespace)

  • 虚拟 Ethernet设备(veth)

  • 虚拟网络交换机(网桥)

  • IP路由和网络地址翻译(NAT)

  • 并且不需要任何代码就可以让这样的网络魔法发生……

前提条件

任意 Linux 发行版都可以。本文例子都是在 vagrant CentOS 8 的虚拟机上执行的:

$ vagrant init centos/8 $ vagrant up $ vagrant ssh 
[vagrant@localhost ~]$ uname -a Linux localhost.localdomain 4.18.0-147.3.1.el8_1.x86_64

为了简单起见,本文使用容器化解决方案(比如,Docker 或者 Podman)。我们会重点介绍基本概念,并使用最简单的工具来达到学习目标。

network 命名空间隔离容器

Linux 网络栈包括哪些部分?显然,是一系列网络设备。还有别的吗?可能还包括一系列的路由规则。并且不要忘记,netfilter hook,包括由iptables规则定义的。

我们可以快速创建一个并不复杂的脚本inspect-net-stack.sh

#!/usr/bin/env bash echo  "> Network devices" ip link 
echo -e "\n> Route table" ip route 
echo -e "\n> Iptables rules" iptables --list-rules

在运行脚本前,让我们修改下 iptable rule:

$ sudo iptables -N ROOT_NS

这之后,在机器上执行上面的脚本,输出如下:

$ sudo ./inspect-net-stack.sh     > Network devices     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 fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:e3:27:77 brd ff:ff:ff:ff:ff:ff     > Route table     default via 10.0.2.2 dev eth0 proto dhcp metric 100     10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100     > Iptables rules     -P INPUT ACCEPT     -P FORWARD ACCEPT     -P OUTPUT ACCEPT     -N ROOT_NS

我们对这些输出感兴趣,因为要确保即将创建的每个容器都有各自独立的网络栈。

你可能已经知道了,用于容器隔离的一个 Linux 命名空间是网络命名空间(network namespace)。从 man ip-netns 可以看到,“网络命名空间是网络栈逻辑上的另一个副本,它有自己的路由,防火墙规则和网络设备。”为了简化起见,这是本文使用的唯一的命名空间。我们并没有创建完全隔离的容器,而是将范围限制在网络栈上。

创建网络命名空间的一种方法是 ip 工具,它是 iproute2 的一部分:​​​​​​​

$ sudo ip netns add netns0 $ ip netns netns0如何使用刚才创建的命名空间呢?一个很好用的命令 nsenter。进入一个或多个特定的命名空间,然后执行指定的脚本:
$ sudo nsenter --net=/var/run/netns/netns0 bash     # 新建的 bash 进程在 netns0 里 $ sudo ./inspect-net-stack.sh     > Network devices 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     > Route table     > Iptables rules     -P INPUT ACCEPT     -P FORWARD ACCEPT     -P OUTPUT ACCEPT

从上面的输出可以清楚地看到 bash 进程运行在 netns0 命名空间,这时看到的是完全不同的网络栈。这里没有路由规则,没有自定义的 iptables chain,只有一个 loopback 的网络设备。

 

60af30c6a36a22bcd832f19dea8243b6.png

使用虚拟的 Ethernet 设备(veth)将容器连接到主机上

如果我们无法和某个专有的网络栈通信,那么它看上去就没什么用。幸运的是,Linux 提供了好用的工具——虚拟 Ethernet设备。从 man veth 可以看到,“veth 设备是虚拟 Ethernet 设备。他们可以作为网络命名空间之间的通道(tunnel),从而创建连接到另一个命名空间里的物理网络设备的桥梁,但是也可以作为独立的网络设备使用。”

虚拟 Ethernet 设备通常都成对出现。不用担心,先看一下创建的脚本:

$ sudo ip link add veth0 type veth peer name ceth0

用这条简单的命令,我们就可以创建一对互联的虚拟 Ethernet 设备。默认选择了 veth0 和 ceth0 这两个名称。​​​​​​​

$ 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 fq_codel state UP mode DEFAULT group default qlen 1000  link/ether 52:54:00:e3:27:77 brd ff:ff:ff:ff:ff:ff 5: ceth0@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000   link/ether 66:2d:24:e3:49:3f brd ff:ff:ff:ff:ff:ff 6: veth0@ceth0:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UMSA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值