web-dev-qa-db-ja.com

再起動しても壊れないように、Dockerコンテナ間のリンクを設定するにはどうすればよいですか?

次のように実行されているDockerコンテナーがいくつかあります。

  • Nginx
  • Webアプリ1
  • Webアプリ2
  • PostgreSQL

NginxはWebアプリ1および2内のWebアプリケーションサーバーに接続する必要があり、WebアプリはPostgreSQLと通信する必要があるため、次のようなリンクがあります。

  • Nginx ---リンク---> Webアプリ1
  • Nginx ---リンク---> Webアプリ2
  • Webアプリ1 ---リンク---> PostgreSQL
  • Webアプリ2 ---リンク---> PostgreSQL

これは最初はかなりうまくいきます。ただし、Webアプリ1とWebアプリ2の新しいバージョンを開発するときは、それらを置き換える必要があります。私がしていることは、Webアプリコンテナを削除し、新しいコンテナをセットアップして起動することです。

Webアプリコンテナーの場合、最初のIPアドレスは次のようになります。

  • 172.17.0.2
  • 172.17.0.3

そして、それらを交換すると、新しいIPアドレスが追加されます。

  • 172.17.0.5
  • 172.17.0.6

現在、Nginxコンテナで公開されている環境変数は、まだ古いIPアドレスを指し示しています。ここに問題があります。コンテナ間のリンクを壊さずにコンテナを交換するにはどうすればよいですか?同じ問題がPostgreSQLでも発生します。 PostgreSQLイメージバージョンをアップグレードする場合は、必ず削除して新しいバージョンを実行する必要がありますが、コンテナーグラフ全体を再構築する必要があるため、これは実際のサーバー操作には理想的ではありません。

80
Fang-Pen Lin

--linkの効果は静的であるため、シナリオでは機能しません(現在、再リンクはありませんが、 リンクの削除 が可能です)。

Dockerize.itで2つの異なるアプローチを使用して、リンクまたはアンバサダーなしでこれを解決しています(ただし、アンバサダーを追加することもできます)。

1)ダイナミックDNSを使用

一般的な考え方は、データベース(またはその他のサービス)に単一の名前を指定し、コンテナを開始および停止するときに、短命のDNSサーバーを実際のIPで更新することです。

SkyDock から始めました。 DNSサーバーと、自動的に更新されるモニターの2つのdockerコンテナーで動作します。後で、 Consul を使用してよりカスタムなものに移動しました(また、dockerizedバージョンを使用: docker-consul )。

これを進化させたのは(まだ試していませんが)etcdなどをセットアップし、そのカスタムAPIを使用してIPとポートを学習することです。ソフトウェアは動的再構成もサポートする必要があります。

2)docker bridge ipを使用します

コンテナポートを公開するときは、よく知られたアドレスを持つ(または持つことができる)docker0ブリッジにそれらをバインドするだけです。

コンテナを新しいバージョンに置き換える場合、新しいコンテナが同じIPで同じポートを公開するようにします。

これは簡単ですが、より制限されています。同様のソフトウェア(たとえば、2つのコンテナがdocker0ブリッジの3306ポートでリッスンできない)などを実行すると、ポートの競合が発生する可能性があります。したがって、現在のお気に入りはオプション1です。

53
Abel Muiño

リンクは特定のコンテナ用であり、コンテナの名前に基づいていません。したがって、コンテナを削除すると、リンクは切断され、新しいコンテナは(同じ名前であっても)自動的に置き換わりません。

新しいネットワーク機能を使用すると、名前でコンテナに接続できるため、新しいネットワークを作成すると、そのネットワークに接続されているコンテナは名前で他のコンテナにアクセスできます。例:

1)新しいネットワークを作成する

$ docker network create <network-name>       

2)コンテナをネットワークに接続します

$ docker run --net=<network-name> ...

または

$ docker network connect <network-name> <container-name>

3)名前によるコンテナのping

docker exec -ti <container-name-A> ping <container-name-B> 

64 bytes from c1 (172.18.0.4): icmp_seq=1 ttl=64 time=0.137 ms
64 bytes from c1 (172.18.0.4): icmp_seq=2 ttl=64 time=0.073 ms
64 bytes from c1 (172.18.0.4): icmp_seq=3 ttl=64 time=0.074 ms
64 bytes from c1 (172.18.0.4): icmp_seq=4 ttl=64 time=0.074 ms

ドキュメントの this セクションを参照してください。

注:レガシーlinksとは異なり、新しいネットワークはそうではありません環境変数を作成し、環境変数を他のコンテナと共有しません。

現在、この機能はエイリアスをサポートしていません

20
Hemerson Varela

ambassador container を使用できます。ただし、上記と同じ問題が発生するため、アンバサダーコンテナをクライアントにリンクしないでください。代わりに、Dockerホストのアンバサダーコンテナの公開ポート(通常は172.17.42.1)を使用します。例:

postgresボリューム:

$ docker run --name PGDATA -v /data/pgdata/data:/data -v /data/pgdata/log:/var/log/postgresql phusion/baseimage:0.9.10 true

postgresコンテナー:

$ docker run -d --name postgres --volumes-from PGDATA -e USER=postgres -e PASS='postgres' paintedfox/postgresql

postgresの大使コンテナ:

$ docker run -d --name pg_ambassador --link postgres:postgres -p 5432:5432 ctlc/ambassador

これで、アンバサダーコンテナをリンクせずにpostgresqlクライアントコンテナを起動し、ゲートウェイホスト(通常は172.17.42.1)でpostgresqlにアクセスできます。

