管理 Swarm 服務網路

此頁面說明 Swarm 服務的網路功能。

Swarm 和流量類型

Docker Swarm 會產生兩種不同的流量

  • 控制和管理平面流量:這包含 Swarm 管理訊息,例如加入或離開 Swarm 的請求。此流量一律經過加密。

  • 應用程式資料平面流量:這包含容器流量以及與外部用戶端往返的流量。

關鍵網路概念

以下三個網路概念對 Swarm 服務而言非常重要

  • 覆蓋網路管理參與 Swarm 的 Docker Daemon 之間的通訊。您可以建立覆蓋網路,就像為獨立容器建立使用者定義的網路一樣。您也可以將服務附加到一個或多個現有的覆蓋網路,以啟用服務對服務的通訊。覆蓋網路是使用 `overlay` 網路驅動程式的 Docker 網路。

  • Ingress 網路是一種特殊的覆蓋網路,可促進服務節點之間的負載平衡。當任何 Swarm 節點在已發佈的埠上收到請求時,它會將該請求交給名為 `IPVS` 的模組。`IPVS` 會追蹤參與該服務的所有 IP 位址,選擇其中一個,並透過 `ingress` 網路將請求路由到該位址。

    當您初始化或加入 Swarm 時,會自動建立 `ingress` 網路。大多數使用者不需要自訂其設定,但 Docker 允許您這樣做。

  • docker_gwbridge 是一個橋接網路,可將覆蓋網路(包括 `ingress` 網路)連線到個別 Docker Daemon 的實體網路。預設情況下,服務正在執行的每個容器都連線到其本地 Docker Daemon 主機的 `docker_gwbridge` 網路。

    當您初始化或加入 Swarm 時,會自動建立 `docker_gwbridge` 網路。大多數使用者不需要自訂其設定,但 Docker 允許您這樣做。

提示

另請參閱網路概觀,以瞭解更多關於 Swarm 網路的詳細資訊。

防火牆注意事項

參與 Swarm 的 Docker Daemon 需要能夠透過以下埠相互通訊

  • 埠 `7946` TCP/UDP,用於容器網路探索。
  • 埠 `4789` UDP(可設定),用於覆蓋網路(包括 ingress)資料路徑。

在 Swarm 中設定網路時,應特別小心。請參閱教學以取得概觀。

覆蓋網路

當您初始化 Swarm 或將 Docker 主機加入現有 Swarm 時,會在該 Docker 主機上建立兩個新的網路

  • 名為 `ingress` 的覆蓋網路,用於處理與 Swarm 服務相關的控制和資料流量。當您建立 Swarm 服務且未將其連線到使用者定義的覆蓋網路時,它預設會連線到 `ingress` 網路。
  • 名為 `docker_gwbridge` 的橋接網路,可將個別 Docker Daemon 連線到參與 Swarm 的其他 Daemon。

建立覆蓋網路

若要建立覆蓋網路,請在使用 `docker network create` 命令時指定 `overlay` 驅動程式

$ docker network create \
  --driver overlay \
  my-network

上述命令未指定任何自訂選項,因此 Docker 會指派一個子網路並使用預設選項。您可以使用 `docker network inspect` 查看有關網路的資訊。

當沒有容器連線到覆蓋網路時,其設定並不會很複雜

$ docker network inspect my-network
[
    {
        "Name": "my-network",
        "Id": "fsf1dmx3i9q75an49z36jycxd",
        "Created": "0001-01-01T00:00:00Z",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "Containers": null,
        "Options": {
            "com.docker.network.driver.overlay.vxlanid_list": "4097"
        },
        "Labels": null
    }
]

在上述輸出中,請注意驅動程式是 `overlay`,且範圍是 `swarm`,而不是您可能在其他類型的 Docker 網路中看到的 `local`、`host` 或 `global` 範圍。此範圍表示只有參與 Swarm 的主機才能存取此網路。

當服務第一次連線到網路時,網路的子網路和閘道會動態設定。以下範例顯示與上述相同的網路,但連線了三個 `redis` 服務的容器。

