Docker Swarm サービスを通常の Docker ネットワークに接続するにはどうすればよいですか?

Docker Swarm サービスを通常の Docker ネットワークに接続するにはどうすればよいですか?

私は WordPress のインストールやいくつかの Web アプリなど、さまざまなサービスを備えた単一の小さな VPS を持っています。しばらくの間、私はすべてのサービスを 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 サービスを指す場合にも機能します。

つまり、次のような 2 つの 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 サービスができました。ただし、それらはお互いを参照できません。

これを修正するために、Traefik Swarm サービスの起動に Docker ネットワークを追加してみました。

--network dockernet \

つまり、このサービスをブリッジ (古い) ネットワークとオーバーレイ (新しい) ネットワークの両方に接続したいのですが、残念ながら次のようになります。

デーモンからのエラー応答: ネットワーク dockernet はサービスでは使用できません。オーバーレイ ドライバーで作成されたものなど、スウォームにスコープされたネットワークのみを使用できます。

新しいサービスを古いネットワークに接続する方法はありますか、または古いコンテナを新しいネットワークに接続する方法はあるのでしょうか? エラーを検索してみましたが、それについてはほとんど言及されていないようです。Swarm のこのエッジケースの使用法にまだ多くの人が遭遇していないのではないかと思います。

(もちろん、すべてのコンテナをサービスに変換するという解決策もありますが、大規模な変更を避けるため、可能であればゆっくりと実行したいと思います)。

接続可能なネットワークを試す

その後、サービスを削除して、次のことを試しました:

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

その後、Traefik サービスを再作成し、起動しました。traefiknet オーバーレイに参加しているサービスにトラフィックをルーティングしているため、まだ動作しているようです。

しかし、私は非サービスコンテナを作成し、それを排他的に に接続しましたtraefiknetが、--network-aliasそれを使用して作成した はサービスからは見えません。奇妙なことに、この非Swarmコンテナにシェルすると、できるSwarm Traefik コンテナに ping を実行すると、ネットワークが機能します。( に接続された Alpine シェル サービスを作成しようとしましたtraefiknetが、ここからは、非 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 コンテナーから Swarm サービスまたは Swarm コンテナーを ping しようとすると、正常に動作します。

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 インスタンスを変換することです。こうすることで、常にコンテナーからサービスに接続し、その逆は起こりません。

( --nameDocker ホストが再起動されると、同じ名前でコンテナーを再作成しようとするため、 を追加できません。古いコンテナーには競合する名前が残っているため、再作成は失敗します。また、--rmは と互換性がないため、 を使用してこれを修正することもできません--restart。)詳細はこちら)。

Docker で生成されたコンテナ名が Swarm コンテナから ping できない理由も、また が役に立たない理由もまだわかりません--network-alias。ただし、すべてのシステムが Swarm サービスになるまでは私のソリューションは一時的なものである必要があるだけなので、おそらく問題にはなりません。

関連情報