幾天前,爲了解決平常在本地進行平常工做和開發測試之間的矛盾,利用docker在Windows系統中搭建了基於Linux的測試環境:藉助Docker,在win10下編碼,一鍵在Linux下測試。在這邊文章裏主要介紹瞭如何在本地經過docker構建與生產環境基本一致的環境並一鍵運行、測試咱們的代碼。Docker官方建議每一個容器中只運行一個服務[1],可是咱們的項目多是由多個服務組成,在服務中可能會須要mysql、redis等中間件的支持,因此一般咱們將一個項目的不一樣服務劃分到不一樣容器中。這種作法雖然具備低耦合、高隔離性等優勢,可是也增長了服務之間通訊的複雜度。mysql
Docker容器間的通訊方式根據媒介能夠分爲:volume共享通訊
、網絡通訊
等;根據通訊範圍也能夠分爲:同主機通訊
和跨主機通訊
等。而本文主要針對容器間的網絡通訊方法進行討論。redis
Docker的網絡驅動模型分類:sql
以上是Docker支持的幾種網絡驅動模型,它們都具備獨特的特色和應用範圍,爲了更加詳細地瞭解Docker的網絡運行原理,下面挑選幾種較爲重要的網絡模型進行研究。docker
如上圖所示爲Docker中bridge
驅動模式的示意圖,其中藍色的模塊表示主機上的網卡。當Docker啓動時會自動在主機上建立一個虛擬網橋docker0
,使用默認網絡模式建立docker容器時會自動建立一對兒veth pair
接口,一端鏈接在docker容器中(如圖容器中的eth0
),一端鏈接在虛擬網橋docker0
上(如圖veth
)。這種veth pair
是一種虛擬網絡設備,主要用於不一樣namespace中(意味着網絡隔離)的網絡通訊,它老是成對存在的。在這裏能夠把它想象成一對兒靠虛擬網線鏈接起來的兩個虛擬網卡,一端鏈接着docker容器,一端鏈接着虛擬網橋docker0
。shell
經過這種方式,不一樣docker容器之間能夠經過ip地址互相通訊,也能夠經過虛擬網橋訪問主機上的網絡eth0
(添加iptables規則,將docker容器對目標地址發出的訪問經過地址假裝的方式修改成主機對目標地址進行訪問)。後端
若是想要外界網絡訪問docker容器時,須要在docker容器啓動時加上參數'-p [主機端口]:[容器端口]'進行端口映射,原理也是經過修改iptables規則將訪問[主機端口]的數據轉發到docker容器的[容器端口]中,可是這種作法也存在着佔用主機有限的端口資源的缺點。安全
在主機上經過命令docker network ls
能夠查看docker中存在的網絡:bash
docker network ls
# 輸出結果:
NETWORK ID NAME DRIVER SCOPE
e79b7548b225 bridge bridge local
666d5f1f459d host host local
d0d785cf4794 none null local
複製代碼
而後經過命令docker network inspect bridge
查看bridge網絡的詳細配置:服務器
docker network inspect bridge
# 輸出結果:
[
{
"Name": "bridge",
"Id": "e79b7548b225c3c80d0f70d0de0b5911ed70a7f39ac20f75a8ae71c5cef05b3a",
"Created": "2019-05-17T13:01:27.6581642Z",
"Scope": "local",
"Driver": "bridge", # bridge驅動模式
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16", # 子網,docker容器的IP範圍
"Gateway": "172.17.0.1" # 網關,即docker0
}
]
},
...
省略
...
# 兩個docker容器(一個mysql容器,一個Web服務容器)的網絡配置
"Containers": {
# mysql容器
"d6f33e9bbd60e10d02dd2eebea424a7fc129d9646c96742ec3fe467833017679": {
"Name": "mysqld5.7",
"EndpointID": "32e900f33367e3570c416c43a5618bd7a742cf94f36799e92895951ed1784736",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16", # 容器的IP
"IPv6Address": ""
},
# 基於tornado的Web服務容器
"dd292d535d16bbfe5382e29486756f4dddfea8e9b10af769db61618d739c5c4e": {
"Name": "test_demo",
"EndpointID": "eaf8e294f7b54aa50c6e6b30ac91f63b1a0ccbc5b56d6fbdcfeacd0471b15eb3",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16", # 容器的IP
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
複製代碼
由上述配置信息能夠看出,docker網橋的網關的IP爲"172.17.0.1",也即docker0
,而docker的子網爲"172.17.0.0/16",docker將會爲容器在"172.17.0.0/16"中分配IP,如其中的mysql容器
的IP爲"172.17.0.2/16"、test_demo容器
的IP爲"172.17.0.3/16"。因爲不一樣容器經過veth pair
鏈接在虛擬網橋docker0
上,因此容器之間能夠經過IP互相通訊,可是沒法經過容器名進行通訊:網絡
# 在test_demo容器中訪問mysqld5.7容器(經過IP)
ping 172.17.0.2 -c 3
# 輸出結果:
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.147 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.185 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.209 ms
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2057ms
rtt min/avg/max/mdev = 0.147/0.180/0.209/0.027 ms
# 在test_demo容器中訪問mysqld5.7容器(經過容器名)
ping mysqld5.7
# 輸出結果:
ping: mysqld5.7: Name or service not known
複製代碼
因此,默認的網橋bridge
上的容器只能經過IP互連,沒法經過DNS解析名稱或別名。假如咱們在container1中部署了Web服務,在container2中部署了mysql,container1中的Web服務每每須要鏈接container2的mysql,這是隻能靠IP進行鏈接,可是docker也沒法保證容器重啓後的IP地址不變,因此更好的方式是經過別名進行互聯,在網絡中加入DNS服務器,將容器名與IP地址進行匹配,省去了手動修改Web服務中鏈接mysql的IP的過程。
爲了實現不一樣容器經過容器名或別名的互連,docker提供瞭如下幾種:
在啓動docker容器時加入--link
參數,可是目前已經被廢棄,廢棄的主要緣由是須要在鏈接的兩個容器上都建立--link
選項,當互連的容器數量較多時,操做的複雜度會顯著增長;
啓動docker容器後進入容器並修改/etc/host
配置文件,缺點是手動配置較爲繁雜;
用戶自定義bridge
網橋,這是目前解決此類問題的主要方法;
用戶自定義bridge相對於使用默認bridge的主要優點:
更好的隔離效果
是針對外界網絡,而更好的互通性
則是指同一bridge
下的不一樣容器之間。仍是以以前的分別部署了Web服務和mysql服務的兩個容器container一、container2爲例,container1只須要對外界網絡暴露Web服務的80
端口,而負責後端的container2只需與container1互連,不須要對外暴露,有效地保護了後端容器的安全性,提升了容器對外的隔離效果。而同屬於用戶自定義bridge
的容器container一、container2之間自動將全部端口暴露,方便容器間進行無障礙的通訊,而不會遭受到外界的意外訪問。建立用戶自定義bridge:
docker network create my-net # 建立了一個名爲"my-net"的網絡
複製代碼
將Web服務容器和mysql服務容器加入到"my-net"中,並觀察變化:
docker network connect my-net test_demo # 將Web服務加入my-net網絡中
docker network connect my-net mysqld5.7 # 將mysql服務加入my-net網絡中
複製代碼
# 查看my-net的網絡配置
docker network inspect my-net
# 輸出結果(省略部份內容):
[
{
"Name": "my-net",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Config": [
{
"Subnet": "172.18.0.0/16", # my-net的子網
"Gateway": "172.18.0.1" # my-net的網關
}
]
},
"Containers": {
"d6f33e9bbd60e10d02dd2eebea424a7fc129d9646c96742ec3fe467833017679": {
"Name": "mysqld5.7",
"EndpointID": "7d0e8d70bb523cceb4d2d8d4e3f8231fc68332c70f7f9b4e5d4abccce2b31a65",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16", # mysql服務容器的IP,與以前不一樣
"IPv6Address": ""
},
"dd292d535d16bbfe5382e29486756f4dddfea8e9b10af769db61618d739c5c4e": {
"Name": "test_demo",
"EndpointID": "f7802f1af81e258f77e227609dfdcdf66c49f19776381eb8b0dca6d9e794ccad",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16", # Web服務容器的IP,與以前不一樣
"IPv6Address": ""
}
},
}
]
複製代碼
如上所示,用戶自定義網絡my-net
的子網爲"172.18.0.0/16",因此兩docker容器在my-net
網絡中的IP分別爲:"172.18.0.3/16"、"172.18.0.2/16",與以前的"172.17.0.2/16"、"172.17.0.3/16"不一樣。
經過容器名或別名互連: 進入到Web服務器container1中鏈接container2:
ping mysqld5.7 -c 3
# 輸出結果:
PING mysqld5.7 (172.18.0.3) 56(84) bytes of data.
64 bytes from mysqld5.7.my-net (172.18.0.3): icmp_seq=1 ttl=64 time=0.066 ms
64 bytes from mysqld5.7.my-net (172.18.0.3): icmp_seq=2 ttl=64 time=0.145 ms
64 bytes from mysqld5.7.my-net (172.18.0.3): icmp_seq=3 ttl=64 time=0.143 ms
--- mysqld5.7 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2048ms
rtt min/avg/max/mdev = 0.066/0.118/0.145/0.036 ms
複製代碼
如上所示,咱們已經能夠經過容器名"mysqld5.7"鏈接mysql服務器了。
斷開網絡: 因爲咱們的容器仍然鏈接着默認bridgedocker0
,而如今咱們已經不須要它,因此應該將容器與docker0
的鏈接斷開,執行如下操做:
# 斷開容器與docker0的鏈接
docker network disconnect bridge test_demo
docker network disconnect bridge mysqld5.7
複製代碼
關鍵字:跨主機通訊、集羣
Run multiple services in a container. docs.docker.com/config/cont… ↩︎