$ docker network inspect my-network
[
    {
        "Name": "my-network",
        "Id": "fsf1dmx3i9q75an49z36jycxd",
        "Created": "2017-05-31T18:35:58.877628262Z",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "Containers": {
            "0e08442918814c2275c31321f877a47569ba3447498db10e25d234e47773756d": {
                "Name": "my-redis.1.ka6oo5cfmxbe6mq8qat2djgyj",
                "EndpointID": "950ce63a3ace13fe7ef40724afbdb297a50642b6d47f83a5ca8636d44039e1dd",
                "MacAddress": "02:42:0a:00:00:03",
                "IPv4Address": "10.0.0.3/24",
                "IPv6Address": ""
            },
            "88d55505c2a02632c1e0e42930bcde7e2fa6e3cce074507908dc4b827016b833": {
                "Name": "my-redis.2.s7vlybipal9xlmjfqnt6qwz5e",
                "EndpointID": "dd822cb68bcd4ae172e29c321ced70b731b9994eee5a4ad1d807d9ae80ecc365",
                "MacAddress": "02:42:0a:00:00:05",
                "IPv4Address": "10.0.0.5/24",
                "IPv6Address": ""
            },
            "9ed165407384f1276e5cfb0e065e7914adbf2658794fd861cfb9b991eddca754": {
                "Name": "my-redis.3.hbz3uk3hi5gb61xhxol27hl7d",
                "EndpointID": "f62c686a34c9f4d70a47b869576c37dffe5200732e1dd6609b488581634cf5d2",
                "MacAddress": "02:42:0a:00:00:04",
                "IPv4Address": "10.0.0.4/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.driver.overlay.vxlanid_list": "4097"
        },
        "Labels": {},
        "Peers": [
            {
                "Name": "moby-e57c567e25e2",
                "IP": "192.168.65.2"
            }
        ]
    }
]

自訂覆蓋網路

在某些情況下,您可能不想使用覆蓋網路的預設設定。如需可設定選項的完整清單,請執行命令 `docker network create --help`。以下是一些最常變更的選項。

設定子網路和閘道

預設情況下,當第一個服務連線到網路時,網路的子網路和閘道會自動設定。您可以在建立網路時使用 `--subnet` 和 `--gateway` 旗標來設定這些選項。以下範例透過設定子網路和閘道來擴充先前的範例。

$ docker network create \
  --driver overlay \
  --subnet 10.0.9.0/24 \
  --gateway 10.0.9.99 \
  my-network
使用自訂預設位址池

若要自訂 Swarm 網路的子網路配置,您可以在 `swarm init` 期間選擇性地設定它們

例如,初始化 Swarm 時會使用以下命令

$ docker swarm init --default-addr-pool 10.20.0.0/16 --default-addr-pool-mask-length 26

每當使用者建立網路,但未使用 --subnet 命令列選項時,該網路的子網路將會從池中的下一個可用子網路依序分配。如果指定的網路已被分配,則 Swarm 將不會使用該網路。

如果需要不連續的位址空間,可以設定多個池。然而,不支援從特定池進行分配。網路子網路將會從 IP 池空間依序分配,並且子網路在從已刪除的網路中解除分配時將會被重複使用。

可以設定預設遮罩長度,且所有網路的預設遮罩長度皆相同。預設設定為 /24。要變更預設子網路遮罩長度,請使用 --default-addr-pool-mask-length 命令列選項。

注意事項

預設位址池只能在 swarm init 上設定,且在叢集建立後無法更改。

覆蓋網路大小限制

Docker 建議使用 /24 區塊建立覆蓋網路。/24 覆蓋網路區塊將網路限制為 256 個 IP 位址。

此建議旨在解決 Swarm 模式限制。如果您需要超過 256 個 IP 位址,請勿增加 IP 區塊大小。您可以使用具有外部負載平衡器的 dnsrr 端點模式,或使用多個較小的覆蓋網路。請參閱 設定服務探索 以取得有關不同端點模式的更多資訊。

設定應用程式資料加密

與 Swarm 相關的管理和控制平面資料始終會被加密。有關加密機制的更多詳細資訊,請參閱 Docker Swarm 模式覆蓋網路安全模型

Swarm 節點之間的應用程式資料預設不會加密。若要在指定的覆蓋網路上加密此流量,請在 docker network create 上使用 --opt encrypted 旗標。這將在 vxlan 層級啟用 IPSEC 加密。此加密會造成不可忽視的效能損失,因此您應該在生產環境中使用此選項之前進行測試。

注意事項

您必須 自訂自動建立的入口 以啟用加密。預設情況下,所有入口流量皆未加密,因為加密是網路層級的選項。

將服務附加到覆蓋網路

要將服務附加到現有的覆蓋網路,請將 --network 旗標傳遞給 docker service create,或將 --network-add 旗標傳遞給 docker service update

$ docker service create \
  --replicas 3 \
  --name my-web \
  --network my-network \
  nginx

連線到覆蓋網路的服務容器可以跨網路互相通訊。

要查看服務連線到哪些網路,請使用 docker service ls 尋找服務的名稱,然後使用 docker service ps <服務名稱> 列出網路。或者,要查看哪些服務的容器連線到網路,請使用 docker network inspect <網路名稱>。您可以從任何已加入 Swarm 且處於 running 狀態的 Swarm 節點執行這些命令。

設定服務探索

服務探索是 Docker 用來將服務的外部用戶端請求路由到個別 Swarm 節點的機制,而用戶端不需要知道有多少節點參與服務,或其 IP 位址或埠。您不需要發佈在同一個網路上服務之間使用的埠。例如,如果您有一個 將其資料儲存在 MySQL 服務中的 WordPress 服務,而且它們連線到同一個覆蓋網路,則您不需要將 MySQL 埠發佈到用戶端,只需要發佈 WordPress HTTP 埠。

服務探索可以透過兩種不同的方式運作:使用內建 DNS 和虛擬 IP (VIP) 在第 3 層和第 4 層進行內部連線型負載平衡,或使用 DNS 輪詢 (DNSRR) 在第 7 層進行外部和自訂請求型負載平衡。您可以針對每個服務進行設定。

  • 預設情況下,當您將服務附加到網路且該服務發佈一個或多個埠時,Docker 會為該服務分配一個虛擬 IP (VIP),它是用戶端連線到服務的「前端」。Docker 會保留服務中所有工作節點的清單,並在用戶端和其中一個節點之間路由請求。來自用戶端的每個請求可能會路由到不同的節點。

  • 如果您將服務設定為使用 DNS 輪詢 (DNSRR) 服務探索,則不會有單一虛擬 IP。相反地,Docker 會為服務設定 DNS 項目,以便對服務名稱的 DNS 查詢會傳回 IP 位址清單,並且用戶端會直接連線到其中一個位址。

    當您想要使用自己的負載平衡器(例如 HAProxy)時,DNS 輪詢很有用。要將服務設定為使用 DNSRR,請在建立新服務或更新現有服務時使用旗標 --endpoint-mode dnsrr

自訂 Ingress 網路

大多數使用者從不需要設定 ingress 網路,但 Docker 允許您這樣做。如果自動選擇的子網路與網路上已存在的子網路衝突,或者您需要自訂其他低階網路設定(例如 MTU),或者您想要 啟用加密,這會很有用。

自訂 ingress 網路涉及移除並重新建立它。這通常在您在 Swarm 中建立任何服務之前完成。如果您有發佈埠的現有服務,則需要先移除這些服務,才能移除 ingress 網路。

在沒有 ingress 網路的時間內,未發佈埠的現有服務會繼續運作,但不會進行負載平衡。這會影響發佈埠的服務,例如發佈埠 80 的 WordPress 服務。

  1. 使用 docker network inspect ingress 檢查 ingress 網路,並移除其容器連線到該網路的任何服務。這些是發佈埠的服務,例如發佈埠 80 的 WordPress 服務。如果所有此類服務未停止,則下一步將會失敗。

  2. 移除現有的 ingress 網路

    $ docker network rm ingress
    
    WARNING! Before removing the routing-mesh network, make sure all the nodes
    in your swarm run the same docker engine version. Otherwise, removal may not
    be effective and functionality of newly created ingress networks will be
    impaired.
    Are you sure you want to continue? [y/N]
    
  3. 使用 --ingress 旗標以及您想要設定的自訂選項建立新的覆蓋網路。此範例將 MTU 設定為 1200,將子網路設定為 10.11.0.0/16,並將閘道設定為 10.11.0.2

    $ docker network create \
      --driver overlay \
      --ingress \
      --subnet=10.11.0.0/16 \
      --gateway=10.11.0.2 \
      --opt com.docker.network.driver.mtu=1200 \
      my-ingress
    

    注意事項

    您可以將 ingress 網路命名為 ingress 以外的名稱,但您只能擁有一個。嘗試建立第二個將會失敗。

  4. 重新啟動您在第一步中停止的服務。

自訂 docker_gwbridge

docker_gwbridge 是一個虛擬橋接器,它將覆蓋網路(包含 ingress 網路)連接到個別 Docker daemon 的實體網路。當您初始化一個 swarm 或將 Docker 主機加入 swarm 時,Docker 會自動建立它,但它並不是一個 Docker 裝置。它存在於 Docker 主機的內核中。如果您需要自訂其設定,您必須在將 Docker 主機加入 swarm 之前,或在暫時將主機從 swarm 中移除之後進行。

您需要在您的作業系統上安裝 brctl 應用程式才能刪除現有的橋接器。套件名稱為 bridge-utils

  1. 停止 Docker。

  2. 使用 brctl show docker_gwbridge 指令檢查是否存在名為 docker_gwbridge 的橋接器裝置。如果存在,請使用 brctl delbr docker_gwbridge 將其移除。

  3. 啟動 Docker。不要加入或初始化 swarm。

  4. 使用您的自訂設定建立或重新建立 docker_gwbridge 橋接器。此範例使用子網路 10.11.0.0/16。如需可自訂選項的完整列表,請參閱橋接器驅動程式選項

    $ docker network create \
    --subnet 10.11.0.0/16 \
    --opt com.docker.network.bridge.name=docker_gwbridge \
    --opt com.docker.network.bridge.enable_icc=false \
    --opt com.docker.network.bridge.enable_ip_masquerade=true \
    docker_gwbridge
    
  5. 初始化或加入 swarm。

使用不同的介面來處理控制和資料流量

預設情況下,所有 swarm 流量都會透過同一個介面傳送,包含維護 swarm 本身所需的控制和管理流量,以及往返服務容器的資料流量。

您可以在初始化或加入 swarm 時傳遞 --data-path-addr 旗標來分隔此流量。如果有多個介面,則必須明確指定 --advertise-addr,如果未指定 --data-path-addr,則預設為 --advertise-addr。關於加入、離開和管理 swarm 的流量會透過 --advertise-addr 介面傳送,而服務容器之間的流量會透過 --data-path-addr 介面傳送。這些旗標可以接受 IP 位址或網路裝置名稱,例如 eth0

此範例使用個別的 --data-path-addr 初始化 swarm。它假設您的 Docker 主機具有兩個不同的網路介面:10.0.0.1 應用於控制和管理流量,而 192.168.0.1 應用於與服務相關的流量。

$ docker swarm init --advertise-addr 10.0.0.1 --data-path-addr 192.168.0.1

此範例加入由主機 192.168.99.100:2377 管理的 swarm,並將 --advertise-addr 旗標設定為 eth0,將 --data-path-addr 旗標設定為 eth1

$ docker swarm join \
  --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2d7c \
  --advertise-addr eth0 \
  --data-path-addr eth1 \
  192.168.99.100:2377

在覆蓋網路上發佈埠

連接到同一個覆蓋網路的 Swarm 服務實際上會將所有連接埠互相公開。若要讓連接埠在服務外部可存取,則必須使用 docker service createdocker service update 上的 -p--publish 旗標來*發佈*該連接埠。同時支援舊有的以冒號分隔的語法和較新的以逗號分隔的值語法。較長的語法是首選,因為它具有一定的自我說明性。

旗標值說明
-p 8080:80
-p published=8080,target=80
將服務上的 TCP 連接埠 80 映射到路由網格上的連接埠 8080。
-p 8080:80/udp
-p published=8080,target=80,protocol=udp
將服務上的 UDP 連接埠 80 映射到路由網格上的連接埠 8080。
-p 8080:80/tcp -p 8080:80/udp
-p published=8080,target=80,protocol=tcp -p published=8080,target=80,protocol=udp
將服務上的 TCP 連接埠 80 映射到路由網格上的 TCP 連接埠 8080,并将服務上的 UDP 連接埠 80 映射到路由網格上的 UDP 連接埠 8080。

深入瞭解