網絡-Docker 提供的幾種原生網絡和自定義網絡(11)

Docker 網絡從覆蓋範圍可分爲單個 host 上的容器網絡和跨多個 host 的網絡,本章重點討論前一種linux

Docker 安裝時會自動在 host 上建立三個網絡,咱們可用 docker network ls 命令查看:web

146.png

下面咱們分別討論它們。docker

none 網絡

故名思議,none 網絡就是什麼都沒有的網絡。掛在這個網絡下的容器除了 lo,沒有其餘任何網卡。容器建立時,能夠經過 --network=none 指定使用 none 網絡。安全

咱們不由會問,這樣一個封閉的網絡有什麼用呢?網絡

其實還真有應用場景。封閉意味着隔離,一些對安全性要求高而且不須要聯網的應用可使用 none 網絡。app

好比某個容器的惟一用途是生成隨機密碼,就能夠放到 none 網絡中避免密碼被竊取。oop

固然大部分容器是須要網絡的,咱們接着看 host 網絡。性能

host 網絡

鏈接到 host 網絡的容器共享 Docker host 的網絡棧,容器的網絡配置與 host 徹底同樣。能夠經過 --network=host 指定使用 host 網絡。ui

在容器中能夠看到 host 的全部網卡,而且連 hostname 也是 host 的。host 網絡的使用場景又是什麼呢?spa

直接使用 Docker host 的網絡最大的好處就是性能,若是容器對網絡傳輸效率有較高要求,則能夠選擇 host 網絡。固然不便之處就是犧牲一些靈活性,好比要考慮端口衝突問題,Docker host 上已經使用的端口就不能再用了。

Docker host 的另外一個用途是讓容器能夠直接配置 host 網路。好比某些跨 host 的網絡解決方案,其自己也是以容器方式運行的,這些方案須要對網絡進行配置,好比管理 iptables,你們將會在後面進階技術章節看到。

bridge 網絡

Docker 安裝時會建立一個 命名爲 docker0 的 linux bridge。若是不指定--network,建立的容器默認都會掛到 docker0 上

brctl show #查看bridge網絡  yum install bridge-utils

docker network inspect bridge   #查看bridge 網絡的詳細信息

149.png

當前 docker0 上沒有任何其餘網絡設備,咱們建立一個容器看看有什麼變化。

一個新的網絡接口 veth28c57df 被掛到了 docker0 上,veth28c57df就是新建立容器的虛擬網卡。

下面看一下容器的網絡配置。

容器有一個網卡 eth0@if34。你們可能會問了,爲何不是veth28c57df 呢?

實際上 eth0@if34 和 veth28c57df 是一對 veth pair。veth pair 是一種成對出現的特殊網絡設備,能夠把它們想象成由一根虛擬網線鏈接起來的一對網卡,網卡的一頭(eth0@if34)在容器中,另外一頭(veth28c57df)掛在網橋 docker0 上,其效果就是將 eth0@if34 也掛在了 docker0 上。

咱們還看到 eth0@if34 已經配置了 IP 172.17.0.2,爲何是這個網段呢?讓咱們經過 docker network inspect bridge 看一下 bridge 網絡的配置信息:

原來 bridge 網絡配置的 subnet 就是 172.17.0.0/16,而且網關是 172.17.0.1。這個網關在哪兒呢?大概你已經猜出來了,就是 docker0。

當前容器網絡拓撲結構如圖所示:

容器建立時,docker 會自動從 172.17.0.0/16 中分配一個 IP,這裏 16 位的掩碼保證有足夠多的 IP 能夠供容器使用。

除了 none, host, bridge 這三個自動建立的網絡,用戶也能夠根據業務須要建立 user-defined 網絡,下一節咱們將詳細討論。

user-defined 網絡

Docker 提供三種 user-defined 網絡驅動:bridge, overlay 和 macvlan。overlay 和 macvlan 用於建立跨主機的網絡,咱們後面有章節單獨討論。

    咱們可經過 bridge 驅動建立相似前面默認的 bridge 網絡,例如:

155.png

    查看一下當前 host 的網絡結構變化:

    新增了一個網橋 br-eaed97dc9a77,這裏 eaed97dc9a77 正好新建 bridge 網絡 my_net 的短 id。執行 docker network inspect 查看一下 my_net 的配置信息:

    這裏 172.18.0.0/16 是 Docker 自動分配的 IP 網段。

    咱們能夠本身指定 IP 網段嗎?
答案是:能夠。

    只需在建立網段時指定 --subnet 和 --gateway 參數:

    這裏咱們建立了新的 bridge 網絡 my_net2,網段爲 172.22.16.0/24,網關爲 172.22.16.1。與前面同樣,網關在 my_net2 對應的網橋 br-5d863e9f78b6 上:

    容器要使用新的網絡,須要在啓動時經過 --network 指定:

    容器分配到的 IP 爲 172.22.16.2。

    到目前爲止,容器的 IP 都是 docker 自動從 subnet 中分配,咱們可否指定一個靜態 IP 呢?

    答案是:能夠,經過--ip指定。

    注:只有使用 --subnet 建立的網絡才能指定靜態 IP

my_net 建立時沒有指定 --subnet,若是指定靜態 IP 報錯以下:

    好了,咱們來看看當前 docker host 的網絡拓撲結構。


經過前面小節的實踐,當前 docker host 的網絡拓撲結構以下圖所示,今天咱們將討論這幾個容器之間的連通性。

163.png

