Docker網絡管理之容器間的通訊

前言

因爲docker技術的火爆,致使如今愈來愈多的企業都在使用docker這種虛擬化技術。企業中使用docker這種虛擬化技術,其目的就是爲了讓docker中的容器對外提供服務。所以,咱們必須深刻了解一下docker的網絡知識,以知足更高的網絡需求。html

咱們安裝Docker時,它會自動建立三個網絡,bridge(建立容器默認鏈接到此網絡)、 none 、host。

* host:容器將不會虛擬出本身的網卡,配置本身的IP等,而是使用宿主機的IP和端口。
* None:該模式關閉了容器的網絡功能,至關於一個迴環網絡。
* Bridge:此模式會爲每個容器分配、設置IP等,並將容器鏈接到一個叫docker0的虛擬網橋,經過docker0網橋以及Iptables nat表配置與宿主機通訊。
[root@docker ~]# docker network  ls          //執行該命令查看docker建立的網絡
NETWORK ID          NAME                DRIVER              SCOPE
2edf7ef4f9fa        bridge              bridge              local
217d2e9a4785        host                host                local
c0bea73a8e1a        none                null                local

關於上述提到的三個網絡解釋以下:web

  • Host:至關於Vmware中的橋接模式,與宿主機在同一個網絡中,但沒有獨立的IP地址。衆所周知,Docker使用了Linux的Namespaces技術來進行資源隔離,如PID Namespace隔離進程,Mount Namespace隔離文件系統,Network Namespace隔離網絡等。一個Network Namespace提供了一份獨立的網絡環境,包括網卡、路由、Iptable規則等都與其餘的Network Namespace隔離。一個Docker容器通常會分配一個獨立的Network Namespace。但若是啓動容器的時候使用host模式,那麼這個容器將不會得到一個獨立的Network Namespace,而是和宿主機共用一個Network Namespace。容器將不會虛擬出本身的網卡,配置本身的IP等,而是使用宿主機的IP和端口。基於Host模式啓動的容器,在容器內執行ifconfig時,看到的都是宿主機上的信息。該模式不夠靈活,容易出現端口衝突問題。
  • None:該模式將容器放置在它本身的網絡棧中,可是並不進行任何配置。實際上,該模式關閉了容器的網絡功能,相似於會換地址,在如下兩種狀況下是有用的:容器並不須要網絡(例如只須要寫磁盤卷的批處理任務)。
  • overlay:顧名思義:覆蓋,但它又不是覆蓋,它的做用就是在容器原有的網絡基礎之上,再添加一塊網卡,併爲其分配一個IP地址,能夠將全部的docker容器關聯到同一個局域網中,適用於容器與容器是跨主機進行通訊的場景。
  • Bridge:至關於Vmware中的NAT模式,容器使用獨立的network Namespace,而且鏈接到docker0虛擬網卡(默認模式)。經過docker網橋以及IPtables nat表配置與宿主機通訊;Bridge模式是Docker默認的網絡設置,此模式會爲每個容器分配一個Network nameSpace、設置IP等,並將一個主機上的Docker容器鏈接到一個虛擬網橋docker0上。

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

雖然docker模式提供三種網絡模式,但實際上是有四種網絡模式的!安全

一、none模式

在none模式下,Docker容器擁有本身的Network Namespace,可是,並不爲Docker容器進行任何網絡配置。也就是說,這個Docker容器只有一個迴環地址,不能與外界通訊,稱爲被隔離的網絡。
使用場景:網絡

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

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

[root@docker ~]# docker run -itd --name none --network none busybox:latest 
//使用busybox鏡像建立一個名爲none的容器,網絡採用none模式
[root@docker ~]# docker exec  -it  none sh         //進入剛剛建立的容器
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    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

二、host模式

若是啓動容器時使用host模式,那麼這個容器將不會得到一個獨立的Network Namespace,而是和宿主機共用一個Network Namespace。容器將不會虛擬出本身的網卡,配置本身的IP等,而是使用宿主機的IP和端口。性能

使用場景:測試

因爲網絡配置與docker宿主機徹底同樣,性能較好,可是不便之處就是靈活性不高,容易和宿主機出現端口衝突的問題。最好是單個容器時使用,通常狀況下不建議使用。spa

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

