4. Docker 網絡模式-bridge

概述

Docker 強大的原因之一在於多個 Docker 容器之間的互相連接。涉及到連接,就引出了網絡通信的幾種模式。Docker 默認提供了 5 種網絡驅動模式。

  • bridge: 默認的網絡驅動模式。如果不指定驅動程序,bridge 便會作爲默認的網絡驅動模式。當應用程序運行在需要通信的獨立容器(standalone containers)中時,通常會選擇 bridge 模式。
  • host:移除容器和 Docker 宿主機之間的網絡隔離,並直接使用主機的網絡。host 模式僅適用於 Docker 17.06+。
  • overlay:overlay 網絡將多個 Docker 守護進程連接在一起,並使集羣服務能夠相互通信。您還可以使用 overlay 網絡來實現 swarm 集羣和獨立容器之間的通信,或者不同 Docker 守護進程上的兩個獨立容器之間的通信。該策略實現了在這些容器之間進行操作系統級別路由的需求。
  • macvlan:Macvlan 網絡允許爲容器分配 MAC 地址,使其顯示爲網絡上的物理設備。 Docker 守護進程通過其 MAC 地址將流量路由到容器。對於希望直連到物理網絡的傳統應用程序而言,使用 macvlan 模式一般是最佳選擇,而不應該通過 Docker 宿主機的網絡進行路由。
  • none:對於此容器,禁用所有聯網。通常與自定義網絡驅動程序一起使用。none 模式不適用於集羣服務。

通過在 Docker 上安裝和使用第三方網絡插件可以算作額外的擴展方式。

默認網絡

kiritodeMacBook-Pro:~ kirito$ docker network ls
NETWORK ID          NAME                         DRIVER              SCOPE
15315759c263        bridge                       bridge              local
d72064d9febf        host                         host                local
83ea989d3fec        none                         null                local

這 3 個網絡包含在 Docker 實現中。運行一個容器時,可以使用 –network 參數指定在哪種網絡模式下運行該容器。

這篇文章重點介紹 bridge 模式。 所有 Docker 安裝後都存在的 docker0 網絡,這在 Docker 基礎中有過介紹。除非使用 **docker run –network=**選項另行指定,否則 Docker 守護進程默認情況下會將容器連接到 docker0 這個網絡。

創建自定義的網絡

使用如下命令就可以創建一個名稱爲 my-net ,網絡驅動模式爲 bridge 的自定義網絡。

$ docker network create my-net

再次查看存在的網絡可以發現上述命令執行之後產生的變化:

kiritodeMacBook-Pro:~ kirito$ docker network ls
NETWORK ID          NAME                         DRIVER              SCOPE
15315759c263        bridge                       bridge              local
d72064d9febf        host                         host                local
73e32007f19f        my-net                       bridge              local
83ea989d3fec        none                         null                local

使用 busybox 測試容器連通性

BusyBox 是一個集成了一百多個最常用 Linux 命令和工具(如 cat、echo、grep、mount、telnet 、ping、ifconfig 等)的精簡工具箱,它只需要幾 MB 的大小,很方便進行各種快速驗證,被譽爲“Linux 系統的瑞士軍刀”。

我們使用 busybox 來測試容器間的網絡情況。(一開始我嘗試使用 ubuntu 作爲基礎鏡像來構建測試容器,但 ubuntu 鏡像刪減了幾乎所有的常用工具,連同 ping,ifconfig 等命令都需要額外安裝軟件,而 busybox 則不存在這些問題。)

使用默認網橋 docker0

kiritodeMacBook-Pro:~ kirito$ docker run --name box1 -it --rm busybox sh
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:07
          inet addr:172.17.0.7  Bcast:172.17.255.255  Mask:255.255.0.0

—rm 指令可以讓我們在退出容器時自動銷燬該容器,這樣便於測試。查看自身的 ip 爲 172.17.0.7,接下來創建第二個容器 box2。

kiritodeMacBook-Pro:~ kirito$ docker run --name box2 -it --rm busybox sh
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:08
          inet addr:172.17.0.8  Bcast:172.17.255.255  Mask:255.255.0.0

查看自身的 ip 爲 172.17.0.8。

在 box2 中執行 ping 命令測試與 box1 的連通性:

使用 IP
/ # ping 172.17.0.8
PING 172.17.0.8 (172.17.0.8): 56 data bytes
64 bytes from 172.17.0.8: seq=0 ttl=64 time=0.107 ms
64 bytes from 172.17.0.8: seq=1 ttl=64 time=0.116 ms
64 bytes from 172.17.0.8: seq=2 ttl=64 time=0.114 ms
64 bytes from 172.17.0.8: seq=3 ttl=64 time=0.126 ms

使用容器名稱
/ # ping box1
無響應

我們發現使用默認網橋 docker0 的橋接模式下,ip 是通的,但是無法使用容器名作爲通信的 host。

使用自定義網橋 my-net

