Docker网络基础

隐身守侯 提交于 2019-11-29 08:52:46

一、 网络命名空间

为了支持网络协议栈的多个实例,Linux在网络栈中引入了网络命名空间,这些独立的协议栈被隔离到不同的命名空间中。

  • 好处:通过对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环境。并且,在Linux的网络命名空间中可以有自己独立的路由表及独立的iptables设置来提供包转发、NAT及IP包过滤等功能。
  • 难处:为了隔离出独立的协议栈,需要纳入命名空间的元素有进程、套接字、网络设备等。
  • 方法:Linux的网络协议栈是十分复杂的,为了支持独立的协议栈,相关的这些全局变量都必须被修改为协议栈私有。最好的办法就是让这些全局变量称为一个Net Namespaces变量的成员,然后为协议栈的函数调用加入一个Namespaces参数。这就是Linux实现网络命名空间的核心。

命令:

  1. 创建一个命名空间:
ip netns add <name>
  1. 在命名空间中执行命令:
ip netns exec <name> <command>
  1. 通过bash命令进入内部的shell界面:
ip netns exec <name> bash
  1. 退出到外面的命名空间时,请输入exit

由于一个设备只能属于一个命名空间,所以转移后在这个命名空间中就看不到这个设备了。具体哪些设备能被转移到不同的命名空间呢?在设备里面有个重要的属性:NETIF_F_ETNS_LOCAL,如果这个属性为on,就不能转移到其他命名空间中。而很多其他设备如lo设备、vxlan设备、ppp设备、bridge设备等都是不可转移的。将无法转移的设备移动到别的命名空间时,会得到无效参数的错误提示。

命令:

  1. 转移设备至命名空间:
ip link set <device> netns <namespace>
  1. 查看设备是否可以转移:
ethtool -k <device>

操作

# ip netns add netns1
# ip netns show
netns1
# ip netns exec netns1 ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# ip netns exec netns1 bash
# ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# exit
exit
# ip link set br0 netns netns1
RTNETLINK answers: Invalid argument
# ethtool -k br0
netns-local: on [fixed]
# ip netns del netns1

由于网络命名空间代表的是一个独立的协议栈,所以它们之间是相互隔离的,彼此无法通信,在协议栈内部都看不到对方。为了打破这种限制,让处于不同命名空间的网络相互通信,甚至和外部的网络进行通信,我们应用“Veth设备对”即可达到。

二、Veth设备对

Veth设备对的一个重要作用就是打通相互看不到的协议栈之间的壁垒,它就像一条管子,一端连着这个网络命名空间的协议栈,一端连着另一个网络命名空间的协议栈。
由于要连接两个网络命名空间,所以Veth设备都是成对出现的,就像是一对以太网卡,并且中间有一根直连的网线。既然是一对网卡,那么我们将其中一端称为另一端的peer。在Veth设备的一端发送数据时,它会将数据直接发送到另一端,并触发另一端的接收操作。

命令:
创建Veth设备对:

ip link add <veth0> type veth peer name <veth1>
  • 生成的两个设备中,一个是veth0,它的peer是veth1

操作:

# ip netns add netns1
# ip link add veth0 type veth peer name veth1
# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether f8:b1:56:d8:da:0a brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:82:ad:fa:6c brd ff:ff:ff:ff:ff:ff
14: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 7a:f0:93:10:6f:69 brd ff:ff:ff:ff:ff:ff
15: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9e:dd:2b:54:78:31 brd ff:ff:ff:ff:ff:ff
# ip link set veth1 netns netns1
# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether f8:b1:56:d8:da:0a brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:82:ad:fa:6c brd ff:ff:ff:ff:ff:ff
15: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9e:dd:2b:54:78:31 brd ff:ff:ff:ff:ff:ff
# ip netns exec netns1 ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
14: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 7a:f0:93:10:6f:69 brd ff:ff:ff:ff:ff:ff
# ip netns exec netns1 ip addr add 10.1.1.2/24 dev veth1
# ip addr add 10.1.1.3/24 dev veth0
# ip link set dev veth0 up
# ping 10.1.1.2
PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data.
64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=0.064 ms
64 bytes from 10.1.1.2: icmp_seq=2 ttl=64 time=0.045 ms
^C
--- 10.1.1.2 ping statistics ---
9 packets transmitted, 9 received, 0% packet loss, time 7999ms
rtt min/avg/max/mdev = 0.032/0.042/0.064/0.012 ms
# ip netns exec netns1 ping 10.1.1.3
PING 10.1.1.3 (10.1.1.3) 56(84) bytes of data.
64 bytes from 10.1.1.3: icmp_seq=1 ttl=64 time=0.074 ms
64 bytes from 10.1.1.3: icmp_seq=2 ttl=64 time=0.038 ms
^C
--- 10.1.1.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.038/0.056/0.074/0.018 ms

Veth设备对如何查看对端:

# ethtool -S veth0
NIC statistics:
     peer_ifindex: 14
# ip netns exec netns1 ip link | grep 14
14: veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000

三、网桥