$ docker run --rm -t -i paintedfox/postgresql /bin/bash
root@b94251eac8be:/# PGHOST=$(netstat -nr | grep '^0\.0\.0\.0 ' | awk '{print $2}')
root@b94251eac8be:/# echo $PGHOST
172.17.42.1
root@b94251eac8be:/#
root@b94251eac8be:/# psql -h $PGHOST --user postgres
Password for user postgres: 
psql (9.3.4)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

postgres=#
postgres=# select 6*7 as answer;
 answer 
--------
     42
(1 row)

bpostgres=# 

これで、クライアントを再起動せずに、アンバサダーコンテナを再起動できます。

10
Swen Thümmler

これは3週間前のdockerの実験的ビルドに含まれており、サービスが導入されています。 https://github.com/docker/docker/blob/master/experimental/networking.md

Dockerコンテナを--publish-service <name>引数。この名前はDNS経由でアクセスできます。これは、コンテナの再起動時に持続します(もちろん、同じサービス名でコンテナを再起動する限り)

2

まだ興味があれば、各dockerコンテナの/ etc/hostsファイルのHostエントリを使用する必要があります。ENV変数は自動的に更新されないため、ENV変数に依存しないでください。

リンクされたコンテナごとに、LINKEDCONTAINERNAME_PORT_PORTNUMBER_TCPなどの形式でホストファイルエントリがあります。

以下はdockerからのものです docs

Docker環境変数に関する重要な注意事項

/ etc/hostsファイルのホストエントリとは異なり、環境変数に保存されているIPアドレスは、ソースコンテナが再起動されても自動的に更新されません。/etc/hostsのホストエントリを使用して、リンクされたコンテナのIPアドレスを解決することをお勧めします。

これらの環境変数は、コンテナ内の最初のプロセスに対してのみ設定されます。 sshdなどの一部のデーモンは、接続用のシェルを生成するときにそれらをスクラブします。

2
frameworksnow

また、リンクをそのまま保持するために中間コンテナを使用するアンバサダーメソッドを試すこともできます...(詳細は https://docs.docker.com/articles/ambassador_pattern_linking/ を参照)

1
Gekkie

openSVCアプローチでは、次の方法で回避できます。

  • 独自のIPアドレス/ DNS名(エンドユーザーが接続するもの)でサービスを使用する
  • この特定のIPアドレスにポートを公開するようにdockerに指示します(「--ip」dockerオプション)
  • サービスIPアドレスに接続するようにアプリを構成します

コンテナを交換するたびに、確実に正しいIPアドレスに接続します。

チュートリアルはこちら=> OpenSVCを使用したDocker Multi Containers

tutoの最後にある「複雑なオーケストレーション」の部分をお見逃しなく。これは、コンテナを正しい順序で開始/停止するのに役立ちます(postgresqlサブセット1つ+ webappサブセット1つ+ nginxサブセット1つ)

主な欠点は、webappおよびPostgreSQLポートをパブリックアドレスに公開することです。実際には、パブリックで公開する必要があるのはnginx tcpポートのみです。

1
user3757286

これを解決するには、名前に dockerlinks を使用できます。

最も基本的なセットアップは、最初にnamedデータベースコンテナを作成することです:

$ Sudo docker run -d --name db training/postgres

次に、dbに接続するWebコンテナを作成します。

$ Sudo docker run -d -P --name web --link db:db training/webapp python app.py

これにより、コンテナをIPアドレスと手動で接続する必要がなくなります。

1
Pak

イメージの接続ポートをホストの固定ポートにバインドし、代わりにそれらを使用するようにサービスを構成できます。

これには欠点もありますが、あなたの場合にはうまくいくかもしれません。

0
ivant

ネットワークスコープのエイリアス は、この場合に必要なものです。これはかなり新しい機能です。1つのコンテナからのみアクセス可能なリンクエイリアスとは異なり、ネットワーク全体にサービスを提供するコンテナを「公開」するために使用できます。

コンテナ間にいかなる種類の依存関係も追加しません。再起動、交換、起動順序に関係なく、両方が実行されている限り通信できます。/etc/hostsではなく、内部的にDNSを使用していると思います

docker run --net=some_user_definied_nw --net-alias postgres ...のように使用すると、同じネットワーク上の任意のコンテナからそのエイリアスを使用して接続できます。

デフォルトのネットワークでは動作しません。残念ながら、すべてのコンテナに対してdocker network create <network>で作成し、--net=<network>で使用する必要があります( composeサポートも同様 )。

コンテナがダウンしているためエイリアスが到達できないことに加えて、複数のコンテナはエイリアスを共有することもできます。この場合、正しいコンテナに解決されることは保証されません。しかし、場合によってはシームレスなアップグレードに役立つ可能性があります。

現時点ではまだ十分に文書化されておらず、manページを読むだけでは理解するのが困難です。

0
Ivan Anishchuk

別の方法は、--net container:$CONTAINER_IDオプションを使用することです。

ステップ1:「ネットワーク」コンテナを作成する

docker run --name db_net ubuntu:14.04 sleep infinity
docker run --name app1_net --link db_net:db ubuntu:14.04 sleep infinity
docker run --name app2_net --link db_net:db ubuntu:14.04 sleep infinity
docker run -p 80 -p 443 --name nginx_net --link app1_net:app1 --link app2_net:app2 ubuntu:14.04 sleep infinity

ステップ2:サービスを「ネットワーク」コンテナに注入する

docker run --name db --net container:db_net pgsql
docker run --name app1 --net container:app1_net app1
docker run --name app2 --net container:app1_net app2
docker run --name nginx --net container:app1_net nginx

「ネットワーク」コンテナに触れない限り、リンクのIPアドレスは変更されません。

0
user1202136