kiritodeMacBook-Pro:~ kirito$ docker run --name box3 -it --rm  --network my-net busybox sh
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:15:00:02
          inet addr:172.21.0.2  Bcast:172.21.255.255  Mask:255.255.0.0

使用 —network 指定使用的網絡模式,my-net 便是在此之前我們通過 docker network create 命令新創建的網絡。新啓動一個 shell 創建 box4

kiritodeMacBook-Pro:~ kirito$ docker run -it --name box4 --rm --network my-net busybox sh
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:15:00:03
          inet addr:172.21.0.3  Bcast:172.21.255.255  Mask:255.255.0.0

在 box4 中執行 ping 命令測試與 box3 的連通性:

使用 IP
/ # ping 172.21.0.2
PING 172.21.0.2 (172.21.0.2): 56 data bytes
64 bytes from 172.21.0.2: seq=0 ttl=64 time=0.203 ms
64 bytes from 172.21.0.2: seq=1 ttl=64 time=0.167 ms
64 bytes from 172.21.0.2: seq=2 ttl=64 time=0.169 ms
64 bytes from 172.21.0.2: seq=3 ttl=64 time=0.167 ms

使用容器名稱
/ # ping box3
PING box3 (172.21.0.2): 56 data bytes
64 bytes from 172.21.0.2: seq=0 ttl=64 time=0.229 ms
64 bytes from 172.21.0.2: seq=1 ttl=64 time=0.170 ms
64 bytes from 172.21.0.2: seq=2 ttl=64 time=0.165 ms
64 bytes from 172.21.0.2: seq=3 ttl=64 time=0.168 ms

與默認的網絡 docker0 不同的是,指定了自定義 network 的容器可以使用容器名稱相互通信,實際上這也是 docker 官方推薦使用 —network 參數運行容器的原因之一。

對比自定義 bridge(my-net)與默認 bridge(docker0)

自定義 bridge 提供更好的隔離性和容器間的互操作性

連接到同一個自定義 bridge 網絡的容器會自動將所有端口相互暴露,並且無法連接到容器之外的網絡。這使得容器化的應用能輕鬆地相互通信,並且與外部環境產生了良好的隔離性。

例如一個包含了 web 應用,數據庫,redis 等組件的應用程序。很有可能只希望對外界暴露 80 端口,而不允許外界訪問數據庫端口和 redis 端口,而又不至於讓 web 應用本身無法訪問數據庫和 redis, 便可以使用自定義 bridge 網絡輕鬆實現。如果在默認 bridge 網絡上運行相同的應用程序,則需要使用 -p 或 —publish 標誌打開 web 端口,數據庫端口,redis 端口。這意味着 Docker 宿主機需要通過其他方式阻止對數據庫端口,redis 端口的訪問,無意增大了工作量。

自定義 bridge 提供容器間的自動 DNS 解析

這一點在上一節的實驗中已經驗證過了。默認 bridge 網絡上的容器只能通過 IP 地址互相訪問,除非使用在 docker run 時添加 —link 參數。這麼做個人認爲有兩點不好的地方:

  1. 容器關係只要稍微複雜一些,便會對管理產生不便。

  2. —link 參數在官方文檔中已經被標記爲過期的參數,不被建議使用。

在用戶定義的橋接網絡上,容器可以通過容器名稱(--name 指定的名稱)或別名來解析對方。可能有人說,在默認 bridge 模式下我可以去修改 /etc/hosts文件呀,但這顯然不是合理的做法。

容器可以在運行中與自定義 bridge 網絡連接和分離

在容器的生命週期中,可以在運行中將其與自定義網絡連接或斷開連接。 而要從默認 bridge 網絡中移除容器,則需要停止容器並使用不同的網絡選項重新創建容器。

每個自定義的 bridge 網絡都會創建一個可配置的網橋

如果容器使用默認 bridge 網絡,雖然可以對其進行配置,但所有容器都使用相同的默認設置,例如 MTU 和防火牆規則。另外,配置默認 bridge 網絡隔離於 Docker 本身之外,並且需要重新啓動 Docker 纔可以生效。

自定義的 bridge 是使用 docker network create 創建和配置的。如果不同的應用程序組具有不同的網絡要求,則可以在創建時分別配置每個用戶定義的 bridge 網絡,這無疑增加了靈活性和可控性。

使用默認 bridge 容器共享所有的環境變量

在 Docker 的舊版本中,兩個容器之間共享環境變量的唯一方法是使用 —link 標誌來進行鏈接。這種類型的變量共享對於自定義的網絡是不存在的。但是,自定義網絡有更好方式來實現共享環境變量:

  • 多個容器可以使用 Docker 捲來掛載包含共享信息的文件或目錄。
  • 多個容器可以使用 docker-compose 一起啓動,並且 docker-compose.yml 文件可以定義共享變量。
  • 使用集羣服務而不是獨立容器,並利用共享密鑰和配置。

結合上述這些論述和官方文檔的建議,使用 bridge 網絡驅動模式時,最好添加使用 —network 來指定自定義的網絡。


原文鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章