使用 Swarm 模式路由網格

Docker Engine Swarm 模式可以輕鬆發佈服務的埠,讓 Swarm 外部的資源可以使用這些服務。所有節點都參與入口路由網格。路由網格讓 Swarm 中的每個節點都能夠接受 Swarm 中執行的任何服務的已發佈埠連線,即使節點上沒有執行任何任務。路由網格會將所有傳入已發佈埠的請求路由到可用節點上的作用中容器。

若要在 Swarm 中使用入口網路,您需要在啟用 Swarm 模式之前,在 Swarm 節點之間開啟下列埠

  • 埠 `7946` TCP/UDP,用於容器網路探索。
  • 埠 `4789` UDP(可設定),用於容器入口網路。

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

您也必須在 Swarm 節點與任何需要存取埠的外部資源(例如外部負載平衡器)之間開啟已發佈的埠。

您也可以針對特定服務繞過路由網格

發佈服務的埠

建立服務時,使用 `--publish` 旗標來發佈埠。`target` 用於指定容器內的埠,`published` 用於指定要在路由網格上綁定的埠。如果您省略 `published` 埠,則會為每個服務任務綁定一個隨機的高號埠。您需要檢查任務才能確定埠。

$ docker service create \
  --name <SERVICE-NAME> \
  --publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <IMAGE>

**注意**

這種語法的舊格式是以冒號分隔的字串,其中已發佈的埠在先,目標埠在後,例如 `-p 8080:80`。建議使用新的語法,因為它更容易閱讀,並且允許更大的彈性。

`<已發佈埠>` 是 Swarm 提供服務的埠。如果您省略它,則會綁定一個隨機的高號埠。`<容器埠>` 是容器監聽的埠。此參數是必需的。

例如,下列命令會將 nginx 容器中的埠 80 發佈到 Swarm 中任何節點的埠 8080

$ docker service create \
  --name my-web \
  --publish published=8080,target=80 \
  --replicas 2 \
  nginx

當您存取任何節點上的埠 8080 時,Docker 會將您的請求路由到作用中容器。在 Swarm 節點本身,埠 8080 可能實際上沒有綁定,但路由網格知道如何路由流量,並防止發生任何埠衝突。

路由網格會在已發佈的埠上監聽指派給節點的任何 IP 位址。對於外部可路由的 IP 位址,可以從主機外部使用該埠。對於所有其他 IP 位址,只能從主機內部進行存取。

Service ingress image

您可以使用下列命令發佈現有服務的埠

$ docker service update \
  --publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <SERVICE>

您可以使用 `docker service inspect` 來檢視服務的已發佈埠。例如

$ docker service inspect --format="{{json .Endpoint.Spec.Ports}}" my-web

[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080}]

輸出顯示容器中的 <CONTAINER-PORT>(標記為 TargetPort)以及節點偵聽服務請求的 <PUBLISHED-PORT>(標記為 PublishedPort)。

僅針對 TCP 或僅針對 UDP 發佈埠

預設情況下,發佈埠時,它是一個 TCP 埠。您可以明確地發佈 UDP 埠,以取代或補充 TCP 埠。當您同時發佈 TCP 和 UDP 埠時,如果您省略協定說明符,則該埠將作為 TCP 埠發佈。如果您使用較長的語法(建議),請將 protocol 鍵設定為 tcpudp

僅限 TCP

長語法

$ docker service create --name dns-cache \
  --publish published=53,target=53 \
  dns-cache

短語法

$ docker service create --name dns-cache \
  -p 53:53 \
  dns-cache

TCP 和 UDP

長語法

$ docker service create --name dns-cache \
  --publish published=53,target=53 \
  --publish published=53,target=53,protocol=udp \
  dns-cache

短語法

$ docker service create --name dns-cache \
  -p 53:53 \
  -p 53:53/udp \
  dns-cache

僅限 UDP

長語法

$ docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp \
  dns-cache

