Docker网络1
一.Dokcer网络基础
Docker本身的技术依赖于linux内核虚拟化技术的发展.所有Docker对Linux内核的特性有很强的依赖。其中Docker使用到的与linux网络有关的技术分别有 : 网络名称空间 , Veth设备 , IPtables ,网桥 , 路由
1.网络名称空间
为了支持网络协议的多个实例linux在网络协议栈中引用了网络名称空间(network Namespace),这些独立的协议栈被隔离到不同的命名空间中。处于不同命名空间的网络协议栈是完全隔离的,彼此之间无法进项网络通信,就好像两个“平行宇宙”。通过这种对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环境,而docker正是利用这种网络名称空间的特性,实现了不同容器之间的网络隔离,在linux的网络命名空间内可以有自己独立的iptables来转发,NAT及IP包过滤功能。
Linux的网络协议栈是十分复杂的为了支持独立的协议栈,相关的这些全局变量都必须修改为协议栈私有最好的办法就是让这些全局变量成为一个Net Namespace 变量的成员,然后为了协议栈的函数调用加入一个 Namespace参数。这就是linux网络名称空间的核心。所有的网络设备都只能属于一个网络名称空间。当然通常的物理网络设备只能关联到root这个命名空间中。虚拟网络设备则可以被创建并关联到一个给定的命名空间中。而且可以在这些名称空间之间移动。
[root@docker ~]# ip netns add test01
[root@docker ~]# ip netns add test02
[root@docker ~]# ip netns list
test02
test01
2.Veth设备
引入veth设备对是为了在不同的网络名称空间之间进行通信,利用它可以直接将两个网络名称空间链接起来,由于要连接的两个网络命名空间,所以Veth设备是成对出现的,很像一对以太网卡,并且中间有一根直连的网线,既然是一对网卡,那么我们将其中一端称为另一端的peer。在Veth设备的一端发送数据时,它会将数据直接发送到另一端,并触发另一端的接收操作。
[root@docker ~]# ip link add veth type veth peer name veth001
[root@docker ~]# ip link show
12: veth001@veth: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether be:61:ae:bd:10:ca brd ff:ff:ff:ff:ff:ff
13: veth@veth001: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 82:a5:3e:86:c9:f0 brd ff:ff:ff:ff:ff:ff
# 生成了两个veth设备,互为对方 peer
[root@docker ~]# ip link set veth001 netns test01
[root@docker ~]# ip link show | grep veth
9: vethb84cbb7@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
11: vethf98b54c@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
13: veth@if12: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
[root@docker ~]# ip netns exec test01 bash
[root@docker ~]# ip link show
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
12: veth001@if13: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether be:61:ae:bd:10:ca brd ff:ff:ff:ff:ff:ff link-netnsid 0
# 设置IP
[root@docker ~]# ip netns exec test01 ip addr add 172.16.0.111/20 dev veth001
# 绑定
[root@docker ~]# ip netns exec test01 ip link set dev veth001 up
# 查看
[root@docker ~]# ip netns exec test01 ip a
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
12: veth001@if13: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000
link/ether be:61:ae:bd:10:ca brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.16.0.111/20 scope global veth001
valid_lft forever preferred_lft forever
[root@docker ~]# ip netns exec test01 ethtool -S veth001
NIC statistics:
peer_ifindex: 13
[root@docker ~]# ip a | grep 13
13: veth@if12: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
[root@docker ~]# ip addr add 172.16.0.112/20 dev veth
[root@docker ~]# ip link set dev veth down
[root@docker ~]# ip link set dev veth up
[root@docker ~]# ping 172.16.0.111
PING 172.16.0.111 (172.16.0.111) 56(84) bytes of data.
64 bytes from 172.16.0.111: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.16.0.111: icmp_seq=2 ttl=64 time=0.150 ms
3.网桥
Linux可以支持多个不同的网络,他们之间能够相互通信,就需要一个网桥。网桥是二层的虚拟网络设备,它是把若干个网络接口"连接"起来,从而报文能够互相转发。网桥能够解析收发的报文,读取目标MAC地址信息,和自己记录的MAC 表结合,来决定报文的转发目标网口。
网桥设备brO绑定了 eth0,eth1,对于网络协议栈的上层来说,只看得到 brO 。因为桥接是在数据链路层实现的,上层不需要关心桥接的细节,于是协议栈上层需要发送的报文被送到brO,网桥设备的处理代码判断报文该转发到eth0还是 eth1, 或者两者皆转发。反过来 从eth0 或从 eth1 接收到的报文被提交给网桥的处理代码,在这里会判断报文应该被转发,丢弃还是提交到协议栈上层,而有时 eth1 也可能会作为报文的源地址 或目的地址 直接参与报文的发送与接收,从而绕过网桥。
4. iptables
Linux网络协议栈非常高效,同时比较复杂,如果我们希望在数据的处理过程中对关心的数据进行一些操作该怎么做呢?Linux提供了一套机制来为用户实现自定义的数据包处理过程。
在Linux网络协议其中有一组回调函数挂接点,童虎这些挂接点挂接点钩子函数可以在linux 网络及处理数据包的过程中对数据包进行些操作,列如过滤 修改 丢弃等 整个挂接点技术叫做 Netfiler iptables
Netfiler 负责在内核中执行各种挂接的规则,运行在内核模式中:而iptables 是在用户模式下运行的进程,复则协助维护内核中 Netfiler 的各种规则表 通过 规则的配合来实现整个 Linux网络协议栈中灵活的数据包处理。
二.总结
设备 | 作用总结 |
---|---|
network namespace | 主要提供了关于网络资源的隔离,包括网络设备,IPv4和IPv6协议栈,IP路由表,防火墙,/proc/net目录,/sysclass/net, 端口(socket)等。 |
Linux Bridge | 功能相当于物理交换机,为连在上面的设备(容器)转发数据帧,如docker0网桥 |
iptables | 主要为容器提供NAT以及容器网络安全。 |
veth pair | 两个虚拟网卡组成的数据通道。在Docker中,用于连接Docker容器和linuxBridge。一端在容器中作为eth0网卡,另一端在Linux bridge中作为网桥的一个端口。 |
三.Docker网络模式
Docker使用Linux桥接的方式,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥时每个容器的默认网关。因为在统一宿主机内的容器都接入通一个网桥,这样容器之间就能够通过容器的Container-IP 直接通信。
Docker网桥时宿主机虚拟出来的,并不是正式存在的网络设备,外部网络是无法寻址到的,这也意味着外不网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run 创建容器时候通过 -p 或 -P参数来启用。访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。
Docker网络模式 | 配置 | 说明 |
---|---|---|
host模式 | –network=host | 容器和宿主机共享Network namespace。 |
containe模式 | –network=container:ID | 容器和另外一个容器共享Network namespace。dubernetes 中的pod就是多个容器共享一个Network namespace。 |
none模式 | –network=none | 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。 |
bridge模式 | –network=bridge | 当 Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Dokcer容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。(默认为该模式) |
1.host模式
如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Nmaespace,而是和宿主机共用一个Network Namespace 。 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统,进程列表等还是和宿主机隔离的。
使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host 最大的优势就是网络性能比较好,但是docker host上几经使用的端口就不能再用了,网络的隔离性不好。
[root@docker ~]# docker run -d -it --name nginx3 --network host nginx
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
401daa833a9b nginx "/docker-entrypoint.…" 3 seconds ago Up 2 seconds nginx3
[root@docker ~]# curl 127.0.0.1:80
2.Containe模式
这个模式指定新创建的容器和已经存在的一个容器共享一个Network Nmaespace,而不是和宿主机共享新建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享 IP ,端口范围等。同样,两个容器处理网络方面,其他的:如文件系统,进程列表等还是隔离的,两个容器的进程可以通过lo网卡设备通信。
[root@docker ~]# docker run -itd --name test01 busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
e5d9363303dd: Pull complete
[root@docker ~]# docker run -itd --name test02 --network "container:test01" busybox
[root@docker ~]# docker exec -it test02 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:04
inet addr:172.17.0.4 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:656 (656.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@docker ~]# docker exec -it test01 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:04
inet addr:172.17.0.4 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:656 (656.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
3.none模式
使用none模式Docker容器拥有自己的Network Namespace 但是并不为Docker容器进行任何网络配置,也就是说,这个Docker容器没有网卡,IP,路由等信息,需要我们自己为Docker容器添加网卡,配置IP等。
这种网络模式下容器只有lo回环网络,没有其他网卡,none模式可以再容器创建时通过–network=none来指定。这种类型的网络没有办法联网,封闭的网络能根号的保证容器的安全性。
[root@docker ~]# docker run -itd --name test03 --network none busybox
ee4c8499e9322a898c5f4dc9925e7973a132f1887875234cde146c04b218817b
[root@docker ~]# docker exec -it test03 sh
/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
4.bridge模式
当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中
从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡 veth pair设备, Docker将veth pair设备的一段放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxx 这样类似的名字命名,并将这个网络设备加入到docker0网桥中,可以通过 brctl show 命令查看
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-15c5aa7519b0 8000.0242a0a30d0e no
docker0 8000.02426e6bb6ea no veth21c1608
vethb84cbb7
vethf98b54c
virbr0 8000.5254006c9966 yes virbr0-nic
bridge模式是docker的默认网络模式,不写 --net 参数,就是bridge模式。 使用 docker run -p时,docker实际是在iptables 做了DNAT规则,实现端口转发功能。可以使用 ipables -t nat -vnL 查看
[root@docker ~]# iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 158 packets, 16816 bytes)
[root@docker ~]# docker run -itd --name test04 busybox
ce08bc68818eac70ce4b0786710443684c4ac1ae1375932177c0180fde6a0020
[root@docker ~]# ip a
17: vethc4d9834@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 8a:46:e2:a9:00:37 brd ff:ff:ff:ff:ff:ff link-netnsid 4
inet6 fe80::8846:e2ff:fea9:37/64 scope link
valid_lft forever preferred_lft forever
[root@docker ~]# docker exec -it test04 ip a
16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:05 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.5/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever