
我有一個小型 VPS,上面有各種服務,例如 WordPress 安裝和一些網頁應用程式。一段時間以來,我將其上的所有服務都作為 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 的這種邊緣情況用法。
(當然,一種解決方案是我將所有容器轉換為服務,但為了避免大爆炸,如果可能的話,我寧願慢慢地進行)。
嘗試可連接網絡
然後我刪除了我的服務並嘗試了以下操作:
docker network rm traefiknet
docker network create driver=overlay --attachable traefiknet
然後我重新創建了 Traefik 服務,它啟動了。它顯然仍在工作,因為它將流量路由到也加入了 traefiknet 覆蓋的服務。
但是,我創建了一個非服務容器,並將其專門連接到traefiknet
和--network-alias
我用它創建的容器無法被服務看到。奇怪的是,如果我將 shell 放入這個非 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 及更高版本支援此功能。
然而,這也沒有幫助。
答案1
我相信我已經解決了這個問題,儘管仍然有一些我不明白的事情。為了設定這個答案的上下文,以下是我現在安裝 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 實例。這樣我將始終從容器連接到服務,而不是相反。
(我無法添加--name
s,因為如果 Docker 主機重新啟動,它將嘗試重新建立具有相同名稱的容器,並且它們將會失敗,因為舊容器仍將具有這些衝突的名稱。而且我無法用來--rm
修復該問題,因為它不相容--restart
!更多相關內容請點這裡)。
我仍然不明白為什麼 Docker 產生的容器名稱無法從 Swarm 容器中執行 ping 操作,也不明白為什麼 a--network-alias
也沒有幫助。但是,考慮到我的解決方案只需要是臨時的,直到我的所有系統都是 Swarm 服務,這可能並不重要。