當你開始大規模使用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 完成以上網絡配置的過程大體是這樣的: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地址。