摘要:而本文主要針對容器間的網絡通信方法進行討論。而同屬于用戶自定義的容器之間自動將所有端口暴露,方便容器間進行無障礙的通信,而不會遭受到外界的意外訪問。
幾天前,為了解決日常在本地進行日常工作和開發測試之間的矛盾,利用docker在Windows系統中搭建了基于Linux的測試環境:借助Docker,在win10下編碼,一鍵在Linux下測試。在這邊文章里主要介紹了如何在本地通過docker構建與生產環境基本一致的環境并一鍵運行、測試我們的代碼。Docker官方建議每個容器中只運行一個服務[1],但是我們的項目可能是由多個服務組成,在服務中可能會需要mysql、redis等中間件的支持,所以通常我們將一個項目的不同服務劃分到不同容器中。這種做法雖然具有低耦合、高隔離性等優點,但是也增加了服務之間通信的復雜度。
Docker容器間的通信方式根據媒介可以分為:volume共享通信、網絡通信等;根據通信范圍也可以分為:同主機通信和跨主機通信等。而本文主要針對容器間的網絡通信方法進行討論。
1. Docker的網絡驅動模型
Docker的網絡驅動模型分類:
bridge:Docker中默認的網絡驅動模型,在啟動容器時如果不指定則默認為此驅動類型;
host:打破Docker容器與宿主機之間的網絡隔離,直接使用宿主機的網絡環境,該模型僅適用于Docker17.6及以上版本;
overlay:可以連接多個docker守護進程或者滿足集群服務之間的通信;適用于不同宿主機上的docker容器之間的通信;
macvlan:可以為docker容器分配MAC地址,使其像真實的物理機一樣運行;
none:即禁用了網絡驅動,需要自己手動自定義網絡驅動配置;
plugins:使用第三方網絡驅動插件;
以上是Docker支持的幾種網絡驅動模型,它們都具有獨特的特點和應用范圍,為了更加詳細地了解Docker的網絡運行原理,下面挑選幾種較為重要的網絡模型進行研究。
2. bridge
如上圖所示為Docker中bridge驅動模式的示意圖,其中藍色的模塊表示主機上的網卡。當Docker啟動時會自動在主機上創建一個虛擬網橋docker0,使用默認網絡模式創建docker容器時會自動創建一對兒veth pair接口,一端連接在docker容器中(如圖容器中的eth0),一端連接在虛擬網橋docker0上(如圖veth)。這種veth pair是一種虛擬網絡設備,主要用于不同namespace中(意味著網絡隔離)的網絡通信,它總是成對存在的。在這里可以把它想象成一對兒靠虛擬網線連接起來的兩個虛擬網卡,一端連接著docker容器,一端連接著虛擬網橋docker0。
通過這種方式,不同docker容器之間可以通過ip地址互相通信,也可以通過虛擬網橋訪問主機上的網絡eth0(添加iptables規則,將docker容器對目標地址發出的訪問通過地址偽裝的方式修改為主機對目標地址進行訪問)。
如果想要外界網絡訪問docker容器時,需要在docker容器啟動時加上參數"-p [主機端口]:[容器端口]"進行端口映射,原理也是通過修改iptables規則將訪問[主機端口]的數據轉發到docker容器的[容器端口]中,但是這種做法也存在著占用主機有限的端口資源的缺點。
在主機上通過命令docker network ls可以查看docker中存在的網絡:
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服務容器
"dd292d535d16bbfe5382e29486756f4ffffdfea8e9b10af769db61618d739c5c4e": {
"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可以在容器化的應用程序提供更好的隔離效果和更好的互通性: 這段話看似有些矛盾,但是其中更好的隔離效果是針對外界網絡,而更好的互通性則是指同一bridge下的不同容器之間。還是以之前的分別部署了Web服務和mysql服務的兩個容器container1、container2為例,container1只需要對外界網絡暴露Web服務的80端口,而負責后端的container2只需與container1互連,不需要對外暴露,有效地保護了后端容器的安全性,提高了容器對外的隔離效果。而同屬于用戶自定義bridge的容器container1、container2之間自動將所有端口暴露,方便容器間進行無障礙的通信,而不會遭受到外界的意外訪問。
用戶自定義bridge在容器之間提供了自動DNS解析: 這也是本文討論的重點,不同于默認bridge只能通過IP互連的限制,用戶自定義的bridge自動提供了容器間的DNS解析功能,容器間可以通過容器名或別名進行通信。
創建用戶自定義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": ""
},
"dd292d535d16bbfe5382e29486756f4ffffdfea8e9b10af769db61618d739c5c4e": {
"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
3. overlay
關鍵字:跨主機通信、集群
Run multiple services in a container. docs.docker.com/config/cont… ??
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/6726.html
摘要:各項配置如下主機的地址為主機的地址為為主機上的容器分配的子網為主機上的容器分配的子網這樣配置之后,兩個主機上的容器就肯定不會使用相同的地址從而避免了沖突。 showImg(https://segmentfault.com/img/remote/1460000015283239); 概述 就目前Docker自身默認的網絡來說,單臺主機上的不同Docker容器可以借助docker0網橋...
摘要:是容器中的一條,是由參數添加進來的。補充容器重啟后可能變化,所以直接在中指定并不是一個好方法。使用時文件會隨著容器的變化更新,所以使用域名才是更容易維護的方法。 轉載請注明出處,原文鏈接http://tailnode.tk/2017/01/do... 以我的ghost博客為例進行說明,我在VPS上用docker啟動了兩個ghost博客,還有一個Nginx做反向代理,將兩個域名分別指向兩...
摘要:本文涵蓋了中的六大新特性內置命令服務發現自愈功能安全負載均衡滾動升級,相關的使用文檔和視頻鏈接也都包含在里面。同時,內部負載均衡要求一個可用的容器。現在開箱即用的負載均衡,上公開暴露的端口在所有節點都是可以訪問的。 Docker 1.12版本最近剛剛發布,這篇文章對它的新特性進行了概述和對比描述。本文涵蓋了 Docker 1.12 中的六大新特性:內置 swarm命令、服務發現、自愈功...
摘要:日志會顯示令牌過期的信息,隨后檢查主機和主機的時鐘是否同步。如果這個子網已經被使用,你將需要更改網絡中使用的默認子網。如果負載均衡器處于初始化狀態,則很可能主機之間無法進行跨主機通信。而一直顯示黃色初始化狀態,說明一直沒有通過健康檢查。 一、服務/容器 1、為什么我只能編輯容器的名稱? Docker容器在創建之后就不可更改了。唯一可更改的內容是我們要存儲的不屬于Docker容器本身的那...
閱讀 4160·2021-11-22 13:52
閱讀 2074·2021-09-22 15:12
閱讀 1121·2019-08-30 15:53
閱讀 3454·2019-08-29 17:12
閱讀 2190·2019-08-29 16:23
閱讀 1647·2019-08-26 13:56
閱讀 1772·2019-08-26 13:44
閱讀 1880·2019-08-26 11:56