Как подключить сервисы Docker Swarm к обычной сети Docker?

Как подключить сервисы Docker Swarm к обычной сети Docker?

У меня есть один небольшой VPS, на котором размещены различные сервисы, такие как установка WordPress и несколько веб-приложений. Некоторое время я запускал все сервисы на нем как контейнеры Docker. Поскольку у меня есть различные домены и поддомены, указывающие на этот ящик, я использую прокси-сервер Traefik для захвата веб-портов и их внутренней маршрутизации в сети 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, которая находится в той же сети.

Итак, у меня есть две сети Docker (среди различных сетей по умолчанию, которые Docker создает для себя), например:

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

В результате у меня есть работающий контейнер Traefik, который видит контейнеры Docker, и работающая служба Traefik, которая видит службы Swarm. Однако они не видят друг друга.

Чтобы попытаться исправить это, я попытался добавить сеть Docker в запуск сервиса Traefik Swarm:

--network dockernet \

Другими словами, я хочу, чтобы эта служба подключалась как к мостовой (старой), так и к оверлейной (новой) сетям. К сожалению, я получаю это:

Ошибка ответа от демона: сеть dockernet не может использоваться со службами. Можно использовать только сети, ограниченные роем, например, созданные с помощью драйвера оверлея.

Есть ли способ, которым мой новый сервис может подключиться к старой сети, или есть ли способ, которым мои старые контейнеры могут подключиться к новой сети? Я пытался искать ошибку, но, похоже, упоминаний о ней совсем немного; интересно, не сталкивались ли еще многие люди с этим пограничным случаем использования Swarm.

(Конечно, одним из решений для меня было бы преобразование всех моих контейнеров в сервисы, но чтобы избежать кардинальных изменений, я бы предпочел делать это медленно, если это возможно).

Попытка подключаемых сетей

Затем я удалил свои службы и попробовал это:

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

Затем я заново создал службу Traefik, и она запустилась. Очевидно, она все еще работает, поскольку направляет трафик в службу, которая также присоединилась к оверлею traefiknet.

Однако я создал не-сервисный контейнер и подключил его исключительно к traefiknet, и то, что --network-aliasя создаю с помощью этого, не может быть видно сервису. Странно, если я зайду в этот не-Swarm-контейнер, онможетпингуйте контейнер Swarm Traefik, чтобы сеть работала. (Я пробовал создать службу оболочки Alpine, подключенную к traefiknet, и отсюда я не могу пинговать ни имя моего контейнера, не относящегося к Swarm, ни его --network-alias).

Обновление Докера

Я попытался обновить Docker с 17.03.2-ce до 18.06.1-ce, потому что фразав руководствеуказало, что моя старая версия Docker может быть причиной проблемы:

Коммуникация между контейнером и службой swarm устанавливает связь между автономным контейнером и службой swarm, используя присоединяемую оверлейную сеть. Это поддерживается в Docker 17.06 и выше.

Однако и это не помогло.

решение1

Я думаю, что у меня есть решение для этого, хотя есть еще некоторые вещи, которые я не понимаю. Чтобы задать контекст для этого ответа, вот как я сейчас устанавливаю Docker non-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, заключается в том, что в нем отсутствует --name. Как только я добавляю --name, он становится доступен. Интересно, однако, что если я пытаюсь пропинговать сервис Swarm или контейнер Swarm из контейнера Docker, это работает:

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, и почему a --network-aliasтоже не помогает. Но, учитывая, что мое решение должно быть временным, пока все мои системы не станут службами Swarm, это, вероятно, не имеет значения.

Связанный контент