短語法

$ docker service create --name dns-cache \
  -p 53:53/udp \
  dns-cache

繞過路由網格

預設情況下,發佈埠的 Swarm 服務會使用路由網格。當您連線到任何 Swarm 節點(無論其是否正在執行特定服務)上的已發佈埠時,您都會被透明地重新導向到正在執行該服務的工作節點。實際上,Docker 充當 Swarm 服務的負載平衡器。

您可以繞過路由網格,以便當您存取特定節點上的繫結埠時,您始終存取在該節點上執行的服務執行個體。這稱為 host 模式。有一些事項需要注意。

  • 如果您存取未執行服務任務的節點,則該服務不會在該埠上進行偵聽。有可能沒有任何程式在偵聽,或者是一個完全不同的應用程式在偵聽。

  • 如果您希望在每個節點上執行多個服務任務(例如,當您有 5 個節點但執行 10 個副本時),則無法指定靜態目標埠。允許 Docker 分配一個隨機的高編號埠(透過省略 published),或者透過使用全域服務而不是複本服務,或使用佈署限制來確保在特定節點上只執行一個服務執行個體。

要繞過路由網格,您必須使用長的 --publish 服務,並將 mode 設定為 host。如果您省略 mode 鍵或將其設定為 ingress,則會使用路由網格。以下命令使用 host 模式建立全域服務並繞過路由網格。

$ docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp,mode=host \
  --mode global \
  dns-cache

設定外部負載平衡器

您可以為 Swarm 服務設定外部負載平衡器,無論是與路由網格結合使用,還是完全不使用路由網格。

使用路由網格

您可以設定外部負載平衡器將請求路由到 Swarm 服務。例如,您可以設定 HAProxy 將請求平衡到發佈到埠 8080 的 nginx 服務。

Ingress with external load balancer image

在這種情況下,埠 8080 必須在負載平衡器和 Swarm 中的節點之間開啟。Swarm 節點可以駐留在代理伺服器可存取的私有網路上,但該網路不能公開存取。

您可以將負載平衡器設定為在 Swarm 中的每個節點之間平衡請求,即使節點上沒有排程任何任務。例如,您可以在 /etc/haproxy/haproxy.cfg 中使用以下 HAProxy 設定

global
        log /dev/log    local0
        log /dev/log    local1 notice
...snip...

# Configure HAProxy to listen on port 80
frontend http_front
   bind *:80
   stats uri /haproxy?stats
   default_backend http_back

# Configure HAProxy to route requests to swarm nodes on port 8080
backend http_back
   balance roundrobin
   server node1 192.168.99.100:8080 check
   server node2 192.168.99.101:8080 check
   server node3 192.168.99.102:8080 check

當您在埠 80 上存取 HAProxy 負載平衡器時,它會將請求轉發到 Swarm 中的節點。Swarm 路由網格會將請求路由到作用中的任務。如果由於任何原因,Swarm 排程器將任務分派到不同的節點,您不需要重新設定負載平衡器。

您可以設定任何類型的負載平衡器,將請求路由到 Swarm 節點。要瞭解更多關於 HAProxy 的資訊,請參閱 HAProxy 文件不使用路由網格

若要在沒有路由網格的情況下使用外部負載平衡器,請將 --endpoint-mode 設定為 dnsrr,而不是預設值 vip。在這種情況下,沒有單一的虛擬 IP。相反,Docker 會為服務設定 DNS 項目,以便對服務名稱的 DNS 查詢會傳回 IP 位址清單,並且用戶端會直接連線到其中一個位址。

您不能將 --endpoint-mode dnsrr--publish mode=ingress 一起使用。您必須在服務前面執行您自己的負載平衡器。在 Docker 主機上對服務名稱進行 DNS 查詢會傳回執行服務的節點的 IP 位址清單。設定您的負載平衡器以使用此清單,並在節點之間平衡流量。請參閱 設定服務探索

深入瞭解