Docker容器網(wǎng)絡(luò)的七種武器

知識(shí),學(xué)過(guò)了之后至耻,把它總結(jié)氏涩、分享出來(lái),能讓自己對(duì)它的理解更加的深入有梆。

因此是尖,把以前學(xué)的Docker容器網(wǎng)絡(luò)模型歸納總結(jié)、并進(jìn)行實(shí)驗(yàn)泥耀。

后續(xù)再繼續(xù)對(duì)Kubernetes饺汹、CNI進(jìn)行總結(jié)實(shí)驗(yàn)。


Docker對(duì)網(wǎng)絡(luò)的支持痰催,可以用如下的思維導(dǎo)圖來(lái)表示:

DockerNetwork.png

包括了None兜辞、Host、Bridge夸溶、Container逸吵、Overlay、Macvlan缝裁、IPvlan七種模型扫皱。

下面,針對(duì)每種網(wǎng)絡(luò)模型進(jìn)行介紹與實(shí)驗(yàn)捷绑。

一. 拔網(wǎng)線 - None模型

None韩脑,啥都沒(méi)有,類似于把網(wǎng)線給拔掉了粹污。所以段多,這種模式下的容器,是一個(gè)封閉的環(huán)境壮吩。

適用于安全性高进苍、又不需要網(wǎng)絡(luò)訪問(wèn)的情景。

運(yùn)行容器時(shí)鸭叙,指定:--network=none即可觉啊。

$ docker run -it --rm --name=bbox --network=none busybox sh

運(yùn)行一個(gè)BusyBox的容器,然后在容器內(nèi)可以看到:

/ # ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

該容器除了一個(gè)localhost的網(wǎng)卡递雀,并沒(méi)有對(duì)外進(jìn)行網(wǎng)絡(luò)通信的設(shè)備柄延。

二. 寄生 - Host模型

使用該模式的容器,共享Host宿主機(jī)(運(yùn)行Docker的機(jī)器)的網(wǎng)絡(luò)棧、網(wǎng)卡設(shè)備搜吧。

這種情況下市俊,容器的網(wǎng)絡(luò)性能很好。但是不靈活滤奈,容器的端口容易與Host的端口沖突摆昧。Host A上能正常運(yùn)行,換到了Host B未必就能正常運(yùn)行蜒程。根據(jù)我的經(jīng)驗(yàn)绅你,這種模式很少有實(shí)際應(yīng)用。

運(yùn)行容器時(shí)昭躺,指定:--network=host即可忌锯。

$ docker run -it --rm --name=bbox --network=host busybox sh

在容器內(nèi)看到的網(wǎng)卡信息:

/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel qlen 1000
    link/ether 00:0c:29:49:39:91 brd ff:ff:ff:ff:ff:ff
    inet **192.168.111.128**/24 brd 192.168.111.255 scope global dynamic noprefixroute ens33
       valid_lft 1242sec preferred_lft 1242sec
    inet6 fe80::72bf:3960:42cd:13cb/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
    link/ether 02:42:65:3a:0c:37 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:65ff:fe3a:c37/64 scope link
       valid_lft forever preferred_lft forever

與在Host宿主機(jī)看到的信息是一致的:

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:49:39:91 brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet **192.168.111.128**/24 brd 192.168.111.255 scope global dynamic noprefixroute ens33
       valid_lft 1148sec preferred_lft 1148sec
    inet6 fe80::72bf:3960:42cd:13cb/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:65:3a:0c:37 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:65ff:fe3a:c37/64 scope link
       valid_lft forever preferred_lft forever

從容器內(nèi)訪問(wèn)網(wǎng)絡(luò),一切正常:

/ # ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=53 time=34.735 ms
64 bytes from 8.8.8.8: seq=1 ttl=53 time=35.659 ms
64 bytes from 8.8.8.8: seq=2 ttl=53 time=35.603 ms
64 bytes from 8.8.8.8: seq=3 ttl=53 time=35.723 ms

三. 搭橋 - Bridge模型

這是Docker在運(yùn)行容器時(shí)领炫,默認(rèn)的網(wǎng)絡(luò)模型偶垮。

Docker在安裝時(shí),會(huì)自動(dòng)在系統(tǒng)里面創(chuàng)建一個(gè)叫做docker0的網(wǎng)橋:

