【Docker Compose】複数.yml(コンテナ間)ネットワーク設定方法

【Docker Compose】複数.yml(コンテナ間)ネットワーク設定方法

こんばんはエンジニアの眠れない夜です。

Docker Composeを使っていて別のDocker Composeファイル(.ymlファイル) で設定しているコンテナに接続したくなることはありませんか?

例えば、開発する時

データベースはMySQLやPostgreを起動して複数のアプリケーションから参照する。

という使い方をしたくなります。

しかし、

  • データベースのポートがバッティングしてしまったり
  • アプリケーションごとにデータベースのコンテナが必要になったり
  • 別のアプリケーションと接続したくなったり

と… 複数のDocker Composeのコンテナ間でネットワーク接続ができないととても不便です。

こういった問題に直面してしまうのは言うまでもなくDockerのコンテナネットワークに関する知識が不足していることが原因です。

上記のような問題を解決できるようになるために今回は複数のDocker Composeの設定をテーマにコンテナネットワークの使い方を紹介します。

複数のDocker Composeのネットワーク接続

まずは、分かっている方やこの記事を見返してくれている方のためにサクッと必要な部分だけ書いておきます。

※ WordPressとMariaDBを接続する例です。
※ MariaDB が何か 分からない方は MySQL だと思ってもらって大丈夫です。

まずはDockerコマンドでネットワークを作成します。

docker network create my_network

アプリケーション(WordPress)側のDocker Composeファイルに作成したネットワークを追加して、ネットワークの設定で external:true の設定をします。

wordpress/docker-compose.yml

version: '3'
services:
  wordpress:
    container_name: 'wordpress'
    image: wordpress:latest
    ports:
      - 8000:80
    networks:
          - my_network
networks:
  my_network:
    external: true

データベース側にも同じく 作成したネットワークを追加してexternal:trueを設定をします。
mariadb/docker-compose.yml

version: '3'
services:

  mariadb:
   image: mariadb:latest
   container_name: 'mariadb'
   environment:
     MYSQL_USER: 'root'
     MYSQL_ROOT_PASSWORD: 'root'
     MYSQL_DATABASE: 'wordpress'
   ports:
     - 3306:3306
   networks:
     - my_network

networks:
  my_network:
    external: true

設定はこれで終わりです。

2つのDocker Composeにかかれているコンテナ間で接続できるようになりました。

初見の方はナンノコッチャって感じかも知れませんが大丈夫です。この後の説明を読んだ後に読み返してみると至って簡単なことが分かります。

それでは少しずつ掘り下げて解説していきます。

複数Docker Composeのサンプル

再現しやすいようにGitHubにサンプル を公開しました。こちらを使いながら確認すると分かりやすいはずです。

git clone https://github.com/sleepless-se/sample-multi-docker-compose-network-setting.git

ファイル構成はmariadbとwordpressのフォルダの中にDocker Composeのファイルが入っているだけの簡単な構成です。

.
├── README.md
├── mariadb
│   └── docker-compose.yml
└── wordpress
└── docker-compose.yml

まずはDockerコマンドのおさらいですdocker networkと打つとこのようにコマンドの一覧が表示されます。

docker network
Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

docker networkの後に上記のコマンドを続けることでそれぞれのコマンドを実行できます。(変なところで色がついて読みづらくてすみません)

今回使うのはcreate rm ls inspectの4つです。

どれも名前からどういうものか想像できそうですが、一応簡単に説明すると
create でネットワークを作成します。
rm でネットワークを削除します。
ls ネットワークの一覧を表示します。
inspect 特定のネットワークの詳細を確認するために使います。

英語で書いている説明のまんまですね…(^_^;)

それでは一つネットワークを作ってみましょう。

docker network create my_network

ネットワークを作ったら ls コマンドで確認します。

docker network ls

今作成したネットワーク名が確認できます。

