Docker 之容器間通訊配置

當你開始大規模使用Docker時,你會發現須要瞭解不少關於網絡的知識。Docker做爲目前最火的輕量級容器技術,有不少使人稱道的功能,如Docker的鏡像管理。然而,Docker一樣有着不少不完善的地方,網絡方面就是Docker比較薄弱的部分。所以,咱們有必要深刻了解Docker的網絡知識,以知足更高的網絡需求。docker

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

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

三個網絡解釋以下:
None:該模式將容器放置在它本身的網絡棧中,可是並不進行任何配置。實際上,該模式關閉了容器的網絡功能,相似於會換地址,在如下兩種狀況下是有用的:容器並不須要網絡(例如只須要寫磁盤卷的批處理任務)
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時,看到的都是宿主機上的信息。該模式不夠靈活,容易出現端口衝突問題
Bridge:至關於Vmware中的NAT模式,容器使用獨立的network Namespace,而且鏈接到docker0虛擬網卡(默認模式)。經過docker網橋以及IPtables nat表配置與宿主機通訊;Bridge模式是Docker默認的網絡設置,此模式會爲每個容器分配一個Network nameSpace、設置IP等,並將一個主機上的Docker容器鏈接到一個虛擬網橋docker0上
overlay:顧名思義:覆蓋,但它又不是覆蓋,它的做用就是在容器原有的網絡基礎之上,再添加一塊網卡,併爲其分配一個IP地址,能夠將全部的docker容器關聯到同一個局域網中,適用於容器與容器是跨主機進行通訊的場景。ide

在生產環境中,應用的最多的就是Bridge模式和overlay模式了。oop

1、Bridge模式
當Docker server啓動時,會在主機上建立一個名爲docker0的虛擬網橋,此主機上啓動的Docker容器就會鏈接到這個虛擬網橋上。虛擬網橋的工做方式和物理交換機相似,這樣主機上的全部容器就經過交換機連在了一個二層網絡中,通常Docker會使用172.17.0.0/16這個網段,並將這個網段分配給docker0網橋使用(在主機上使用ifconfig命令能夠看到docker0),而後爲容器分配一個同網段的IP地址。
單機環境下的網絡拓撲以下(主機地址是10.10.0.186/24):
Docker 之容器間通訊配置測試

Docker 完成以上網絡配置的過程大體是這樣的:spa

  • 在主機上建立一對虛擬網卡veth pair設備。veth設備老是成對出現的,它們組成了一個數據的通道,數據從一個設備進入,就會從另外一個設備出來。所以,veth設備經常使用來鏈接兩個網絡設備。
  • Docker將veth pair設備的一端放在新建立的容器中,並命名爲eth0。另外一端放在主機中,以veth65f9這樣相似的名字命名,並將這個網絡設備加入到docker0網橋中,能夠經過brctl show命令查看。
  • 從docker0子網中分配一個IP給容器使用,並設置docker0的IP地址爲容器的默認網關。

當全部的容器都是基於默認的docker0進行建立的,那麼拋開防火牆、IPtables等相關的設置外,理論上,各個容器是能夠相互通訊的,可是docker0這個網絡是系統自帶的,有些功能不可以實現,而且不夠靈活。code

其實咱們也是能夠自定義建立網絡的,而且能夠指定其具體屬於哪一個網段等。這是docker 0沒法實現的,那麼,若是各個容器,不是基於同一個網絡(如Docker0)建立的話,那麼?如何使它們互通呢?server

實現的效果以下:blog

  • 基於docker0(docker的驅動名稱使bridge)網絡建立2個容器,分別是box一、box2。
  • 建立自定義網絡,網絡類型爲bridge,名稱爲my_net1.基於此網絡建立兩個容器box3,box4(若不指定網段,會使用172.18.0.0/16這個網段,基於docker0增長一個網絡位)
  • 建立自定義網絡,網絡類型爲bridge,名稱爲my_net2,指定網段爲172.20.18.0/24,基於此網絡建立兩個容器box5(ip爲172.20.18.6),box6(IP爲172.20.18.8)。
  • 配置實現box2可以和box3相互通訊,box4和box5能夠相互通訊。
[root@docker03 ~]# docker run -itd --name test1 --network bridge busybox
#建立一個容器box1,--network選項能夠省略,默認就是bridge,這裏只是爲了展現命令
[root@docker03 ~]# docker run -itd --name test2 --network bridge busybox          # 同上
[root@docker03 ~]# docker network create -d bridge my_net1             #建立一個橋接網絡,名稱爲my_net1
[root@docker03 ~]# docker run -itd --name test3 --network my_net1 busybox                #基於my_net1建立容器test3
[root@docker03 ~]# docker run -itd --name test4 --network my_net1 busybox                # 同上
[root@docker03 ~]# docker network create -d bridge --subnet 172.20.18.0/24 my_net2               # 建立一個橋接網絡my_net2,並指定其網段
[root@docker03 ~]# docker run -itd --name test5 --network my_net2 --ip 172.20.18.5 busybox       #基於my_net2網絡,建立一個容器test5,而且指定其IP地址
[root@docker03 ~]# docker run -itd --name test6 --network my_net2 --ip 172.20.18.6 busybox
[root@docker03 ~]# docker network connect my_net1 test2          #將test2鏈接到my_net1這個網絡
[root@docker03 ~]# docker exec test2 ping test3           #進行ping測試,能夠發現test2 能夠ping通test3了。
#而若是沒有將box2鏈接到網絡my_net1,是絕對不會ping通
PING test3 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.121 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.059 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.061 ms
[root@docker03 ~]# docker network connect my_net2 test4    # 將test4鏈接到my_net2網絡
#同box2和box3的ping測試,若沒有將box4鏈接到box5所在的網絡,是不可能ping通的。
[root@docker03 ~]# docker exec test5 ip a         # 查看test5 的IP
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:14:12:05 brd ff:ff:ff:ff:ff:ff
    inet 172.20.18.5/24 brd 172.20.18.255 scope global eth0          # 肯定其IP
       valid_lft forever preferred_lft forever
[root@docker03 ~]# docker exec test4 ping test5     # 能夠ping通
PING test5 (172.20.18.5): 56 data bytes
64 bytes from 172.20.18.5: seq=0 ttl=64 time=0.112 ms
64 bytes from 172.20.18.5: seq=1 ttl=64 time=0.065 ms
64 bytes from 172.20.18.5: seq=2 ttl=64 time=0.058 ms

通過以上配置,已經實現了最終的效果,須要注意的是,咱們徹底能夠將建立的my_net一、my_net2網絡驅動理解爲一個交換機,而執行命令docker network connect my_net1 test2,則至關於將test2這個容器添加了一塊網卡,而後鏈接到了my_net1這個交換機,而後這個容器就多了一塊網卡,而且擁有my_net1這個交換機中IP地址。在上述的配置中,test2不但能夠和test3進行通訊,也是能夠和test4進行通訊的,由於它們都是鏈接在了my_net1這個「交換機」上。進程

注意:

  • 容器之間可使用容器名進行通訊,但前提使用的是自定義的網絡,如上面的my_net一、my_net2;
  • 若是在建立自定義網絡的同時,指定了該網絡的網段,那麼,使用此網絡的容器也能夠指定容器的IP地址,若沒有指定該網絡的網段,則不能夠指定容器的IP地址。