[root@docker ~]# docker run  -itd --name host --network host  busybox:latest 
//使用busybox鏡像建立一個名爲host的容器,網絡採用host模式
[root@docker ~]# docker exec -it host sh      //進入建立的容器
/ # ip a
//進入容器後能夠看出容器中的網絡與docker主機的網絡如出一轍
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    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:06:84:51 brd ff:ff:ff:ff:ff:ff
    inet 192.168.45.129/24 brd 192.168.45.255 scope global dynamic ens33
       valid_lft 1479sec preferred_lft 1479sec
    inet6 fe80::7992:920f:d01f:6485/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:e5:63:9d 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:e5:63:9d brd ff:ff:ff:ff:ff:ff
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue 
    link/ether 02:42:95:5a:2d:28 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

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@docker ~]# 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:95:5a:2d:28  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@docker ~]# brctl  show                    //查看橋接網絡
bridge name bridge id       STP enabled interfaces
docker0     8000.0242955a2d28   no         //若是沒有建立橋接模式的容器,默認是空的。
virbr0      8000.525400e5639d   yes     virbr0-nic

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

[root@docker ~]#  docker run -itd --name bridge busybox:latest /bin/sh
//建立一個名爲bridge的容器,若是沒有指定網絡模式,默認即是bridge模式
[root@docker ~]# docker exec  -it bridge  /bin/sh   //進入建立的容器中
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    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
 //能夠看出eth0@if7這塊虛擬網卡上的地址與docker宿主機的docker0網絡屬於同一網段
 [root@docker ~]# brctl show
bridge name bridge id       STP enabled interfaces
docker0     8000.0242955a2d28   no      veth33eb530
virbr0      8000.525400e5639d   yes     virbr0-nic
/能夠看到橋接模式的接口下出現了一個新的接口,當建立一個容器便會出現一個接口
//這個接口即是容器在docker宿主機建立一個虛擬網卡,用於容器與docker通訊
[root@docker ~]# ifconfig  veth33eb530
veth33eb530: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::30a8:fff:fe8c:41f4  prefixlen 64  scopeid 0x20<link>
        ether 32:a8:0f:8c:41:f4  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 24  bytes 2618 (2.5 KiB)
        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地址爲容器的默認網關;

四、自定義bridge網絡

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