NETWORK ID          NAME                  DRIVER              SCOPE
f67acf1dc370        bridge                bridge              local
45c7455345a1        host                  host                local
95defd809e6c        my_network            bridge              local

続いて、作成したネットワークへの接続設定をDocker Composeのファイルに追記します。

アプリケーション側wordpress/docker-compose.ymlとデータベース側mariadb/docker-compose.ymlのファイルです。

portsの設定の後の部分が追加したネットワーク設定です。


   ports:
     - 3306:3306
   networks:
     - my_network
 

このnetworksの設定だけを書いてDocker Composeを起動すると「そんなネットワークありません」とエラーが出ます。

さっき確認した時は確かに作成されていたはずなのになぜ「そんなネットワークがありません」とエラーが出てしまうのか…と悩むところですね(笑)

Docker composeで起動するときはDocker Composeのファイル内にそのネットワークがあるかの確認を行っています。

このエラーを回避するために先ほど作成した「接続したいネットワークはDocker Composeのファイル外にあるものだよ」というの教えてあげる必要があります。

それが後半のNetworksのexternal:trueと言うという設定です。

networks:
  my_network:
    external: true

この設定を追加した後に、mariadbwordpressのディレクトリに移動してdocker-compose up -dで2つのDocker Composeを起動してみましょう。

コンテナを起動したらそれぞれのコンテナから接続ができるかを確認してみましょう。

今回はWordPressのコンテナのボートは8000でホスト側に解放しているので、localhost:8000にアクセスします。

WordPress の画面が開いて言語を選択するとデータベースの接続設定の画面になります。

Docker Composeコンテナ間ネットワーク接続例

ここには

データベース名 wordpress
ユーザー名 root
パスワード root
コンテナのホスト名 mariadb

と入力して次に進むと、データベースに接続できることが確認できます。これでミッションコンプリートです!

データベースとアプリケーション側のファイルが分かれているので、この後アプリケーションが増えても簡単にデータベースに接続ができます。

※ データベースのDocker Composeのファイルに初期のデータベースとしてMYSQL_DATABASE: 'wordpress'を設定していますが、後からデータベースを作成すればこの設定はなくても大丈夫です。

version: '3'
services:

  mariadb:
   image: mariadb:latest
   container_name: 'mariadb'
   environment:
     MYSQL_USER: 'root'
     MYSQL_ROOT_PASSWORD: 'root'
     MYSQL_DATABASE: 'wordpress'

Docker Compose間のネットワーク接続を確認する

念のためもう少し詳しくデータベースとアプリケーションが繋がっているのかをdocker networkで確認してみましょう

docker network inspect my_network

を入力すると色々情報が出てきます。その中でもContainersを見るとそれぞれのコンテナ名NameとIPアドレスIPv4Addressが確認できます。

"Containers": {
            "54e448c9cd885cfdf3423dea12806e1cd1723c116b9a3dbef02f9a74e2cc2421": {
                "Name": "wordpress",
                "EndpointID": "0e27cb058b6b67a019ec096b45874eaeab392a2598cd664ccc5884594ac5cbd8",
                "MacAddress": "02:42:ac:16:00:02",
                "IPv4Address": "172.22.0.2/16",
                "IPv6Address": ""
            },
            "7cbc0881601cf0a7ac8e59098402de067cf0a73583f1116c794ca321b88113ce": {
                "Name": "mariadb",
                "EndpointID": "41789304e003fcfb88316c7af9d224f801fa85fe4b21a7d916c88869f9770aa1",
                "MacAddress": "02:42:ac:16:00:03",
                "IPv4Address": "172.22.0.3/16",
                "IPv6Address": ""
            }
        },

wordpressのIPアドレスは172.22.0.2
mariadbのIPアドレスは172.22.0.3
に接続されていることが確認できます。

Docker Composeはネットワーク名を指定せずに起動するとDocker Composeごとに新しいネットワークが作成されます。

IPアドレスのドットで区切られた区分の内前3つが異なる組み合わせになります。

