docker容器網絡

在安裝docker時,會自動在host主機上創建三個網絡,用docker network ls可以進行查看:

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
b271af4d6598        bridge              bridge              local
95f888208994        host                host                local
5705b1b4107d        none                null                local

none網絡

none網絡就是什麼都沒有的網絡,掛在none網絡下面的容器除了了lo,沒有其他任何的網卡,在創建容器的時候可以通過--network=none指定容器使用none網絡。

$ docker run -it --network=none busybox
/ # ip a
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

可以看到該容器只有一塊網卡lo,封閉意味着隔離,一些對安全性要求高並且不需要聯網的應用可以使用 none 網絡。

host網絡

連接到host網絡的容器共享host的網絡棧,容器的網絡配置跟host的完全相同:

$ docker run -it --network=host busybox
/ # ip l
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
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 00:0c:29:09:e3:78 brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue 
    link/ether 02:42:9b:0d:23:8b brd ff:ff:ff:ff:ff:ff
31: vethb6ac730@if30: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 
    link/ether be:0d:67:bb:5f:9c brd ff:ff:ff:ff:ff:ff
33: veth5819fa7@if32: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 
    link/ether 8a:a7:7c:de:29:16 brd ff:ff:ff:ff:ff:ff
35: veth7c93491@if34: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 
    link/ether 9a:19:ce:26:aa:ab brd ff:ff:ff:ff:ff:ff
/ # hostname
ubuntu

容器中能看到host的所有網卡,連hostname也跟host一樣。

直接使用 Docker host 的網絡最大的好處就是性能,如果容器對網絡傳輸效率有較高要求,則可以選擇 host 網絡。當然不便之處就是犧牲一些靈活性,比如要考慮端口衝突問題,Docker host 上已經使用的端口就不能再用了。

Docker host 的另一個用途是讓容器可以直接配置 host 網路。比如某些跨 host 的網絡解決方案,其本身也是以容器方式運行的,這些方案需要對網絡進行配置,比如管理 iptables

bridge網絡

docker在安裝時會創建一個名爲docker0的linux bridge。如果容器啓動的時候不指定–network,那麼容器會默認掛在docker0上。

$ brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02429b0d238b	no

現在docker0上沒有任何網絡設備,我們創建一個容器看看。

root@ubuntu:~# docker run -d httpd
3f8da19c11f089cce5b3f85bc016f3403db0ad4af71a7abea0b696afd1886411
root@host1:~# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02429b0d238b	no		vethe631bd9
root@ubuntu:~# docker exec -it 3f8da19c11f0 bash
root@3f8da19c11f0:/usr/local/apache2# ip a
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
52: eth0@if53: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    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

可以看到一個新的網絡設備掛在在docker0上,vethe631bd9就是新創建的httpd容器的虛擬網卡。看了容器內部的網卡爲eth0@if53,爲什麼從外面看到的和容器內部看到的網卡不一樣呢?

實際上vethe631bd9eth0@if53是一對veth pair。veth pair是一種成對出現的網絡設備,可以理解爲一根網線的兩端,一端(eth0@if53)在容器內,另一端(vethe631bd9)掛在docker0上,其效果就是相當於(eth0@if53)也掛在docker0上。

還看到eth0@if53已經配置了IP爲172.17.0.2,爲什麼是這個網段,我們通過docker network inspect bridge看一下bridge網絡的配置:

