我有一个小型 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 容器的方式:
如您所见,根据我的问题更新,我现在可以将容器放在可附加的 Swarm 网络上。
我发现无法从 Swarm 服务 ping 通的原因是它缺少
--name
. 只要我添加一个--name
,它就可以访问。有趣的是,如果我尝试从 Docker 容器 ping Swarm 服务或 Swarm 容器,它会起作用:因此,我最初的计划是将我的 Traefik 实例从容器转换为 Swarm 服务,但这行不通,因为无法访问未命名的非 Swarm 容器。我现在的解决方案是首先将我的所有系统从容器转换为服务,然后一旦完成,我就可以最后转换 Traefik 实例。这样,我将始终从容器连接到服务,而不是相反。
(我无法添加
--name
s ,因为如果 Docker 主机重新启动,它将尝试重新创建具有相同名称的容器,并且它们将失败,因为旧容器仍然具有那些冲突的名称。我不能--rm
用来解决这个问题,因为它与不兼容--restart
!更多信息请点击此处)。我仍然不明白为什么 Docker 生成的容器名称不能从 Swarm 容器 ping 通,也不明白为什么 a
--network-alias
也没有帮助。但是,鉴于我的解决方案只需要在我的所有系统都是 Swarm 服务之前是临时的,这可能并不重要。