$ ip addr
......
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:65:3a:0c:37 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:65ff:fe3a:c37/64 scope link
       valid_lft forever preferred_lft forever

繼續(xù)查看該網(wǎng)橋的詳細(xì)信息:

$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "d92abe90e2bc79d8a4cd5ae73138d8da7aa0684a6a170fe7fc0ade4518057440",
        "Created": "2023-04-18T11:02:11.199720084+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    **"Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"**
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

根據(jù)上面的信息帝洪,Docker在運(yùn)行容器時(shí)似舵,會(huì)在172.17.0.0/16網(wǎng)段,為容器分配IP地址葱峡,并把Gateway指向172.17.0.1砚哗,即docker0這個(gè)虛擬設(shè)備。

而且砰奕,Docker會(huì)為運(yùn)行的容器創(chuàng)建一對(duì)veth蛛芥。該veth pair,一端接在容器內(nèi)部脆淹,另一端接在docker0上常空。使得容器可以通過(guò)docker0與外界通信。

運(yùn)行一個(gè)容器盖溺,可以看到容器里面的網(wǎng)絡(luò)設(shè)備:

$ docker run -it --rm --name=bbox busybox sh
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

容器內(nèi)部有eth0網(wǎng)卡,它是veth的一端铣缠。在Host上烘嘱,可以看到veth的另一端:

$ brctl show
bridge name        bridge id            STP enabled        interfaces
docker0            8000.0242653a0c37    no                vethe22e54f

網(wǎng)絡(luò)拓?fù)鋮⒖脊俜皆瓐D:

Docker_Bridge.png
1. 相同Host上的容器間網(wǎng)絡(luò)通信

在這種模式下,同一個(gè)Host上的不同容器蝗蛙,可以通過(guò)docker0直接通信蝇庭。比如運(yùn)行一個(gè)Nginx的容器:

$ docker run -it --rm --name=web nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/04/18 03:50:39 [notice] 1#1: using the "epoll" event method
2023/04/18 03:50:39 [notice] 1#1: nginx/1.23.4
2023/04/18 03:50:39 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2023/04/18 03:50:39 [notice] 1#1: OS: Linux 5.19.0-38-generic
2023/04/18 03:50:39 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/04/18 03:50:39 [notice] 1#1: start worker processes
2023/04/18 03:50:39 [notice] 1#1: start worker process 28
2023/04/18 03:50:39 [notice] 1#1: start worker process 29

在另一個(gè)shell窗口里,先查看該容器的IP地址捡硅,確定為172.17.0.2:

$ docker network inspect bridge
[
    {
        "Name": "bridge",
        ......
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        ......
        "Containers": {
            "d3025a31c47c80bdcf711f329ff3c70677c28bfaed08d700743d91ad1bc33f15": {
                "Name": "web",
                "EndpointID": "d6f319d19fac52189c70fddb3a732f5b4081ff16fbe21e859c647ff8ff8ae7e6",
                "MacAddress": "02:42:ac:11:00:02",
                **"IPv4Address": "172.17.0.2/16",**
                "IPv6Address": ""
            }
        },
        ......
    }
]

然后,運(yùn)行一個(gè)BusyBox的容器:

$ docker run -it --rm --name=bbox busybox sh
/ # wget 172.17.0.2:80
Connecting to 172.17.0.2:80 (172.17.0.2:80)
saving to 'index.html'
index.html           100% |********************************************************************************************************************************************************************************|   615  0:00:00 ETA
'index.html' saved

可以看到,BusyBox容器成功的訪問(wèn)了Nginx容器缘挽。

2. 容器與外部網(wǎng)絡(luò)通信

2.1. 從內(nèi)到外

Bridge模式下的容器,默認(rèn)就可以訪問(wèn)外部網(wǎng)絡(luò)纹因。它依靠Host上的iptables,做了NAT地址轉(zhuǎn)換琳拨。

啟動(dòng)一個(gè)BusyBox的容器瞭恰,得到的IP是172.17.0.2。它的Host IP是:192.168.111.128狱庇。在容器內(nèi)可以直接訪問(wèn)外部的另一臺(tái)機(jī)器:192.168.111.129惊畏。

$ docker run -it --rm --name=bbox busybox sh
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # ping 192.168.111.129
PING 192.168.111.129 (192.168.111.129): 56 data bytes
64 bytes from 192.168.111.129: seq=0 ttl=63 time=0.521 ms
64 bytes from 192.168.111.129: seq=1 ttl=63 time=0.465 ms

