Networking

如何將 Docker Swarm 服務連接到普通的 Docker 網路?

  • August 26, 2018

我有一個小型 VPS,上面有各種服務,例如 WordPress 安裝和一些 Web 應用程序。一段時間以來,我將其上的所有服務都作為 Docker 容器執行。由於我有各種指向此框的域和子域,我使用前端代理 Traefik 來擷取 Web 埠,然後在 Docker 網路中內部路由它們。

我像這樣啟動 Traefik:

#!/bin/bash

# Removes the restart policy from previous containers
CONTAINER_LABEL=traefik-instance
../../bin/remove-restart.sh $CONTAINER_LABEL

mkdir --parents /var/log/traefik
mkdir --parents /etc/letsencrypt-traefik

docker run \
   --label $CONTAINER_LABEL \
   --publish 80:80 \
   --publish 443:443 \
   --volume $PWD/traefik.toml:/etc/traefik/traefik.toml \
   --volume $PWD/rules:/etc/traefik/rules \
   --volume /etc/letsencrypt-traefik:/etc/letsencrypt-traefik \
   --volume /var/log/traefik:/log \
   --network dockernet \
   --detach \
   --restart always \
   traefik:1.6

這一切都很好。我最近發現了 Docker Swarm,並希望將我所有的容器轉換為服務,這將為我提供複製服務、滾動更新和零停機部署。但是,我想逐步進行更改,以便 Traefik 可以路由到 Swarm 服務和普通(非 Swarm)容器。

因此,為了將 Traefik 作為服務啟動,我現在正在執行以下操作。您會注意到我使用非標準埠進行測試:

#!/bin/bash

# Using "traefik2" while I am experimenting with multiple services
mkdir --parents /var/log/traefik2
mkdir --parents /etc/letsencrypt-traefik

docker service create \
   --publish 8080:80 \
   --publish 8443:443 \
   --mount type=bind,source=$PWD/traefik.toml,target=/etc/traefik/traefik.toml \
   --mount type=bind,source=$PWD/rules,target=/etc/traefik/rules \
   --mount type=bind,source=/etc/letsencrypt-traefik,target=/etc/letsencrypt-traefik \
   --mount type=bind,source=/var/log/traefik2,target=/log \
   --network traefiknet \
   traefik:1.6

當指向出現在同一網路上的 Swarm Web 服務時,這也有效。

所以,我有兩個 Docker 網路(在 Docker 為自己創建的各種預設值中),如下所示:

root@box:~/docker# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
1aa479f13faa        dockernet           bridge              local
k71hpg1n0lo9        traefiknet          overlay             swarm

這導致我有一個可以看到 Docker 容器的工作 Traefik 容器,以及一個可以看到 Swarm 服務的工作 Traefik 服務。然而,他們看不到對方。

為了解決這個問題,我嘗試將 Docker 網路添加到 Traefik Swarm 服務的啟動中:

--network dockernet \

換句話說,我希望此服務同時連接到橋接(舊)和覆蓋(新)網路。不幸的是,我得到了這個:

來自守護程序的錯誤響應:網路 dockernet 不能與服務一起使用。只能使用範圍為 swarm 的網路,例如使用覆蓋驅動程序創建的網路。

有沒有辦法讓我的新服務連接到舊網路,或者確實有辦法讓我的舊容器連接到新網路?我已經嘗試搜尋錯誤,但似乎根本沒有太多提及它;我想知道是否很多人還沒有遇到過 Swarm 的這種邊緣情況使用。

(當然,一種解決方案是讓我將所有容器都轉換為服務,但為了避免大爆炸式的變化,如果可能的話,我寧願慢慢做)。

嘗試可連接的網路

然後我刪除了我的服務並嘗試了這個:

docker network rm traefiknet
docker network create driver=overlay --attachable traefiknet

然後我重新創建了 Traefik 服務,它啟動了。它顯然仍在工作,因為它將流量路由到也加入了 traefiknet 覆蓋的服務。

