Como conectar os serviços Docker Swarm a uma rede Docker comum?

Como conectar os serviços Docker Swarm a uma rede Docker comum?

Eu tenho um único VPS pequeno que possui uma variedade de serviços, como instalação do WordPress e alguns aplicativos da web. Por algum tempo, executei todos os serviços nele como contêineres Docker. Como tenho vários domínios e subdomínios apontando para esta caixa, uso o proxy frontend Traefik para capturar as portas da web e depois roteá-las internamente em uma rede Docker.

Eu inicio o Traefik assim:

#!/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

Tudo isso funciona muito bem. Recentemente descobri o Docker Swarm e gostaria de converter todos os meus contêineres em serviços, o que me proporcionará serviços de replicação, atualizações contínuas e implantações com tempo de inatividade zero. No entanto, eu gostaria de fazer a mudança aos poucos, para que o Traefik possa rotear tanto para serviços Swarm quanto para contêineres comuns (não Swarm).

Então, para lançar o Traefik como um serviço, estou fazendo o seguinte. Você notará que estou usando portas não padrão para fins de teste:

#!/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

Isso também funciona quando apontado para um serviço web Swarm que aparece na mesma rede.

Então, eu tenho duas redes Docker (entre os vários padrões que o Docker cria para si mesmo) assim:

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

Isso resulta em um contêiner Traefik funcional que pode ver contêineres Docker e um serviço Traefik funcional que pode ver serviços Swarm. No entanto, eles não podem se ver.

Para tentar corrigir isso, tentei adicionar a rede Docker na inicialização do serviço Traefik Swarm:

--network dockernet \

Em outras palavras, quero que este serviço se conecte às redes bridge (antiga) e overlay (nova). Infelizmente eu entendo isso:

Resposta de erro do daemon: A rede dockernet não pode ser usada com serviços. Somente redes com escopo definido para o enxame podem ser usadas, como aquelas criadas com o driver de sobreposição.

Existe uma maneira de meu novo serviço se conectar à rede antiga ou, de fato, de meus contêineres antigos se conectarem à nova rede? Tentei procurar o erro, mas não parece haver muitas menções a ele; Eu me pergunto se esse uso extremo do Swarm ainda não foi encontrado por muitas pessoas.

(Claro, uma solução é converter todos os meus contêineres em serviços, mas para evitar uma mudança radical, prefiro fazê-lo lentamente, se possível).

Experimentando redes conectáveis

Em seguida, excluí meus serviços e tentei o seguinte:

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

Em seguida, recriei o serviço Traefik e ele foi inicializado. Evidentemente, ainda está funcionando porque roteia o tráfego para um serviço que também aderiu à sobreposição traefiknet.

No entanto, criei um contêiner que não é de serviço e o conectei exclusivamente ao traefiknet, e o --network-aliasque crio com ele não pode ser visto pelo serviço. Estranhamente, se eu entrar neste contêiner que não é do Swarm,podeexecute ping no contêiner Swarm Traefik, para que a rede funcione. (Tentei criar um serviço de shell Alpine, conectado a traefiknete, a partir daqui, não consigo executar ping no nome do contêiner que não é do Swarm, nem no seu --network-alias).

Atualizando o Docker

Tentei atualizar o Docker de 17.03.2-ce para 18.06.1-ce, porque uma fraseno manualindicou que minha versão antiga do Docker pode ser a causa do problema:

A comunicação entre um contêiner e um serviço de enxame configura a comunicação entre um contêiner independente e um serviço de enxame, usando uma rede de sobreposição anexável. Isso é compatível com Docker 17.06 e superior.

No entanto, isso também não ajudou.

Responder1

Acredito que tenho uma solução para isso, embora ainda haja algumas coisas que não entendo. Para definir o contexto para esta resposta, veja a seguir como instalo um contêiner Docker não 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

Como você pode ver, de acordo com a atualização da minha pergunta, agora posso colocar um contêiner em uma rede Swarm anexável.

Eu descobri que a razão pela qual isso não pode ser executado em um serviço Swarm é que está faltando um arquivo --name. Assim que eu adicionar um --name, ele estará acessível. Curiosamente, se eu tentar executar ping no serviço Swarm ou no contêiner Swarm do contêiner Docker, ele funciona:

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

Portanto, meu plano original era converter minha instância do Traefik de um contêiner para um serviço Swarm, mas isso não funcionará, porque contêineres sem nome que não sejam do Swarm não estarão acessíveis. Minha solução agora é primeiro converter todos os meus sistemas de contêineres em serviços e, depois que tudo estiver feito, posso converter a instância do Traefik por último. Dessa forma estarei sempre conectando do container ao serviço, e não o contrário.

(Não posso adicionar --names, pois se o host Docker for reiniciado, ele tentará recriar contêineres com o mesmo nome, e eles falharão porque os contêineres antigos ainda terão esses nomes conflitantes. E não posso usar --rmpara corrigir isso, porque não é compatível com --restart!Mais sobre isso aqui).

Ainda não entendo por que um nome de contêiner gerado pelo Docker não pode ser pingado de um contêiner Swarm, nem por que a --network-aliastambém não ajuda. Mas, dado que minha solução só precisa ser temporária até que todos os meus sistemas sejam serviços Swarm, provavelmente isso não importa.

informação relacionada