docker-compose での疑問
docker公式っぽいやつの docker-compose の例 : https://docs.docker.com/compose/gettingstarted/
ここでのapp.py
のredis
のhost
が以下のように指定されています。
cache = redis.Redis(host='redis', port=6379)
なぜ host='redis'
で別のコンテナのredis
につなぐことが出来るんだい?
上記の公式サイトには以下のように解説されています。
In this example, redis is the hostname of the redis container on the application’s network. We use the default port for Redis, 6379.
はぇ〜
application’s network ってなに
ここでいう application’s network
とは docker container
におけるネットワークのことっぽい?
docker-compose up
等で起動されたコンテナ群は、すべて同一のネットワークに所属することになるようです。
参考にさせていただいた記事 : https://qiita.com/roba4coding/items/efd3a38db08eb476d412
つまりどういうことだってばよ
docker inspect
コマンドを使うことでふわっと概要がわかります。
inspect
するためにまず コンテナのIDを調べます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aa690f2ae5d4 example_docker_compose_web "python app-server/s…" 2 minutes ago Up 2 minutes 0.0.0.0:5000->5000/tcp example_docker_compose_web_1
4f39c7c9cc47 redis:alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 6379/tcp example_docker_compose_redis_1
inspect
します。
$ docker inspect 4f39c7c9cc47
...
"Networks": {
"example_docker_compose_default": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"4f39c7c9cc47",
"redis"
],
...
}
}
...
コンテナのID : 4f39c7c9cc47
(example_docker_compose_redis_1) が redis
というエイリアスで登録されているのですね。
このエイリアスを使うことが出来るのが、同一 docker network
に所属するものだけだということですね。
上記でいうと コンテナ aa690f2ae5d4
(example_docker_compose_web_1) が エイリアスを使うことが出来るということですね。
どこで redis
というエイリアスの名前が決まったかということですが、docker-compose.yml
に書いてある services
の直下の定義の名のことみたいですね。
version: '3'
services:
# ↓これ
web:
build: .
ports:
- "5000:5000"
# ↓これ
redis:
image: "redis:alpine"
docker network ってなに
docker network ls
で現在存在する docker network
の一覧を見ることができます。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
ac27f0096628 bridge bridge local
e72136cdac25 example_docker_compose_default bridge local
d2b0552308a8 host host local
ここで 最初の docker-compose
の example
で作られたであろう example_docker_compose_default
のdocker network
の詳細を見てみましょう。
コマンドは docker network inspect
です。
$ docker network inspect example_docker_compose_default
[
{
"Name": "example_docker_compose_default",
"Id": "e72136cdac25de9dbc9875467aacd59e916ba8b7122cbede91f81387a2a18715",
...
"Containers": {
"4f39c7c9cc478dc30aca3bd21c6dc1eda2bb189c0b5264a325f98b38ad8cd7c6": {
"Name": "example_docker_compose_redis_1",
...
},
"aa690f2ae5d483c0c2cf213d9929a3d49025859464abe095f861c05bbb66ee32": {
"Name": "example_docker_compose_web_1",
...
}
},
...
]
Containers
に 先ほど docker-compose
で作られたコンテナ達がありますね。コンテナIDも一致しているようです。
参考にさせていただいた記事 : https://qiita.com/TsutomuNakamura/items/ed046ee21caca4a2ffd9
docker-compose を使わずにやってみよう
今回は別の例として mysql
が起動しているコンテナ に対して python
が起動したコンテナからアクセスしたいと思います。
docker networkを知らなかった時
まずmysql
のコンテナをたてます。
$ docker run -e MYSQL_ROOT_PASSWORD=root -d -p 3307:3306 --name test-mysql mysql:5.6
4f7475ea1ac4db5d4aad630cbe585faf2dca39db61d7e405e14e9554414bd486
python
が起動しているコンテナから mysql
のコンテナにアクセスするためには、そのコンテナのアドレスを知る必要があります。
$ docker exec test-mysql cat /etc/hosts
127.0.0.1 localhost
..
172.17.0.2 4f7475ea1ac4
こうすることでようやく接続することができました。(もっといいやり方あったら教えてください..)
>>> import mysql.connector
>>> conn = mysql.connector.connect(host="172.17.0.2",user="root",password="root",port=3306,database="mysql")
>>> conn.is_connected()
True
docker networkを使った場合
まず、コンテナが所属するための docker network
を作ります。
docker network
に関して参考にさせていただいたブログ : https://www.sambaiz.net/article/7/
$ docker network create -d bridge test-network
25d355cf117def0e6ce801341e1b535320cd688435a436ce063dc49bbb3c9c0e
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
ac27f0096628 bridge bridge local
e72136cdac25 example_docker_compose_default bridge local
d2b0552308a8 host host local
07263a6d0de1 test-network bridge local
コンテナが作成される時に、作ったネットワークに所属してもらうようにするには、--net
オプションを使うようです。
$ docker run -e MYSQL_ROOT_PASSWORD=root -d -p 3307:3306 --name test-mysql --net=test-network --net-alias mysql mysql:5.6
0f901dbda634c3d05cce10d2bf91fb0ef82d39fbd1b1046f284db522bc8387f8
こうすることで、docker-compose
で起動したコンテナと同様にエイリアスが登録されます。
$ docker inspect 0f901dbda634
...
"Networks": {
"test-network": {
...
"Aliases": [
"mysql",
"0f901dbda634"
]
...
}
...
そして python が起動するコンテナも同一docker network
上にたててあげれば、
$ docker run -it --net=test-network test-python
>>> import mysql.connector
>>> conn = mysql.connector.connect(host='mysql',user='root',password='root',port=3306,database='mysql')
>>> conn.is_connected()
True
無事、コンテナを名前解決できるようになり、host='mysql'
で接続できているのがわかると思います。
--link
の場合
$ docker run -e MYSQL_ROOT_PASSWORD=root -d -p 3307:3306 --name test-mysql --net=test-network mysql:5.6
2d96784fb9ae77cec276558d3439e3b455782bb4bac4291b76b65a27d5c27480
$ docker run -it --net=test-network --link test-mysql:mysql test-python
Python 3.7.3 (default, Mar 27 2019, 23:48:15)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import mysql.connector
>>> conn = mysql.connector.connect(host='mysql',user='root',password='root',port=3306,database='mysql')
>>> conn.is_connected()
True
同様に繋ぐことが出来ました。
link
の場合 Aliases
ではなくLinks
に名前解決するための情報が書かれていました。
...
"Networks": {
"test-network": {
...
"Links": [
"test-mysql:mysql"
],
"Aliases": [
"d0d2ed057334"
],
...
}
}
...
--net-alias
と --link
の使い分けに関してはまだ知識が浅いのでいつか調べたいと思います。
まとめ
docker-compose を使おう!