2.2. 從外到內(nèi)

如果需要外部網(wǎng)絡(luò)訪問(wèn)Bridge模式下的容器,可以通過(guò)端口映射功能密任。在運(yùn)行容器時(shí)颜启,指定Host端口A與容器端口B的映射。然后浪讳,通過(guò)訪問(wèn):Host-IP:Host端口A农曲,即可映射到:容器:容器端口B。

我們做個(gè)試驗(yàn)驻债,把前面的Nginx容器和BusyBox容器全部退出乳规。然后重新運(yùn)行一個(gè)新的Nginx容器,并通過(guò)-p參數(shù)指定端口映射:

$ docker run -it --rm --name=web -p 8080:80 nginx

從另外一臺(tái)機(jī)器發(fā)起訪問(wèn)合呐,192.168.111.128是Host的IP地址:

$ wget 192.168.111.128:8080
Connecting to 192.168.111.128:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 615 [text/html]
Saving to: ‘index.html’

index.html                                              100%[===============================================================================================================================>]     615  --.-KB/s    in 0s      

‘index.html’ saved [615/615]

四. 如影隨形 - Container模型

這個(gè)模式我沒(méi)看到官方的名字暮的,名字我瞎取的,但是在Kubernetes的Pod里面經(jīng)常用淌实。

具體的做法冻辩,是在容器B運(yùn)行時(shí),指定:--network=container:容器A的名字或者ID拆祈。

這樣恨闪,容器A、B處于同一個(gè)網(wǎng)絡(luò)空間放坏。它們的MAC地址咙咽、IP地址都一樣,共享網(wǎng)絡(luò)棧淤年、網(wǎng)卡和配置信息钧敞。它們可以通過(guò)127.0.0.1直接通信。

在Kubernetes部署Pod的時(shí)候麸粮,就會(huì)用到這個(gè)模式溉苛。針對(duì)每個(gè)Pod,Kubernetes先啟動(dòng)Pause容器弄诲,然后再啟動(dòng)其它容器并使用Pause容器的網(wǎng)絡(luò)愚战。這樣,同一個(gè)Pod之內(nèi)的容器,共享了同一個(gè)網(wǎng)絡(luò)空間寂玲,可以高效的通信塔插。

試驗(yàn)看看,先啟動(dòng)一個(gè)Nginx容器:

$ docker run -it --rm --name=web nginx

看看Docker網(wǎng)絡(luò)情況:

$ docker network inspect bridge
[
    {
        "Name": "bridge",
        ......
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        ......
        "Containers": {
            "da67b03b02c2e99fdaaa2fd75b7829c4005eba80a50f39404db4da8d8defa0e3": {
                "Name": "web",
                "EndpointID": "0e29b7473a8446100dc45a711536b0277ae0f911cb4c2decc7245511fd2dbb02",
                **"MacAddress": "02:42:ac:11:00:02",**
                **"IPv4Address": "172.17.0.2/16",**
                "IPv6Address": ""
            }
        },
    }
]

Nginx容器的IP地址是:172.17.0.2敢茁,MAC地址是:02:42:ac:11:00:02佑淀。

再啟動(dòng)一個(gè)BusyBox容器,并使用Nginx的網(wǎng)絡(luò):

$ docker run -it --rm --name=bbox --network=container:web busybox sh
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether **02:42:ac:11:00:02** brd ff:ff:ff:ff:ff:ff
    inet **172.17.0.2**/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

可以看到彰檬,BusyBox的IP地址伸刃、MAC地址,和Nginx的一模一樣逢倍。

直接訪問(wèn)127.0.0.1可以得到:

/ # wget 127.0.0.1
Connecting to 127.0.0.1 (127.0.0.1:80)
saving to 'index.html'
index.html           100% |********************************************************************************************************************************************************************************|   615  0:00:00 ETA
'index.html' saved

這種模式除了K8S的Pod之外捧颅,還可以用在簡(jiǎn)易版的Web Server + App Server情景。

五. 套娃 - Overlay模型