172.22.0.2
172.22.10.2

異なるネットワークなので当然お互いに接続することはできません…

ネットワークを指定して同じネットワークに参加させることでお互いに接続可能な状態になります。

ちなみに先ほどWordPressの画面からホスト名を指定する時にはmariadbと入力しましたがもちろんIPアドレスで172.22.0.3と入力してもデータベースに接続できます。

しかし、IPアドレスはコンテナがネットワークに参加するタイミングで変わる可能性があるのでホスト名で指定する方が確実です。

ホスト名の設定はDocker Composeのcontainer_nameで変更できます。container_nameを指定しないとmariadb_mariadb_1のような名前になります。見栄えが悪く、使い勝手も悪そうなのでcontainer_nameを指定した方がいいと思います。

container_nameとは別でサービスの後に続く名前を使っても接続できます。

version: '3'
services:
  mariadb:

(↑この部分のmariadbのこと。)

つまり、同じネットワークにコンテナが参加できていれば

  • サービスの後に続く名前
  • コンテナのホスト名
  • コンテナホスト名を指定しなかったときのデフォルトの名前
  • IP アドレス

のどれを使っても接続ができるということです。 割と柔軟に接続ができることに驚きです。

「同じネットワークに接続する」ということがよくわかっていなかった時はコンテナとコンテナをつなぐのに四苦八苦したのが嘘のようです。

コンテナ間で接続ができない時は?

ここまで読んでいただいた方ならもうコンテナ間のネットワーク接続の大枠は理解できたかと思います。

しかし、記事を読んで実際に自分の手元で再現しようとするとうまくいかないというのは世の常ですね(笑)

そういう時に確認して欲しいのは先ほどのdocker Network lsdocker network inspect [NETWORK_NAME]で自分が作成したネットワークにそれぞれのコンテナが参加できているか、IPアドレスのドットで区切られた前3つが部分が同じ値になっているかを確認してください。

他にありそうなパターンは先に作成していたコンテナが邪魔して、ネットワークに設定をして立ち上げたコンテナが起動できていないというパターンでしょうか。

そういう時はdocker psで現在立ち上がっているコンテナのIDを確認して

docker stop [CONTAINER_ID] && docker rm [CONTAINER_ID]

でコンテナを削除してからDocker Composeから起動するとうまくいきます。

最後になりましたが、使い終わったネットワークを削除するのはdocker network rm [NETWORK_NAME]で削除できます。

データベースのクライアントアプリからコンテナ間に接続する場合は?

これまで紹介ししてきたコンテナ間ネットワークとは異なるネットワークなので

   ports:
     - 3306:3306

を使って[HOST_PORT]:[CONTAINER_PORT]でホストとコンテナ間のポートをつなぎます。

今回の場合データベースはホストの3306につながっているのでlocalhost127.0.0.1のポート3306でコンテナに接続できます。

データベース名 wordpress
ユーザー名 root
パスワード root
ホスト名 localhost or 127.0.0.1 
ポート 3306

コンテナ間ネットワーク接続のまとめ

Dockerコンテナ単体で利用する時は--network=[NETWORK]というオプションがあります。

docker run --network=<NETWORK> 

今回の複数のDocker Composeファイルでコンテナ間のネットワーク接続では

  1. ネットワーク設定をDocker Composeにも書いたということと

  2. Docker Composeでは外部のネットワークに接続するときにはexternal:trueの設定が必要

というたったこの2つだけです。

Dockerネットワークの超初歩的なことですが、きちんと理解せずにすっ飛ばしてしまったばかりに複数のDocker Composeでネットワーク設定をするのに私は随分悩みました。つまずいたところや、いまいち理解できなかったDockerのネットワーク設定を簡単にまとめられたかなと思います。

この記事を読んでくださった方はサクッとコンテナ間のネットワーク接続をしてアプリケーションの開発に時間を費やせることを願います。

少し長くなりましたが最後まで読んでいただきありがとうございました。

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください