Docker網絡管理(容器間通信)

一、前言

由於docker技術的火爆,導致現在越來越多的企業都在使用docker這種虛擬化技術。企業中使用docker這種虛擬化技術,其目的就是爲了讓docker中的容器對外提供服務。因此,我們必須深入瞭解一下docker的網絡知識,以滿足更高的網絡需求。

二、Docker的原生網絡

當你安裝Docker時,它會自動創建三個網絡。如下:

[root@localhost ~]# docker network ls                      
//查看docker的默認網絡
NETWORK ID          NAME                DRIVER              SCOPE
a38bd52b4cec        bridge              bridge               local
624b3ba70637        host                 host                   local
62f80646f707          none                  null                     local         

Docker內置這三個網絡,運行容器時,你可以使用該“--network”選項來指定容器應連接到哪些網絡。如果沒有指定則默認使用bridge模式。

比如:

host模式:使用 --net=host 指定;
none模式:使用 --net=none 指定;
bridge模式:使用 --net=bridge 指定(默認設置);

下面詳細介紹一下這幾種網絡模式:

雖然docker模式提供三種網絡模式,但其實是有四種網絡模式的!

1.host模式

如果啓動容器的時候使用host模式,那麼這個容器將不會獲得一個獨立的Network Namespace,而是和宿主機共用一個Network Namespace。容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和端口。

使用場景:

網絡配置與docker宿主機完全一樣,性能較好,但是不便之處就是靈活性不高,容易和宿主機出現端口衝突的問題。最好是單個容器時使用,一般情況下不建議使用。

創建使用host網絡模式的容器示例:

[root@localhost ~]# docker run -it --name host --network host busybox:latest 
//使用busybox鏡像創建一個名爲host的容器,網絡採用host模式
/ # ip a 
//進入容器後可以看出容器中的網絡與docker主機的網絡一模一樣
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 pfifo_fast qlen 1000
    link/ether 00:0c:29:66:72:13 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.1/24 brd 192.168.1.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::9f3:b94e:5f5d:8070/64 scope link 
       valid_lft forever preferred_lft forever
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue qlen 1000
    link/ether 52:54:00:e1:82:15 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 qlen 1000
    link/ether 52:54:00:e1:82:15 brd ff:ff:ff:ff:ff:ff
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue 
    link/ether 02:42:3c:06:f8:1d 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

2.none模式

在none模式下,Docker容器擁有自己的Network Namespace,但是,並不爲Docker容器進行任何網絡配置。也就是說,這個Docker容器沒有網卡、IP、路由等信息。需要我們自己爲Docker容器添加網卡、配置IP等。

使用場景:

none模式被稱爲隔離的網絡,隔離便意味着安全,不能與外部通信,同樣外部也不可以訪問到使用none模式的容器,使用這種網絡模式的容器可以運行於關於安全防面的驗證碼、校驗碼等服務。
一般用於對安全性要求較高的場景中!

創建使用none網絡模式的容器示例:

[root@localhost ~]# docker run -it --name none --network none busybox:latest 
//使用busybox鏡像創建一個名爲none的容器,網絡採用none模式
/ # ip a            //可以看到容器中只有一個lo網卡
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

3.bridge模式

bridge模式是Docker默認的網絡設置,此模式會爲每一個容器分配Network Namespace、設置IP等,並將一個主機上的Docker容器連接到一個虛擬網卡上。當Docker server啓動時,會在主機上創建一個名爲docker0的虛擬網橋,此主機上啓動的Docker容器會連接到這個虛擬網橋上。虛擬網橋的工作方式和物理交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網絡中。接下來就要爲容器分配IP了,Docker會從RFC1918所定義的私有IP網段中,選擇一個和宿主機不同的IP地址和子網分配給docker0,連接到docker0的容器就從這個子網中選擇一個未佔用的IP使用。如一般Docker會使用172.17.0.0/16這個網段,並將172.17.0.1/16分配給docker0網橋。

[root@localhost ~]# ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:3c:06:f8:1d  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@localhost ~]# brctl show             //查看橋接網絡
bridge name bridge id       STP enabled interfaces
docker0     8000.02423c06f81d   no      
//如果沒有創建橋接模式的容器,默認是空的。