但是,我創建了一個非服務容器,並將其專門連接到traefiknet,而--network-alias我創建的容器無法被服務看到。奇怪的是,如果我進入這個非 Swarm 容器,它可以ping Swarm Traefik 容器,所以網路可以正常工作。(我嘗試創建一個連接到 的 Alpine shell 服務,traefiknet並且從這裡我無法 ping 非 Swarm 容器的容器名稱,也無法 ping 通它的--network-alias)。

升級 Docker

我曾嘗試將 Docker 從 17.03.2-ce 升級到 18.06.1-ce,因為手冊中的一句話表明我的舊 Docker 版本可能是問題的原因:

容器和 swarm 服務之間的通信使用可附加的覆蓋網路在獨立容器和 swarm 服務之間建立通信。這在 Docker 17.06 及更高版本中受支持。

然而,這也無濟於事。

我相信我對此有解決辦法,儘管仍有一些我不明白的事情。要設置此答案的上下文,以下是我現在安裝 Docker 非 Swarm 容器的方式:

#!/bin/bash

# Save pwd and then change dir to the project root
STARTDIR=`pwd`
cd `dirname $0`/../..

# Removes the restart policy from previous containers
CONTAINER_LABEL=ilovephp-staging
NETWORK_ALIAS=${CONTAINER_LABEL}
./bin/remove-restart.sh $CONTAINER_LABEL

docker run \
   --network swarmnet \
   --network-alias ${NETWORK_ALIAS} \
   --env TUTORIAL_ENVIRONMENT_NAME=staging \
   --detach \
   --restart always \
   ilovephp:2018-08-19

# Go back to original dir
cd $STARTDIR

如您所見,根據我的問題更新,我現在可以將容器放在可附加的 Swarm 網路上。

我發現無法從 Swarm 服務 ping 通的原因是它缺少--name. 只要我添加一個--name,它就可以訪問。有趣的是,如果我嘗試從 Docker 容器 ping Swarm 服務或 Swarm 容器,它會起作用:

root@server:~# docker exec -it loving_allen sh
/ # # *** Ping a specific Swarm container ***
/ # ping alpine-swarm.1.9llv2hvv5xnc1c8diuhfh5m09
PING alpine-swarm.1.9llv2hvv5xnc1c8diuhfh5m09 (10.0.1.23): 56 data bytes
64 bytes from 10.0.1.23: seq=0 ttl=64 time=0.516 ms
^C
--- alpine-swarm.1.9llv2hvv5xnc1c8diuhfh5m09 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.516/0.516/0.516 ms
/ # # *** Ping the Swarm service ***
/ # ping alpine-swarm
PING alpine-swarm (10.0.1.22): 56 data bytes
64 bytes from 10.0.1.22: seq=0 ttl=64 time=0.376 ms
^C
--- alpine-swarm ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.137/0.231/0.376 ms

因此,我最初的計劃是將我的 Traefik 實例從容器轉換為 Swarm 服務,但這行不通,因為無法訪問未命名的非 Swarm 容器。我現在的解決方案是首先將我的所有系統從容器轉換為服務,然後一旦完成,我就可以最後轉換 Traefik 實例。這樣,我將始終從容器連接到服務,而不是相反。

(我無法添加--names ,因為如果 Docker 主機重新啟動,它將嘗試重新創建具有相同名稱的容器,並且它們將失敗,因為舊容器仍然具有那些衝突的名稱。我不能--rm用來解決這個問題,因為它與不兼容--restart更多資訊請點擊此處)。

我仍然不明白為什麼 Docker 生成的容器名稱不能從 Swarm 容器 ping 通,也不明白為什麼 a--network-alias也沒有幫助。但是,鑑於我的解決方案只需要在我的所有系統都是 Swarm 服務之前是臨時的,這可能並不重要。

引用自:https://serverfault.com/questions/928050