Edited at

docker-compose から docker network を少しだけ理解したい


docker-compose での疑問

docker公式っぽいやつの docker-compose の例 : https://docs.docker.com/compose/gettingstarted/

ここでのapp.pyredishostが以下のように指定されています。


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-composeexample で作られたであろう example_docker_compose_defaultdocker 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 を使おう!