Linux可以支持多个不同的网络,它们之间能够相互通信,如何将这些网络连接起来并实现各网络中主机的相互通信呢?可以用“网桥”。 网桥是一个二层的虚拟网络设备,把若干个网络接口“连接”起来,以使得网络接口之间的报文能够相互转发。网桥能够解析收发的报文,读取目标MAC地址的信息,和自己记录的MAC表结合,来决策报文的转发目标网络接口。为了实现这些功能,网桥会学习源MAC地址(二层网桥转发的依据就是MAC地址)。在转发报文时,网桥只需要向特定的网口进行转发,来避免不必要的网络交互。如果它遇到一个自己从未学习到的地址,就无法知道这个报文应该向哪个网络接口转发,就将报文广播给所有的网络接口(报文来源的网络接口除外)
在Linux的内部网络栈里实现的网桥设备,作用和上面的描述相同。过去Linux主机一般都只有一个网卡,现在多网卡的及其越来越多,而且又很多虚拟的设备存在,所以Linux的网桥提供了在这些设备之间相互转发数据的二层设备。
Linux内核是通过一个虚拟的网桥设备(Net Device)来实现桥接的。这个虚拟设备可以绑定若干个以太网接口设备,从而将它们桥接起来。这种Net Device网桥和普通的设备不同,最明显的一个特征是它还可以有一个IP地址。
命令:

  1. 新增一个网桥设备:
brctl addbr <br_name>
  1. 为网桥增加网口:
brctl addbr <br_name> <eth_name>
  1. 网桥的物理网卡作为一个网口,由于在链路层工作,就不再需要IP地址了,这样上面的IP地址自然失效:
ifconfig <eth_name> 0.0.0.0
  1. 配置网桥IP地址:
ifconfig <eth_name> <ip_address>

这样网桥就有一个IP地址,而连接到上面的网卡就是一个纯链路层设备了。

操作:

# brctl addbr bridge
# brctl addif veth0
# brctl show
bridge name     bridge id               STP enabled     interfaces
bridge          8000.9edd2b547831       no              veth0
docker0         8000.02425e4d0ba8       no              vethb8777d1
# ifconfig veth0 0.0.0.0
# ifconfig bridge 10.1.1.1/16
# ip addr show bridge
16: bridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 9e:dd:2b:54:78:31 brd ff:ff:ff:ff:ff:ff
    inet 10.1.1.1/16 brd 10.1.255.255 scope global bridge
       valid_lft forever preferred_lft forever
    inet6 fe80::9cdd:2bff:fe54:7831/64 scope link
       valid_lft forever preferred_lft forever
# ping 10.1.1.2
PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data.
64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=0.064 ms
64 bytes from 10.1.1.2: icmp_seq=2 ttl=64 time=0.040 ms
^C
--- 10.1.1.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.040/0.052/0.064/0.012 ms

注意:

  • 如果网桥上的网口不卸掉IP,相当于在网络层工作,而网桥只能在链路层工作,所以网口IP不失效,将导致网桥不起作用(表现:Veth设备对不通)
# ping -I 10.1.1.3 10.1.1.2
connect: Network is unreachable
  • 网桥是不具备路由功能的,具体表现为:主机可以ping通veth1,而veth1却ping不同主机。
# ping 10.1.1.2
PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data.
64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=0.060 ms
64 bytes from 10.1.1.2: icmp_seq=2 ttl=64 time=0.034 ms
^C
--- 10.1.1.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.034/0.047/0.060/0.013 ms
# ip route add 192.168.0.0/24 dev bridge  proto kernel  scope link  src 10.1.1.1
# ip netns exec netns1 ping 192.168.1.2
connect: Network is unreachable
# ip netns exec netns1 ping 10.1.1.1
PING 10.1.1.1 (10.1.1.1) 56(84) bytes of data.
64 bytes from 10.1.1.1: icmp_seq=1 ttl=64 time=0.065 ms
64 bytes from 10.1.1.1: icmp_seq=2 ttl=64 time=0.036 ms
^C
--- 10.1.1.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.036/0.050/0.065/0.016 ms
  • <host_ip> : 192.168.1.2
  • <bridge_ip> : 10.1.1.1

四、iptables和Netfilter

Linux网络协议栈非常高效,同时比较复杂。如果我们希望在数据的处理过程中对关心的数据进行一些操作,该怎么办呢?Linux提供了一套机制来为用户实现自定义的数据包处理过程。
在Linux网络协议栈中有一组回调函数挂接点,通过这些挂接点挂接的钩子函数可以在Linux网络栈处理数据包的过程中对数据包进行一些操作,例如过滤、修改、丢弃等。整个挂接点技术叫作Netfilter和iptables。
Netfilter负责在内核中执行各种挂接的规则,运行在内核模式中;而iptables是在用户模式下运行的进程,负责协助和维护内核中Netfilter的各种规则表。二者相互配合来实现整个Linux网络协议栈中灵活的数据包处理机制。
iptables命令用于协助用户维护各种规则。我们在使用Kubernetes、Docker的过程中,通常都会去查看相关的Netfilter配置。这里只介绍如何查看规则表,详细的介绍请参照 iptables详解

五、路由

路由功能由IP层维护的一张路由表来实现。当主机收到数据报文时,它用此表来决策接下来应该做什么操作。当从网络侧接收到数据报文时,IP层首先会检查报文的IP地址是否与主机自身的地址相同。如果数据报文中的IP地址是主机自身的地址,那么报文将被发送到传输层相应的协议中。如果报文中的IP地址不是主机自身的地址,并且主机配置了路由功能,那么报文将被转发,否则,报文将被丢弃。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!