使用 Swarm 模式路由網格

Docker Engine Swarm 模式可以輕鬆地為服務釋出埠,使其可用於 Swarm 外部的資源。所有節點都參與一個入口路由網格(ingress routing mesh)。路由網格使 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。新語法更受青睞,因為它更易於閱讀並允許更大的靈活性。

<PUBLISHED-PORT> 是 Swarm 提供服務可用的埠。如果省略它,將繫結一個隨機的高位埠。<CONTAINER-PORT> 是容器監聽的埠。此引數是必需的。

例如,以下命令將 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

在這種情況下,負載均衡器和 Swarm 中的節點之間必須開放 8080 埠。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 地址列表。配置您的負載均衡器以使用此列表並在這些節點之間平衡流量。請參閱配置服務發現

瞭解更多