[root@docker ~]# docker network  create -d bridge  my_net
//建立一個橋接網絡,名稱爲my_net,若是沒有指定網段,默認是172.18.0.0/16,按docker0的網段自動遞增
[root@docker ~]# docker network  ls               //查看docker支持的網絡類型
NETWORK ID          NAME                DRIVER              SCOPE
2edf7ef4f9fa           bridge                   bridge                 local
217d2e9a4785        host                     host                         local
ac4d9e74e744        my_net                bridge                     local
c0bea73a8e1a        none                    null                         local
//能夠看出,剛纔建立的my_net已經出如今列表中
[root@docker ~]# docker inspect  my_net   查看默認IP地址
[
    {
        "Name": "my_net",
        "Id": "ac4d9e74e744a140ed8be2a7db0f0b0c5913d08258154fadb0f2ec64a61549db",
        "Created": "2020-08-01T10:03:46.543981931+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",      //若是沒有指定網段,默認是172.18.0.0/16
                    "Gateway": "172.18.0.1"
[root@docker ~]# docker run -itd --name test1 --network my_net busybox:latest /bin/sh
[root@docker ~]# docker run -itd --name test2 --network my_net busybox:latest /bin/sh
//使用剛纔建立的網絡模式建立兩個容器
[root@docker ~]# docker exec  -it test1 /bin/sh  //進入test容器
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    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
9: eth0@if10: <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.057 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.148 ms
64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.143 ms
[root@docker ~]# ip a

Docker網絡管理之容器間的通訊

[root@docker ~]# ifconfig br-ac4d9e74e744
br-ac4d9e74e744: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255      //經過IP地址網段就可看出
        inet6 fe80::42:3dff:fe79:ee81  prefixlen 64  scopeid 0x20<link>
        ether 02:42:3d:79:ee:81  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
**自定義網絡的優勢:**

* 能夠經過容器的名稱進行通訊;
* 自定了ContainerDNSserver功能;

以上方法按照默認的方式建立一個橋接模式的網絡,能夠發現網段地址並非咱們自定義的。

接下來咱們經過指定具體網段的方式建立網卡。方法以下:

[root@docker ~]# docker network create -d bridge --subnet 172.20.16.0/24 --gateway 172.20.16.1 my_net2
//自定義網絡模式的地址時,必需要明確指定其IP網段及網關信息
[root@docker ~]# ip a

Docker網絡管理之容器間的通訊

[root@docker ~]# ifconfig  br-70bd6d1c3371
br-70bd6d1c3371: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.20.16.1  netmask 255.255.255.0  broadcast 172.20.16.255     
        ether 02:42:d8:9e:20:0b  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@docker ~]# docker run -itd --name test3 --network my_net2 --ip 172.20.16.3 busybox:latest
[root@docker ~]# docker run -itd --name test4 --network my_net2 --ip 172.20.16.4 busybox:latest
//基於剛纔建立的網絡建立出兩個容器並指定其固定的IP地址
[root@docker ~]# docker exec  -it test3 sh      //進入test3容器
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    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:14:10:03 brd ff:ff:ff:ff:ff:ff
    inet 172.20.16.3/24 brd 172.20.16.255 scope global eth0
       valid_lft forever preferred_lft forever
//發現其IP地址確實咱們剛纔指定的IP地址           
/ # ping test4                //測試發現確實是能夠和test4通訊的
PING test4 (172.20.16.4): 56 data bytes
64 bytes from 172.20.16.4: seq=0 ttl=64 time=0.089 ms
64 bytes from 172.20.16.4: seq=1 ttl=64 time=0.146 ms
64 bytes from 172.20.16.4: seq=2 ttl=64 time=0.105 ms
/ # ping test1               //測試發現沒法與第一次建立的my_net網絡進行通訊
ping: bad address 'test1'

使用相同的網絡建立的容器是能夠相互通訊的,可是發現沒法與其餘容器進行通訊,這主要是由於iptables規則的緣由,建立docker網絡時,iptables規則就會隨着自動添加的。

舉例說:嘗試把iptables規則清空(iptables -F),是能夠實現咱們想要的效果的。可是這種命令的做用不亞於「rm -rf /*」,顯然在現實環境中是不可使用的!(iptables -F)

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

[root@docker ~]# docker network connect  my_net2 test1
[root@docker ~]# docker exec  -it test1 sh   //進入test1容器
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    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
9: eth0@if10: <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:ac:14:10:02 brd ff:ff:ff:ff:ff:ff
    inet 172.20.16.2/24 brd 172.20.16.255 scope global eth1
       valid_lft forever preferred_lft forever
//能夠查詢到確實多了一塊虛擬網卡,網段確實和my_net2屬於同一網段        
/ # ping test3     
PING test3 (172.20.16.3): 56 data bytes
64 bytes from 172.20.16.3: seq=0 ttl=64 time=0.140 ms
64 bytes from 172.20.16.3: seq=1 ttl=64 time=0.057 m
/ # ping test4
PING test4 (172.20.16.4): 56 data bytes
64 bytes from 172.20.16.4: seq=0 ttl=64 time=0.192 ms
64 bytes from 172.20.16.4: seq=1 ttl=64 time=0.143 ms
//測試與test三、test4通訊,通訊正常

注:此時test2容器並不能夠與test三、test4進行通訊!若是須要其通訊,還需給test2添加虛擬my_net2網卡地址(使用案例中的命令便可)!

**注意:**

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

五、container(共享網絡協議棧)

這個模式指定新建立的容器和已經存在的一個容器共享一個Network Namespace,而不是和宿主機共享。新建立的容器不會建立本身的網卡,配置本身的IP,而是和一個指定的容器共享IP、端口範圍等。一樣,兩個容器除了網絡方面,其餘的如文件系統、進程列表等仍是隔離的。兩個容器的進程能夠經過lo網卡設備通訊。
使用場景
因爲這種網絡的特殊性,通常在運行同一個服務,而且合格服務須要作監控,以及日誌收集、或者網絡監控的時候,能夠選擇這種網絡。
建立使用container網絡模式的容器示例:

[root@docker ~]# docker run -itd --name web1 busybox:latest
[root@docker ~]# docker run -itd --name web2 --network container:web1 busybox:latest
[root@docker ~]# docker exec  -it web2  sh
/ # echo  "Thank you" > /tmp/index.html                       
/ # httpd -h /tmp/      //模擬http服務
[root@docker ~]# docker exec  -it web1  sh
/ #  wget -O - -q 127.0.0.1
Thank you
//發如今web1上也可以獲取到暴露在外http服務

web1容器:
Docker網絡管理之容器間的通訊
web2容器:
Docker網絡管理之容器間的通訊
注:這時會發現兩個容器,共用的是同一個IP地址服務

相關文章
相關標籤/搜索