兩個 busybox 容器都掛在 my_net2 上,應該可以互通,咱們驗證一下:

可見同一網絡中的容器、網關之間都是能夠通訊的。

my_net2 與默認 bridge 網絡能通訊嗎?

從拓撲圖可知,兩個網絡屬於不一樣的網橋,應該不能通訊,咱們經過實驗驗證一下,讓 busybox 容器 ping httpd 容器:

確實 ping 不通,符合預期。

「等等!不一樣的網絡若是加上路由應該就能夠通訊了吧?」我已經聽到有讀者在建議了。

這是一個很是很是好的想法。

確實,若是 host 上對每一個網絡的都有一條路由,同時操做系統上打開了 ip forwarding,host 就成了一個路由器,掛接在不一樣網橋上的網絡就可以相互通訊。下面咱們來看看 docker host 滿不知足這些條件呢?

ip r 查看 host 上的路由表:

# ip r

......

172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1

172.22.16.0/24 dev br-5d863e9f78b6  proto kernel  scope link  src 172.22.16.1

......

172.17.0.0/16 和 172.22.16.0/24 兩個網絡的路由都定義好了。再看看 ip forwarding:

# sysctl net.ipv4.ip_forward

net.ipv4.ip_forward = 1

ip forwarding 也已經啓用了。

    條件都知足,爲何不能通行呢?

    咱們還得看看 iptables:

# iptables-save

......

-A DOCKER-ISOLATION -i br-5d863e9f78b6 -o docker0 -j DROP

-A DOCKER-ISOLATION -i docker0 -o br-5d863e9f78b6 -j DROP

......

緣由就在這裏了:iptables DROP 掉了網橋 docker0 與 br-5d863e9f78b6 之間雙向的流量

    從規則的命名 DOCKER-ISOLATION 可知 docker 在設計上就是要隔離不一樣的 netwrok。

    那麼接下來的問題是:怎樣才能讓 busybox 與 httpd 通訊呢?

    答案是:爲 httpd 容器添加一塊 net_my2 的網卡。這個能夠經過docker network connect 命令實現

    咱們在 httpd 容器中查看一下網絡配置:

    容器中增長了一個網卡 eth1,分配了 my_net2 的 IP 172.22.16.3。如今 busybox 應該可以訪問 httpd 了,驗證一下:

busybox 可以 ping 到 httpd,而且能夠訪問 httpd 的 web 服務。當前網絡結構如圖所示:

下一節咱們討論容器間通訊的三種方式

容器之間可經過 IP,Docker DNS Server 或 joined 容器三種方式通訊

 

IP 通訊

 

從上一節的例子能夠得出這樣一個結論:兩個容器要能通訊,必需要有屬於同一個網絡的網卡。

 

知足這個條件後,容器就能夠經過 IP 交互了。具體作法是在容器建立時經過 --network 指定相應的網絡,或者經過 docker network connect 將現有容器加入到指定網絡。可參考上一節 httpd 和 busybox 的例子,這裏再也不贅述。

 

Docker DNS Server

 

經過 IP 訪問容器雖然知足了通訊的需求,但仍是不夠靈活。由於咱們在部署應用以前可能沒法肯定 IP,部署以後再指定要訪問的 IP 會比較麻煩。對於這個問題,能夠經過 docker 自帶的 DNS 服務解決。

 

從 Docker 1.10 版本開始,docker daemon 實現了一個內嵌的 DNS server,使容器能夠直接經過「容器名」通訊。方法很簡單,只要在啓動時用 --name 爲容器命名就能夠了。

 

下面啓動兩個容器 bbox1 和 bbox2:

 

docker run -it --network=my_net2 --name=bbox1 busybox

 

docker run -it --network=my_net2 --name=bbox2 busybox

 

而後,bbox2 就能夠直接 ping 到 bbox1 了:

 

 

    使用 docker DNS 有個限制:只能在 user-defined 網絡中使用。也就是說,默認的 bridge 網絡是沒法使用 DNS 的。下面驗證一下:

 

    建立 bbox3 和 bbox4,均鏈接到 bridge 網絡。

 

docker run -it --name=bbox3 busybox

 

docker run -it --name=bbox4 busybox

 

    bbox4 沒法 ping 到 bbox3。

 

171.png

 

joined 容器

 

joined 容器是另外一種實現容器間通訊的方式。

 

joined 容器很是特別,它可使兩個或多個容器共享一個網絡棧,共享網卡和配置信息,joined 容器之間能夠經過 127.0.0.1 直接通訊。請看下面的例子:

 

    先建立一個 httpd 容器,名字爲 web1。
docker run -d -it --name=web1 httpd 而後建立 busybox 容器並經過 --network=container:web1 指定 jointed 容器爲 web1:

 

 

    請注意 busybox 容器中的網絡配置信息,下面咱們查看一下 web1 的網絡:

 

 

    看!busybox 和 web1 的網卡 mac 地址與 IP 徹底同樣,它們共享了相同的網絡棧。busybox 能夠直接用 127.0.0.1 訪問 web1 的 http 服務。

 

 

joined 容器很是適合如下場景:

 

  1.             不一樣容器中的程序但願經過 loopback 高效快速地通訊,好比 web server 與 app server。        

  2.             但願監控其餘容器的網絡流量,好比運行在獨立容器中的網絡監控程序。        

 

容器之間的通訊咱們已經搞清楚了,接下來要考慮的是容器如何與外部世界通訊?這將是下一節的主題。

相關文章
相關標籤/搜索