創建使用bridge網絡模式的容器示例:

[root@localhost ~]# docker run -itd --name bridge busybox:latest /bin/sh
//創建一個名爲bridge的容器,如果沒有指定網絡模式,默認便是bridge模式
[root@localhost ~]# docker exec -it bridge /bin/sh
//進入bridge容器中
/ # 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
6: eth0@if9: <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
//可以看出eth0@if9這塊虛擬網卡上的地址與docker宿主機的docker0網絡屬於同一網段
[root@localhost ~]# brctl show
bridge name bridge id       STP enabled interfaces
docker0     8000.02423c06f81d   no      veth811d20c
//可以看到橋接模式的接口下出現了一個新的接口,當創建一個容器便會出現一個接口
//這個接口便是容器在docker宿主機創建一個虛擬網卡,用於容器與docker通信
[root@localhost ~]# ifconfig veth811d20c           //查看這個虛擬網卡是否存在
veth811d20c: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::c035:95ff:febf:978b  prefixlen 64  scopeid 0x20<link>
        ether c2:35:95:bf:97:8b  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8  bytes 648 (648.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

當使用bridge網絡模式,docker的工作步驟大致爲:
(1)在主機上創建一對虛擬網卡veth pair設備。veth設備總是成對出現的,它們組成了一個數據的通道,數據從一個設備進入,就會從另一個設備出來。因此,veth設備常用來連接兩個網絡設備;
(2)Docker將veth pair設備的一端放在新創建的容器中,並命名爲eth0。另一端放在主機中,以veth811d20c這樣類似的名字命名,並將這個網絡設備加入到docker0網橋中,可以通過brctl show命令查看(上述實例已經驗證);
(3)從docker0子網中分配一個IP給容器使用,並設置docker0的IP地址爲容器的默認網關;

4.container模式

這個模式指定新創建的容器和已經存在的一個容器共享一個Network Namespace,而不是和宿主機共享。新創建的容器不會創建自己的網卡,配置自己的IP,而是和一個指定的容器共享IP、端口範圍等。同樣,兩個容器除了網絡方面,其他的如文件系統、進程列表等還是隔離的。兩個容器的進程可以通過lo網卡設備通信。

創建使用container網絡模式的容器示例:

[root@localhost ~]# docker run -it --name container --network container:a172b832b531 busybox:latest 
//a172b832b531是bridge容器的ID號
/ # 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
8: eth0@if9: <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
//可以看出container容器的IP地址與bridge容器的IP地址一模一樣

關於這四種網絡模式推薦使用默認的bridge網絡模式!

3.自定義bridge網絡

細心一點可以發現,創建的容器默認情況IP地址爲172.17.0.0/16網段,那麼我們可不可以自定義一個網段供容器使用呢?答案肯定是可以的,方法如下:

[root@localhost ~]# docker network create -d bridge my_net
//創建一個橋接網絡,名稱爲my_net,如果沒有指定網段,默認是172.18.0.0/16,按docker0的網段自動遞增
[root@localhost ~]# docker network ls         //查看docker支持的網絡類型
NETWORK ID          NAME                DRIVER              SCOPE
9fba9dc3d2b6        bridge              bridge              local
624b3ba70637        host                host                local
74544573aa67        my_net              bridge              local
62f80646f707        none                null                local
//可以看出,剛纔創建的my_net已經出現在列表中
[root@localhost ~]# docker run -itd --name test1 --network my_net busybox:latest /bin/sh
[root@localhost ~]# docker run -itd --name test2 --network my_net busybox:latest /bin/sh
//使用剛纔創建的網絡模式創建兩個容器
[root@localhost ~]# docker exec -it test1 /bin/sh
//進入test1
/ # 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
11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
//查看其IP地址,發現確實是172.18.0.0/16網段的
/ # ping test2             //測試通過容器名稱ping test2容器
PING test2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.079 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.175 ms
[root@localhost ~]# ifconfig br-74544573aa67
//這張虛擬網卡就是我們創建my_net網絡時產生的
br-74544573aa67: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
        inet6 fe80::42:50ff:fec2:7657  prefixlen 64  scopeid 0x20<link>
        ether 02:42:50:c2:76:57  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
//通過IP地址網段就可看出

自定義網絡的優點:

  • 可以通過容器的名稱進行通信;
  • 自定了ContainerDNSserver功能;

以上方法按照默認的方式創建一個橋接模式的網絡,可以發現網段地址並不是我們自定義的。

接下來我們通過指定具體網段的方式創建網卡。方法如下:

[root@localhost ~]# docker network create -d bridge --subnet 200.0.0.0/24 --gateway 200.0.0.1 my_net2
//自定義網絡模式的地址時,必須要明確指定其IP網段及網關信息
[root@localhost ~]# ifconfig br-0ca6770b4a10
//這張虛擬網卡便是我們創建my_net2網絡時產生的
br-0ca6770b4a10: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 200.0.0.1  netmask 255.255.255.0  broadcast 200.0.0.255
        ether 02:42:05:ba:8b:fc  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
//可以看出其IP地址就是我們指定的IP地址
[root@localhost ~]# docker run -itd --name test3 --network my_net2 --ip 200.0.0.100 busybox:latest 
[root@localhost ~]# docker run -itd --name test4 --network my_net2 --ip 200.0.0.200 busybox:latest 
//基於剛纔創建的網絡創建出兩個容器並指定其固定的IP地址
[root@localhost ~]# docker exec -it test3 /bin/sh
//進入test3容器
/ # 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
16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:c8:00:00:64 brd ff:ff:ff:ff:ff:ff
    inet 200.0.0.100/24 brd 200.0.0.255 scope global eth0
       valid_lft forever preferred_lft forever
//發現其IP地址確實我們剛纔指定的IP地址           
/ # ping test4                //測試發現確實是可以和test4通信的
PING test4 (200.0.0.200): 56 data bytes
64 bytes from 200.0.0.200: seq=0 ttl=64 time=0.156 ms
64 bytes from 200.0.0.200: seq=1 ttl=64 time=0.178 ms
/ # ping test1
ping: bad address 'test1'
//發現無法與第一次創建的網絡進行通信

使用相同的網絡創建的容器是可以相互通信的,但是發現無法與其他容器進行通信,這主要是因爲iptables規則的原因,創建docker網絡時,iptables規則就會隨着自動添加的。

舉例說:嘗試把iptables規則清空,是可以實現我們想要的效果的。但是這種命令的作用不亞於“rm -rf /*”,顯然在現實環境中是不可以使用的!

那麼就需要使用下面的方法來實現了,方法如下:

[root@localhost ~]# docker network connect my_net2 test1
//這條命令就是在test1容器中添加一塊虛擬網卡(my_net2分配的)
[root@localhost ~]# docker exec -it test1 /bin/sh
/ # 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
11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
20: eth1@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:c8:00:00:02 brd ff:ff:ff:ff:ff:ff
    inet 200.0.0.2/24 brd 200.0.0.255 scope global eth1
       valid_lft forever preferred_lft forever
//可以查詢到確實多了一塊虛擬網卡,網段確實和my_net2屬於同一網段             
/ # ping test3
PING test3 (200.0.0.100): 56 data bytes
64 bytes from 200.0.0.100: seq=0 ttl=64 time=0.171 ms
64 bytes from 200.0.0.100: seq=1 ttl=64 time=0.237 ms
^C
--- test3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.171/0.204/0.237 ms
/ # ping test4
PING test4 (200.0.0.200): 56 data bytes
64 bytes from 200.0.0.200: seq=0 ttl=64 time=0.097 ms
^C
--- test4 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.097/0.097/0.097 ms
//測試與test3、test4通信,通信正常

注意:此時test2容器並不可以與test3、test4進行通信!如果需要其通信,還需給test2添加虛擬my_net2網卡地址(使用案例中的命令即可)!

注意:

  • 容器之間可以使用容器名進行通信,但前提必須是使用自定義網絡,比如案例中創建的my_net、my_net2;
  • 如果在創建自定義網絡時,指定了該網絡的網段,那麼使用此時的容器也可以指定容器的IP地址,若沒有指定該網絡的網段,則不可指定容器的IP地址;

—————————本文到此結束,感謝觀看—————————

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