こんばんはエンジニアの眠れない夜です。
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 の設定をします。
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
この設定を追加した後に、mariadb
とwordpress
のディレクトリに移動してdocker-compose up -d
で2つのDocker Composeを起動してみましょう。
コンテナを起動したらそれぞれのコンテナから接続ができるかを確認してみましょう。
今回はWordPressのコンテナのボートは8000でホスト側に解放しているので、localhost:8000にアクセスします。
WordPress の画面が開いて言語を選択するとデータベースの接続設定の画面になります。
ここには
データベース名 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 ls
とdocker 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につながっているのでlocalhost
か127.0.0.1
のポート3306でコンテナに接続できます。
データベース名 wordpress
ユーザー名 root
パスワード root
ホスト名 localhost or 127.0.0.1
ポート 3306
コンテナ間ネットワーク接続のまとめ
Dockerコンテナ単体で利用する時は--network=[NETWORK]
というオプションがあります。
docker run --network=<NETWORK>
今回の複数のDocker Composeファイルでコンテナ間のネットワーク接続では
- ネットワーク設定をDocker Composeにも書いたということと
-
Docker Composeでは外部のネットワークに接続するときには
external:true
の設定が必要
というたったこの2つだけです。
Dockerネットワークの超初歩的なことですが、きちんと理解せずにすっ飛ばしてしまったばかりに複数のDocker Composeでネットワーク設定をするのに私は随分悩みました。つまずいたところや、いまいち理解できなかったDockerのネットワーク設定を簡単にまとめられたかなと思います。
この記事を読んでくださった方はサクッとコンテナ間のネットワーク接続をしてアプリケーションの開発に時間を費やせることを願います。
少し長くなりましたが最後まで読んでいただきありがとうございました。
コメントを残す