$ docker network inspect bridge 
[
    {
        "Name": "bridge",
        "Id": "b271af4d65980ecfa171fdad89636864ec076f45fb8c8558310916bedc7ecda0",
        "Created": "2018-01-22T17:51:21.295766604+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"
                }
......

原理bridge網絡的Subnet(子網)是172.17.0.0/16,Gateway(網關)是172.17.0.1,這個網關就是docker0。

在容器啓動的過程中,docker會自動從172.17.0.0/16中分配一個IP。

自定義容器網絡

docker提供了三種user-defined網絡驅動:bridge,overlay和macvlan。後兩種用於創建跨主機的網絡。

可以使用bridge驅動創建類似bridge的網絡:

$ docker network create --driver bridge my_net
5e9efda5449ba5a581e9fb91e3afbb1621bacd823b0ad08ef79b5d3cd368e1da
$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
b271af4d6598        bridge              bridge              local
95f888208994        host                host                local
5e9efda5449b        my_net              bridge              local
5705b1b4107d        none                null                local
$ brctl show
bridge name	bridge id		STP enabled	interfaces
br-5e9efda5449b		8000.02426b4ed3ee	no		
docker0		8000.02429b0d238b	no		vethe631bd9

這樣我們成功穿創建了一個my_net的網絡,新增加了一個網橋br-5e9efda5449b,並且5e9efda5449b是my_net網絡的短ID。

通過docker network inspect my_net命令查看my_net網絡的配置信息:

$ docker network inspect my_net
[
    {
        "Name": "my_net",
        "Id": "5e9efda5449ba5a581e9fb91e3afbb1621bacd823b0ad08ef79b5d3cd368e1da",
        "Created": "2018-01-23T15:44:17.670486371+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
.......

docker自動爲my_net網絡分配了子網和網關。

同時我們也可以自己指定subnet和gateway,在創建網絡的時候加上--subnet--gateway參數就可以了:

$ docker network create --driver bridge --subnet 172.19.0.0/24 --gateway 172.19.0.1 my_net2
1ded797aeede01408e2a70295e7b327a06233ac4e799b7da7e0913db1f41d8dd
$ brctl show 
brctl show 
bridge name	bridge id		STP enabled	interfaces
br-1ded797aeede		8000.0242bfebcd26	no	
$ ifconfig br-1ded797aeede
br-1ded797aeede Link encap:以太網  硬件地址 02:42:bf:eb:cd:26  
          inet 地址:172.19.0.1  廣播:172.19.0.255  掩碼:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  躍點數:1
          接收數據包:0 錯誤:0 丟棄:0 過載:0 幀數:0
          發送數據包:0 錯誤:0 丟棄:0 過載:0 載波:0
          碰撞:0 發送隊列長度:0 
          接收字節:0 (0.0 B)  發送字節:0 (0.0 B)
$ docker network inspect my_net2
[
    {
        "Name": "my_net2",
        "Id": "1ded797aeede01408e2a70295e7b327a06233ac4e799b7da7e0913db1f41d8dd",
        "Created": "2018-01-23T15:55:51.894463236+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.19.0.0/24",
                    "Gateway": "172.19.0.1"
                }
......

到這裏,我們自己指定了網絡。my_net2對應的網橋是br-1ded797aeede

容器要使用新的網絡,可以用--network指定:

$ docker run -it --network=my_net2 busybox
/ # ip a
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
56: eth0@if57: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:13:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.2/24 brd 172.19.0.255 scope global eth0
       valid_lft forever preferred_lft forever

容器分到的地址是172.19.0.2,那麼能不能給容器指定一個靜態IP呢?通過--ip參數就可以給容器指定靜態IP:

$ docker run -it --network=my_net2 --ip 172.19.0.6 busybox
/ # ip a
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
58: eth0@if59: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:13:00:06 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.6/24 brd 172.19.0.255 scope global eth0
       valid_lft forever preferred_lft forever

到這裏,我們給容器指定了靜態IP:172.19.0.6

注意:只有通過--subnet創建的網絡才能指定靜態IP

同主機網絡的通信

上面的兩個busybox容器都掛在my_net2上,我們測試以下能否互通:

/ # ip a
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
56: eth0@if57: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:13:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.2/24 brd 172.19.0.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # ping 172.19.0.6 -c 3
PING 172.19.0.6 (172.19.0.6): 56 data bytes
64 bytes from 172.19.0.6: seq=0 ttl=64 time=0.224 ms
64 bytes from 172.19.0.6: seq=1 ttl=64 time=0.192 ms
64 bytes from 172.19.0.6: seq=2 ttl=64 time=0.336 ms

--- 172.19.0.6 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.192/0.250/0.336 ms

同一網絡中的容器、網關之間都是互通的
不同網絡中的容器不能互通,通過docker network connect命令可以實現:

$ docker network connect my_net2 3f8da19c11f0
$ docker exec -it 3f8da19c11f0 bash
root@3f8da19c11f0:/usr/local/apache2# ping 172.19.0.6 -c 3
PING 172.19.0.6 (172.19.0.6): 56 data bytes
64 bytes from 172.19.0.6: icmp_seq=0 ttl=64 time=0.162 ms
64 bytes from 172.19.0.6: icmp_seq=1 ttl=64 time=0.196 ms
64 bytes from 172.19.0.6: icmp_seq=2 ttl=64 time=0.160 ms
--- 172.19.0.6 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.160/0.173/0.196/0.000 ms

果然,能夠互通了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章