使用 Swarm 模式路由網格
Docker Engine Swarm 模式可輕鬆發布服務連接埠,使其能供 Swarm 叢集外部的資源存取。所有節點都會參與 Ingress 路由網格。路由網格使 Swarm 中的每個節點都能接收發布連接埠的連線(針對 Swarm 中執行的任何服務),即使該節點上並未執行任何任務(Task)亦然。路由網格會將所有發布連接埠的連入請求路由至可用節點上的活動容器。
若要在 Swarm 中使用 Ingress 網路,在啟用 Swarm 模式之前,您需要在 Swarm 節點之間開放以下連接埠:
- 連接埠
7946(TCP/UDP):用於容器網路探索。 - 連接埠
4789(UDP):用於容器 Ingress 網路(可配置)。
在 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 位址,存取僅限於主機內部。

您可以使用以下指令為現有服務發布連接埠:
$ 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 鍵設為 tcp 或 udp。
僅 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 服務的請求。

在此情況下,負載平衡器與 Swarm 節點之間的 8080 連接埠必須開放。Swarm 節點可以位於 Proxy 伺服器可存取的私有網路上,但該網路不必公開可存取。
您可以配置負載平衡器以在 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 位址列表。請配置您的負載平衡器以使用此列表,並在節點之間平衡流量。請參閱配置服務探索。