Docker的應用運行在容器中,其相互之間或與外部之間是如何通訊的,涉及到哪些知識點,本文對相關內容進行整理。因網絡這塊牽涉的面較多,所以只從平常使用或理解的角度出發,過於專業的就不深刻探討了。
html
1. Docker默認的網絡拓撲
在Docker筆記(二):Docker管理的對象中,介紹了Docker經過一些驅動程序來實現容器之間或容器與外部的互聯,包括bridge(默認的虛擬網橋形式),host(與主機共享網絡棧),overlay(跨Docker Daemon容器間的互聯),macvlan(爲容器分配mac地址),none(禁用全部網絡)等。docker
默認狀況下,Docker啓動時會建立一個虛擬網橋 docker0,能夠理解爲一個軟件交換機。當建立一個 Docker 容器的時候,會建立一對 veth pair 接口(當數據包發送到一個接口時,另一個接口也能夠收到相同的數據包)。這對接口一端在容器內,即 eth0 ;另外一端在宿主機本地並被掛載到 docker0 網橋,名稱以veth 開頭,如 veth340c305,docker0會在掛載到它上面的網口之間進行轉發,從而實現主機與容器之間及容器與容器之間的相互通訊。Docker默認的網絡拓撲圖以下:
json
咱們能夠在宿主機上經過ifconfig
查看相關的網絡接口,centos
~$ ifconfig docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 inet6 fe80::42:46ff:fe26:ce0b prefixlen 64 scopeid 0x20<link> ether 02:42:46:26:ce:0b txqueuelen 0 (Ethernet) RX packets 16868344 bytes 127838098551 (127.8 GB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 17929275 bytes 137867853738 (137.8 GB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth340c305: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::50f7:7ff:fe8f:6e72 prefixlen 64 scopeid 0x20<link> ether 52:f7:07:8f:6e:72 txqueuelen 0 (Ethernet) RX packets 8093606 bytes 126893792744 (126.8 GB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8795102 bytes 10834735399 (10.8 GB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth6c803b7: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::1045:4cff:fe66:7f5a prefixlen 64 scopeid 0x20<link> ether 12:45:4c:66:7f:5a txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 140 bytes 9832 (9.8 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
|
經過brctl show
可查看網絡接口的掛載狀況,bash
~$ brctl show bridge name bridge id STP enabled interfaces docker0 8000.02424626ce0b no veth340c305 veth6c803b7
|
由上可看出網絡接口veth340c305,veth6c803b7都掛在虛擬網橋docker0上。服務器
2. 容器與外部的互聯
咱們前面的許多容器啓動命令都有添加相似 -p 8080:8080 的參數,以指定將宿主機端口映射到容器端口,從而經過訪問 宿主機IP:宿主機端口
的地址來訪問對應端口的容器服務。
端口映射的完整格式爲 宿主機IP:宿主機端口:容器端口
,其中前兩個是能夠二者都取,或只取其一微信
宿主機IP:宿主機端口:容器端口
:將指定宿主機IP的一個指定端口映射到容器端口,如192.168.40.205:8090:8080
宿主機IP::容器端口
:將指定宿主機IP的一個隨機端口映射到容器端口上,若是宿主機有多個IP,則能夠經過這種格式指定綁定其中一個宿主機IP,隨機端口範圍爲49000~49900
宿主機端口:容器端口
:將宿主機全部網絡接口IP的指定端口映射到容器端口上,8090:8080
等效於0.0.0.0:8090:8080
(0.0.0.0
即表示全部網絡接口地址)
可使用 docker port 容器ID或名稱 容器端口
或docker ps
命令來查看端口映射狀況,如網絡
~$ docker port test-dev 8080 0.0.0.0:32768
~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 696a76944e72 cnbots:dev "/bin/sh -c '/usr/lo…" 23 minutes ago Up 23 minutes 0.0.0.0:32768->8080/tcp test-dev
|
在容器啓動時,能夠屢次使用 -p 來指定映射多個端口。tcp
若是不指定具體的宿主機端口,則可使用 -P(大寫)來分配一個宿主機的隨機端口(範圍爲49000~49900), 如docker run -d -P --name test-dev test:dev
,而後經過docker port 容器ID或名稱 容器端口
或docker ps
命令來查看具體映射到了哪一個端口。spa
3. 容器之間的互聯
同一個Docker Daemon下的容器,彼此之間是能夠經過容器IP互相訪問的(如何查看容器IP?用docker inspect 容器ID或名稱
命令),若是要實現兩個容器之間能夠經過容器名直接訪問,則能夠經過自建一個docker網絡。
# 建立一個自定義網絡,-d 表示網絡類型,能夠爲bridge(網橋,軟件交換機),或overlay(跨Docker Daemon容器間的互聯) ~$ docker network create -d bridge my-net 0c97fc265ed1cab67d84b9376d6914c9558419c73bb5abc040e75c945cd99f0a
# 啓動一個centos容器centos1,經過 --network 指定自定義網絡 ~$ docker run -it --name centos1 --network my-net centos:7.3.1611 bash [root@3dcf507bd12a /]#
# 再啓動一個centos容器centos2(打開另外一個窗口),指定同一個自定義網絡 ~$ docker run -it --name centos2 --network my-net centos:7.3.1611 bash [root@16dcce660a89 /]#
# 在centos1容器中直接ping centos2 [root@3dcf507bd12a /]# ping centos2 PING centos2 (172.19.0.2) 56(84) bytes of data. 64 bytes from centos2.my-net (172.19.0.2): icmp_seq=1 ttl=64 time=0.111 ms 64 bytes from centos2.my-net (172.19.0.2): icmp_seq=2 ttl=64 time=0.058 ms
# 在centos2容器中直接ping centos1 [root@16dcce660a89 /]# ping centos1 PING centos1 (172.19.0.3) 56(84) bytes of data. 64 bytes from centos1.my-net (172.19.0.3): icmp_seq=1 ttl=64 time=0.061 ms 64 bytes from centos1.my-net (172.19.0.3): icmp_seq=2 ttl=64 time=0.054 ms
|
由上可見經過自定義網橋鏈接的容器能夠經過容器名稱互相訪問。若是須要多個容器之間互聯,則可使用Docker Compose。
4. 配置容器的DNS
若是要自定義全部容器的DNS,則能夠在 /etc/docker/daemon.json 中增長
{ "dns" : [ "114.114.114.114", "8.8.8.8" ] }
|
也能夠在啓動容器時經過參數指定單個容器的DNS配置,--dns=IP_ADDRESS
,這會將指定DNS的地址添加到容器的 /etc/resolv.conf 文件中,讓容器用這個DNS服務器來解析全部不在 /etc/hosts 中的主機名。
5. Docker網絡的底層實現
容器的網絡訪問控制,主要是經過Linux上的iptables防火牆來實現與管理的。
1. 容器訪問外部網絡
容器訪問外部網絡,須要經過本地系統的轉發,能夠經過以下命令查看轉發是否打開
$sysctl net.ipv4.ip_forward net.ipv4.ip_forward = 1
# 爲1爲打開,爲0則未打開,可經過以下命令打開,也能夠在Docker服務啓動時經過參數--ip-forward=true打開 $sysctl -w net.ipv4.ip_forward=1
|
容器全部到外部網絡的訪問,源地址都會被 NAT 成本地系統的 IP 地址。這是使用 iptables 的源地址假裝操做實現的,
~# iptables -t nat -nL Chain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
|
上述規則將全部源地址在 172.17.0.0/16 的網段(容器IP所在網段),目標地址爲任意網段(包括外部網絡)的流量動態假裝爲從系統網卡發出。MASQUERADE 跟傳統 SNAT 的好處是它能動態從網卡獲取地址。
2. 外部訪問容器
經過 -p 或 -P 指定端口映射,容許外部訪問容器端口,實質也是在本地的 iptable 的 nat 表中添加相應的規則,如
~# iptables -t nat -nL Chain DOCKER (2 references) target prot opt source destination DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 to:172.17.0.2:3306 DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:11090 to:172.17.0.3:11090
|
這裏的規則映射了 0.0.0.0 ,意味着將接受主機來自全部網絡接口的流量。
3. 容器之間的訪問
容器之間能互相訪問,須要知足兩個條件:1)容器的網絡拓撲是否已經互聯,默認狀況下容器都鏈接到docker0網橋上,默認是互聯的。2)本地系統的防火牆iptables是否容許經過。當容器啓動時經過–link互聯時,也是在iptables中建立對應規則來實現。
6. 總結
本文整理了Docker網絡相關知識,對容器之間及容器與外部之間的通訊機制應該有了必定的瞭解。除了默認的網絡實現,Docker還提供了網絡的配置及自定義網絡,出於篇幅,本文介紹到這,後續再補充。
相關閱讀
Docker筆記(一):什麼是Docker
Docker筆記(二):Docker管理的對象
Docker筆記(三):Docker安裝與配置
Docker筆記(四):Docker鏡像管理
Docker筆記(五):整一個本身的鏡像
Docker筆記(六):容器管理
Docker筆記(七):經常使用服務安裝——Nginx、MySql、Redis
Docker筆記(八):數據管理
個人微信公衆號:jboost-ksxy (一個不僅有技術乾貨的公衆號,歡迎關注,及時獲取更新內容)