Docker通過(guò)Overlay模式较雕,實(shí)現(xiàn)了對(duì)VXLAN的支持碉哑。這個(gè)模式的環(huán)境搭建比別的模式稍顯復(fù)雜,主要是因?yàn)樾枰幸粋€(gè)地方來(lái)保存各個(gè)節(jié)點(diǎn)在overlay網(wǎng)絡(luò)中的配置信息亮蒋。一般是在另一個(gè)機(jī)器安裝etcd或者Consul這種key-value數(shù)據(jù)庫(kù)扣典。

偷懶起見(jiàn),我直接使用了Docker自帶的Swarm來(lái)搭建環(huán)境慎玖。準(zhǔn)備了兩臺(tái)機(jī)器A贮尖、B。A身兼兩職趁怔,既保存數(shù)據(jù)庫(kù)湿硝,又運(yùn)行容器。

  • 首先润努,在機(jī)器A关斜,初始化swarm:

    ycwang@ycwang-ubuntu:~$ docker swarm init
    Swarm initialized: current node (qygp7ymrfh5g0lgky10teck4r) is now a manager.
    
    To add a worker to this swarm, run the following command:
    
        docker swarm join --token SWMTKN-1-3rjaah******rowo 192.168.111.128:2377
    
    To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
    
  • 換到機(jī)器B,Copy上面的join命令铺浇,加入集群:

    ycwang@ycwang-ubuntu-slave:~$ docker swarm join --token SWMTKN-1-3rjaah******rowo 192.168.111.128:2377
    This node joined a swarm as a worker.
    
  • 回到機(jī)器A痢畜,可以看到集群的情況:

    ycwang@ycwang-ubuntu:~$ docker node ls
    ID                            HOSTNAME              STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
    qygp7ymrfh5g0lgky10teck4r *   ycwang-ubuntu         Ready     Active         Leader           23.0.4
    sr637j4g891bsxo56tesv55y8     ycwang-ubuntu-slave   Ready     Active                          23.0.4
    
  • 在機(jī)器A上,可以看到Docker為Overlay模式随抠,創(chuàng)建了兩個(gè)新的網(wǎng)絡(luò)裁着,docker_gwbridge和ingress。后面運(yùn)行的容器拱她,會(huì)通過(guò)docker_gwbridge與外部網(wǎng)絡(luò)進(jìn)行通信(南北向流量):

    ycwang@ycwang-ubuntu:~$ docker network ls
    NETWORK ID     NAME              DRIVER    SCOPE
    51276c2e1741   bridge            bridge    local
    596dbdd24c3a   docker_gwbridge   bridge    local
    fc504698f255   host              host      local
    tmbwbg86eph4   ingress           overlay   swarm
    4829db6948ad   none              null      local
    
  • 在機(jī)器A上,為Docker創(chuàng)建Overlay網(wǎng)絡(luò):

    ycwang@ycwang-ubuntu:~$ docker network create --driver=overlay vxlanA
    thya4qliq95dh81yndfqpimwn
    
  • 在機(jī)器A上扔罪,創(chuàng)建服務(wù)秉沼,使用vxlanA這個(gè)網(wǎng)絡(luò),replicas 指定為 2:

    ycwang@ycwang-ubuntu:~$ docker service create --network=vxlanA --name bboxes --replicas 2 busybox ping 8.8.8.8
    q44lh7mwwpgbae7fleilgenk2
    overall progress: 2 out of 2 tasks 
    1/2: running   [==================================================>] 
    2/2: running   [==================================================>] 
    verify: Service converged
    

    注意,busybox后面的ping 8.8.8.8唬复,并不是為了讓它去ping矗积,目的只是讓這個(gè)容器不要馬上退出,否則Service會(huì)不停的重啟這兩個(gè)容器敞咧。別問(wèn)我為什么知道的……

  • 分別在兩個(gè)機(jī)器上查看容器的信息:

    ycwang@ycwang-ubuntu:~$ docker ps 
    CONTAINER ID   IMAGE            COMMAND          CREATED          STATUS          PORTS     NAMES
    a9f2b06f0f9e   busybox:latest   "ping 8.8.8.8"   16 minutes ago   Up 16 minutes             bboxes.2.m6qqi8k75rvr8ukk4ll6jfrnp
    ycwang@ycwang-ubuntu:~$ docker exec -it a9f2b06f0f9e sh
    / # ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    62: eth0@if63: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue 
        link/ether 02:42:0a:00:01:21 brd ff:ff:ff:ff:ff:ff
        inet 10.0.1.33/24 brd 10.0.1.255 scope global eth0
           valid_lft forever preferred_lft forever
    64: eth1@if65: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
        link/ether 02:42:ac:13:00:03 brd ff:ff:ff:ff:ff:ff
        inet 172.19.0.3/16 brd 172.19.255.255 scope global eth1
           valid_lft forever preferred_lft forever
    
    ycwang@ycwang-ubuntu-slave:~$ docker ps -a
    CONTAINER ID   IMAGE            COMMAND          CREATED          STATUS          PORTS     NAMES
    04aacff98016   busybox:latest   "ping 8.8.8.8"   18 minutes ago   Up 18 minutes             bboxes.1.ky0fcmy5geudr2fothxxh05y3
    ycwang@ycwang-ubuntu-slave:~$ docker exec -it 04aacff98016 sh
    / # ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    62: eth0@if63: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue 
        link/ether 02:42:0a:00:01:20 brd ff:ff:ff:ff:ff:ff
        inet 10.0.1.32/24 brd 10.0.1.255 scope global eth0
           valid_lft forever preferred_lft forever
    64: eth1@if65: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
        link/ether 02:42:ac:13:00:03 brd ff:ff:ff:ff:ff:ff
        inet 172.19.0.3/16 brd 172.19.255.255 scope global eth1
           valid_lft forever preferred_lft forever
    

    可以發(fā)現(xiàn)棘捣,每個(gè)容器會(huì)帶兩張網(wǎng)卡。

    eth1 - 172.19.0.3接在前面的docker_gwbridge網(wǎng)橋上休建,負(fù)責(zé)與外部網(wǎng)絡(luò)的南北向流量乍恐。通過(guò)docker network inspect docker_gwbridge可以確認(rèn)這個(gè)信息。

    etho - 10.0.1.32/24测砂,10.0.1.33/24茵烈,屬于vxlanA網(wǎng)絡(luò),負(fù)責(zé)VXLAN內(nèi)部的東西向流量砌些。通過(guò)docker network inspect vxlanA可以確認(rèn)這個(gè)信息呜投。

  • 從容器A ping 容器B:

    / # ping 10.0.1.32
    PING 10.0.1.32 (10.0.1.32): 56 data bytes
    64 bytes from 10.0.1.32: seq=0 ttl=64 time=0.735 ms
    64 bytes from 10.0.1.32: seq=1 ttl=64 time=0.556 ms
    

    兩個(gè)容器之間是可以通信的。此時(shí)存璃,用tcpdump在Host宿主機(jī)的網(wǎng)卡上抓包:

    $ sudo tcpdump -i ens33 udp port 4789 -s 0 -X -nnn -vvv
    tcpdump: listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
    15:50:57.566431 IP (tos 0x0, ttl 64, id 34769, offset 0, flags [none], proto UDP (17), length 134)
        192.168.111.128.42627 > 192.168.111.129.4789: [bad udp cksum 0x60d6 -> 0xb9a9!] VXLAN, flags [I] (0x08), vni 4097
    IP (tos 0x0, ttl 64, id 30207, offset 0, flags [DF], proto ICMP (1), length 84)
        10.0.1.33 > 10.0.1.32: ICMP echo request, id 23, seq 0, length 64
        0x0000:  4500 0086 87d1 0000 4011 9243 c0a8 6f80  E.......@..C..o.
        0x0010:  c0a8 6f81 a683 12b5 0072 60d6 0800 0000  ..o......r`.....
        0x0020:  0010 0100 0242 0a00 0120 0242 0a00 0121  .....B.....B...!
        0x0030:  0800 4500 0054 75ff 4000 4001 ae69 0a00  ..E..Tu.@.@..i..
        0x0040:  0121 0a00 0120 0800 ae96 0017 0000 bbd5  .!..............
        0x0050:  8d7c 0000 0000 0000 0000 0000 0000 0000  .|..............
        0x0060:  0000 0000 0000 0000 0000 0000 0000 0000  ................
        0x0070:  0000 0000 0000 0000 0000 0000 0000 0000  ................
        0x0080:  0000 0000 0000                           ......
    

    可以清楚的看到從容器A - 10.0.1.33 到容器B - 10.0.1.32的ICMP數(shù)據(jù)包仑荐,被VNI為4097的VXLAN封裝。

    封裝后纵东,變成了從Host A - 192.168.111.128.42627到Host B - 192.168.111.129.4789的UDP數(shù)據(jù)包粘招。

通過(guò)這個(gè)模型,實(shí)現(xiàn)了容器間的直連篮迎,虛擬的二層直連男图。Overlay模型也成了許多云廠商采用的實(shí)現(xiàn)方案。

六. 狡兔三窟 - Macvlan模型

Macvlan是一種網(wǎng)卡虛擬化技術(shù)甜橱,將一張物理網(wǎng)卡(父接口)虛擬出多張網(wǎng)卡(子接口)逊笆。每個(gè)子接口有自己獨(dú)立的 MAC 地址和 IP 地址。

物理網(wǎng)卡(父接口)相當(dāng)于一個(gè)交換機(jī)岂傲,記錄著對(duì)應(yīng)的虛擬網(wǎng)卡(子接口)和 MAC 地址难裆。當(dāng)物理網(wǎng)卡收到數(shù)據(jù)包后,會(huì)根據(jù)目的 MAC 地址判斷這個(gè)包屬于哪一個(gè)虛擬網(wǎng)卡镊掖,并轉(zhuǎn)發(fā)給它乃戈。

Macvlan技術(shù)有四種模式,Docker支持其中的bridge模式亩进。

接下來(lái)症虑,試驗(yàn)看看。

  • 首先归薛,需要打開(kāi)網(wǎng)卡的混雜模式谍憔,否則它拒絕接收MAC地址跟它不一樣的數(shù)據(jù)報(bào)文匪蝙。ens33是Host機(jī)器的物理網(wǎng)卡:

    $ sudo ip link set ens33 promisc on
    
  • 第二步,為Docker創(chuàng)建一個(gè)Macvlan網(wǎng)絡(luò)习贫。子網(wǎng)是:192.168.111.0/24逛球,跟Host一樣;指定父接口為ens33

    $ docker network create --driver=macvlan --subnet=192.168.111.0/24 --gateway=192.168.111.1 -o parent=ens33 macvnet
    0283990d6acdc9df87d5b34a999c05266e12a4423aa0041387373d8bc5ee042c
    
  • 第三步苫昌,運(yùn)行容器颤绕,指定其IP地址為:192.168.111.10,并使用上一步創(chuàng)建的Macvlan網(wǎng)絡(luò):

    $ docker run -it --rm --name=web --ip=192.168.111.10 --network=macvnet nginx
    

這樣祟身,Nginx這個(gè)容器就運(yùn)行在了192.168.110.10這個(gè)地址上奥务,從外部機(jī)器可以直接訪問(wèn)它:

$ wget 192.168.111.10
Connecting to 192.168.111.10:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 615 [text/html]
Saving to: ‘index.html’

index.html                                            100%[===============================================================================================================================>]     615  --.-KB/s    in 0s      

‘index.html’ saved [615/615]

可以看到,Macvlan 是一種將容器通過(guò)二層月而,連接到物理網(wǎng)絡(luò)不錯(cuò)的方案汗洒,配置簡(jiǎn)單、性能好父款。但它也有一些局限性溢谤,比如:
物理網(wǎng)卡所連接的交換機(jī),可能會(huì)限制同一個(gè)物理端口上的 MAC 地址數(shù)量憨攒。
許多物理網(wǎng)卡上的 MAC地址數(shù)量也有限制世杀。

七. 狡兔三窟Plus - IPvlan模型

IPvlan是一個(gè)比較新的特性,Linux內(nèi)核>= 4.2之后才可以穩(wěn)定的使用肝集。

與Macvlan類似瞻坝,都是從一個(gè)物理網(wǎng)卡(父接口)虛擬出多張網(wǎng)卡(子接口)。與Macvlan不同的是杏瞻,這些子接口的MAC地址都是一樣的所刀,不一樣的只是它們的IP地址。而且捞挥,它不像Macvlan那樣浮创,要求物理網(wǎng)卡打開(kāi)混雜模式。

IPvlan有兩種模式:L2和L3模式砌函。顧名思義斩披,L2模式跟交換機(jī)有關(guān),L3模式則跟路由器有關(guān)讹俊。

1. L2模式

IPvlan的L2模式垦沉,跟之前的Macvlan非常類似。容器的子接口與父接口在同一子網(wǎng)仍劈,父接口做為交換機(jī)來(lái)轉(zhuǎn)發(fā)子接口的數(shù)據(jù)厕倍。如果是與外部網(wǎng)絡(luò)通信,則依賴父接口進(jìn)行路由轉(zhuǎn)發(fā)贩疙。

首先绑青,為Docker創(chuàng)建一個(gè)L2模式的IPvlan網(wǎng)絡(luò):

$ docker network create --driver=ipvlan --subnet=192.168.0.0/24 --gateway=192.168.0.1 -o ipvlan_mode=l2 -o parent=ens33 ipv_l2
7091b861fd44798d21be6d3dcdd03e79c68d65e9149862b9f21bca42678fda19

該網(wǎng)絡(luò)與Host宿主機(jī)同在192.168.0.0/24網(wǎng)段诬像,Host的網(wǎng)卡是ens33屋群,IP是192.168.0.105闸婴。

使用該網(wǎng)絡(luò),運(yùn)行第一個(gè)容器:

$ docker run -it --rm --network=ipv_l2 --name=bbox1 busybox sh
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
4: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 00:0c:29:12:5b:f4 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.2/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever

該容器的IP地址為192.168.0.2芍躏。MAC地址與Host宿主機(jī)的ens33一致邪乍。

從容器內(nèi),訪問(wèn)另外一臺(tái)機(jī)器B:

/ # ping 192.168.0.112
PING 192.168.0.112 (192.168.0.112): 56 data bytes
64 bytes from 192.168.0.112: seq=0 ttl=64 time=79.549 ms

從另外的機(jī)器B对竣,訪問(wèn)該容器:

$ ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=3.94 ms

可以看到庇楞,容器的網(wǎng)絡(luò)訪問(wèn)都是沒(méi)問(wèn)題的。

2. L3模式

這個(gè)模式下否纬,容器跟Host宿主機(jī)可以不在同一個(gè)子網(wǎng)吕晌。該模式的配置,網(wǎng)上的資料比較少临燃,Docker官網(wǎng)也是語(yǔ)焉不詳?shù)摹?/p>

假設(shè)Host宿主機(jī)的父接口是ens33睛驳,IP地址是192.168.0.105/24。

現(xiàn)在想要?jiǎng)?chuàng)建兩個(gè)容器膜廊,分別屬于不同的子網(wǎng)乏沸,例如10.0.1.0/24和10.0.2.0/24,并讓它們可以相互通信爪瓜,也可以訪問(wèn)外部網(wǎng)絡(luò)蹬跃。

可以按照如下的步驟來(lái)實(shí)現(xiàn)。

  • 首先铆铆,把之前環(huán)境下的容器退出蝶缀,并清理資源,因?yàn)橐粋€(gè)父接口不能同時(shí)支持L2和L3模式:

    $ docker system prune
    
  • 創(chuàng)建一個(gè)新的IPvlan網(wǎng)絡(luò):

    $ docker network create --driver=ipvlan --subnet=10.0.1.0/24 --subnet=10.0.2.0/24 -o parent=ens33 -o ipvlan_mode=l3 ipvlan-l3
    
  • 在兩個(gè)Terminal窗口薄货,分布運(yùn)行一個(gè)容器翁都,并連接到剛剛創(chuàng)建的IPvlan網(wǎng)絡(luò)、使用不同的子網(wǎng)菲驴。它們的IP地址分別為10.0.1.10和10.0.2.10:

    $ docker run -it --rm --name bbox1 --network ipvlan-l3 --ip 10.0.1.10 busybox sh
    / # ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    4: eth0@if2: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
        link/ether 00:0c:29:12:5b:f4 brd ff:ff:ff:ff:ff:ff
        inet 10.0.1.10/24 brd 10.0.1.255 scope global eth0
           valid_lft forever preferred_lft forever
    
    $ docker run -it --rm --name bbox2 --network ipvlan-l3 --ip 10.0.2.10 busybox sh
    / # ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    5: eth0@if2: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
        link/ether 00:0c:29:12:5b:f4 brd ff:ff:ff:ff:ff:ff
        inet 10.0.2.10/24 brd 10.0.2.255 scope global eth0
           valid_lft forever preferred_lft forever
    
  • 容器之間互通性荐吵。此時(shí),兩個(gè)容器之間已經(jīng)可以互相訪問(wèn)赊瞬。

    從bbox1訪問(wèn)bbox2:

    / # ping 10.0.2.10
    PING 10.0.2.10 (10.0.2.10): 56 data bytes
    64 bytes from 10.0.2.10: seq=0 ttl=64 time=0.270 ms
    64 bytes from 10.0.2.10: seq=1 ttl=64 time=0.061 ms
    

    從bbox2訪問(wèn)bbox1:

    / # ping 10.0.1.10
    PING 10.0.1.10 (10.0.1.10): 56 data bytes
    64 bytes from 10.0.1.10: seq=0 ttl=64 time=0.077 ms
    64 bytes from 10.0.1.10: seq=1 ttl=64 time=0.077 ms
    
  • 但此時(shí)先煎,從外部網(wǎng)絡(luò)訪問(wèn)這兩個(gè)容器依然是無(wú)法到達(dá)的。因?yàn)橥獠康木W(wǎng)絡(luò)環(huán)境里巧涧,沒(méi)有關(guān)于10.0.1.10或者10.0.2.10這兩個(gè)IP地址的路由信息薯蝎。

    需要在外部路由器上添加相應(yīng)的路由規(guī)則,讓它知道如何到達(dá)容器網(wǎng)絡(luò)谤绳。

    假設(shè)外部路由器的接口為eth1占锯,IP地址為192.168.0.1/24袒哥。

    添加路由規(guī)則,將目標(biāo)地址為10.0.1.0/24或10.0.2.0/24的數(shù)據(jù)包轉(zhuǎn)發(fā)到192.168.0.105消略,即堡称,轉(zhuǎn)發(fā)到容器的父接口ens33。

    $ sudo ip route add 10.0.1.0/24 via 192.168.0.105 dev eth1
    $ sudo ip route add 10.0.2.0/24 via 192.168.1.105 dev eth1
    

    這樣艺演,就可以實(shí)現(xiàn)IPvlan L3模式的容器與外部網(wǎng)絡(luò)的通信却紧。Sorry,我忘了我家里路由器的密碼了胎撤,暫時(shí)沒(méi)法登錄實(shí)驗(yàn)……

綜合運(yùn)用下來(lái)晓殊,感覺(jué)IPvlan模式應(yīng)該比Macvlan模式更加實(shí)用,因?yàn)镸acvlan擁有的功能伤提,IPvlan的L2模式都有巫俺,而且還少了混雜模式、MAC地址數(shù)目的潛在問(wèn)題肿男。除此之外介汹,IPvlan還多了L3模式的支持。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末次伶,一起剝皮案震驚了整個(gè)濱河市痴昧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冠王,老刑警劉巖赶撰,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異柱彻,居然都是意外死亡豪娜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)哟楷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瘤载,“玉大人,你說(shuō)我怎么就攤上這事卖擅∶迹” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵惩阶,是天一觀的道長(zhǎng)挎狸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)断楷,這世上最難降的妖魔是什么锨匆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮冬筒,結(jié)果婚禮上恐锣,老公的妹妹穿的比我還像新娘茅主。我一直安慰自己,他們只是感情好土榴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布诀姚。 她就那樣靜靜地躺著,像睡著了一般鞭衩。 火紅的嫁衣襯著肌膚如雪学搜。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天论衍,我揣著相機(jī)與錄音,去河邊找鬼聚磺。 笑死坯台,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瘫寝。 我是一名探鬼主播蜒蕾,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼焕阿!你這毒婦竟也來(lái)了咪啡?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤暮屡,失蹤者是張志新(化名)和其女友劉穎撤摸,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體褒纲,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡准夷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了莺掠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衫嵌。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖彻秆,靈堂內(nèi)的尸體忽然破棺而出楔绞,到底是詐尸還是另有隱情,我是刑警寧澤唇兑,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布酒朵,位于F島的核電站,受9級(jí)特大地震影響幔亥,放射性物質(zhì)發(fā)生泄漏耻讽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一帕棉、第九天 我趴在偏房一處隱蔽的房頂上張望针肥。 院中可真熱鬧饼记,春花似錦、人聲如沸慰枕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)具帮。三九已至博肋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蜂厅,已是汗流浹背匪凡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掘猿,地道東北人病游。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像稠通,于是被迫代替她去往敵國(guó)和親衬衬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容