Docker Compose の links は非推奨なのかわかりにくい
はじめに
Docker で Minio を使っていたのですが、 Virtual Hosted Style の指定が必要でした。
が、注意書きが散らばっており、かなりわかりにくかったです。 少し整理してみました。
Docker の link オプションは非推奨は間違いない
こちらのページです。
Docker のネットワーク機能が作成される以前は、 Docker インストール時に作成される bridge ネットワークと Docker のリンク機能によりコンテナ間の情報を伝達していました。
リンク機能を利用する
適当にコンテナを作って試してみます。
$ docker run -d --name db -e POSTGRES_PASSWORD=password postgres
$ docker run -d --name db2 --link db:db -e POSTGRES_PASSWORD=password postgres
ネットワークの設定を見ると bridge が指定されており、どこのネットワークにも所属していません。
$ docker inspect db2 | jq '.[].NetworkSettings.Networks'
{
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null,
"NetworkID": "6190c1b18956de6190e467e2a5adaf992f70b43c740c4d1a91f69be4fc2f19f0",
"EndpointID": "f20458149fd60452d3a60e6de8b91794fdf67e8f269b691aca35726cc957eaea",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": null
}
}
どのようにコンテナ間の通信を可能にしているかというと、Links を指定したコンテナ側には以下の2つの方法によって実現しているようです。
環境変数
<alias>_ENV_<name>
形式で環境変数を作成します。
以下を実行するとログに以下の環境変数が出力されていました。
$ docker exec db2 env
...
HOSTNAME=936df0592cbd
DB_PORT_5432_TCP_ADDR=172.17.0.2
DB_PORT=tcp://172.17.0.2:5432
DB_PORT_5432_TCP=tcp://172.17.0.2:5432
DB_PORT_5432_TCP_PROTO=tcp
DB_NAME=/db2/db
DB_PORT_5432_TCP_PORT=5432
$ docker exec db env
...
HOSTNAME=252042d6bfdf
/etc/hosts の更新
作成されたコンテナ /etc/hosts ファイルは以下で作成されていました。
252042d6bfdf
は db の env に出力されている HOSTNAME と対応しています。
936df0592cbd
は db2 の自身を指していることになります。
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 db 252042d6bfdf
172.17.0.3 936df0592cbd
ネットワーク機能を利用する
ユーザー定義のネットワークを作成して、リンク機能と同様に作成してみます。
$ docker network create -d bridge my-net
$ docker run --network=my-net -d --name db -e POSTGRES_PASSWORD=password postgres
$ docker run --network=my-net -d --name db2 -e POSTGRES_PASSWORD=password postgres
Links の時に作成されていた環境変数が作られていません。
$ docker exec db env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/postgresql/17/bin
HOSTNAME=3cd6eaf8577c
POSTGRES_PASSWORD=password
GOSU_VERSION=1.17
LANG=en_US.utf8
PG_MAJOR=17
PG_VERSION=17.2-1.pgdg120+1
PGDATA=/var/lib/postgresql/data
HOME=/root
$ docker exec db2 env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/postgresql/17/bin
HOSTNAME=8f7be2a3bbb4
POSTGRES_PASSWORD=password
GOSU_VERSION=1.17
LANG=en_US.utf8
PG_MAJOR=17
PG_VERSION=17.2-1.pgdg120+1
PGDATA=/var/lib/postgresql/data
HOME=/root
db2 のコンテナ側の /etc/hosts には自身の HOSTNAME の設定されていますが、追加はなさそうです。
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3 8f7be2a3bbb4
Network 自体の設定を見るとコンテナに Name や IPアドレス を保持しているようです。
$ docker network inspect my-net | jq '.[].Containers'
{
"3cd6eaf8577cc69a68850611a6a5b4581ba2e1222417fddb46313a9e3d359848": {
"Name": "db",
"EndpointID": "9b68eaf4502bad6b82d9ea36fcb226658700d1b573e55e4317ec26f4376174ae",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
},
"8f7be2a3bbb463a5d72acd467c1ae37cdc0afe2bbba38ebec8e9f9c17c61180b": {
"Name": "db2",
"EndpointID": "c74fc43d7884c6262efa5dc01b318c6a6e77e2018a8bf15d19b8768dc5320daf",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
}
}
DNSNames に登録されているのみで、 Links / Aliases のどちらも設定がされていません。
$ docker inspect db2 | jq '.[].NetworkSettings.Networks'
{
"my-net": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"MacAddress": "02:42:ac:12:00:03",
"DriverOpts": null,
"NetworkID": "11a0357a71b950cb29eaa412e0df9c3b7064e3dd53452093190a18757a729e4f",
"EndpointID": "fd5aa3e78c94593ab251cd527444f5972f4315cf229c92c0d05d622c9d391e82",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": [
"db2",
"b72d6dce53e1"
]
}
}
Ping は通りますが、 db.my-net の指定になっています。Network の機能を使うとサービス名でのアクセスはデフォルトで可能です。
$ root@b72d6dce53e1:/# ping db
PING db (172.18.0.2) 56(84) bytes of data.
64 bytes from db.my-net (172.18.0.2): icmp_seq=1 ttl=64 time=0.205 ms
一旦、ネットワークから抜いた後に Alias も付与してみました。 Docker inspect の Network に反映されています。
$ docker network disconnect my-net 11c06ee6ef21
$ docker network connect --alias db2 --alias other-name my-net 11c06ee6ef21
$ docker inspect db2 | jq '.[].NetworkSettings.Networks'
{
"my-net": {
"IPAMConfig": {},
"Links": null,
"Aliases": [
"db2",
"other"
],
"MacAddress": "02:42:ac:12:00:03",
"DriverOpts": {},
"NetworkID": "9787240a2ed6722288d091753cf73e8b4f6efc8627272818c32e128b53c30896",
"EndpointID": "5dfe0fe415648290d1ce82e3e73bb246ee4954752bb37b7e30f48bfb38e99815",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": [
"db2",
"other",
"11c06ee6ef21"
]
}
}
Docker Compose の links は非推奨ではなさそう
Links を指定する
まずは Docker Compose の Links を指定してみます。 db2 側に links として <service名>:<alias名>
を登録します。
services:
db:
image: postgres
environment:
- POSTGRES_PASSWORD=password
db2:
image: postgres
environment:
- POSTGRES_PASSWORD=password
links:
- db:other
特に network を記載しなくても専用のネットワーク定義が作られています。そして、そのネットワークにコンテナが所属しています。
$ docker compose up -d
[+] Running 3/3
✔ Network demo_default Created 0.0s
✔ Container demo-db-1 Started 0.2s
✔ Container demo-db2-1 Started
$ docker network inspect demo_default | jq '.[].Containers'
{
"c6b2f326118702c8b18e4e42f581b054b889fdc1fd36de714801b3f8fa2670bf": {
"Name": "demo-db-1",
"EndpointID": "ca25f79e5698e83a0bd5079889c7948a946f54108de5561f326bd920d49c77bb",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
},
"d3d356da18430afbd7a535a28e3627abb44d0c4cea7ef4ae2ab203af11b6bdd2": {
"Name": "demo-db2-1",
"EndpointID": "244a7b22dda252d53b736ec27ec1cc28f3d243d6fecdc607d3f8a56abda24e74",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
}
}
Ping も通ります。
$ root@5b261aa1787f:/# ping other
PING other (172.18.0.2) 56(84) bytes of data.
64 bytes from demo-db-1.demo_default (172.18.0.2): icmp_seq=1 ttl=64 time=0.205 ms
Docker の inspect を見てみます。 Links というプロパティが追加されています。 Alias 自体は特に変更がなさそうです。
$ docker inspect demo-db2-1 | jq '.[].NetworkSettings.Networks'
{
"demo_default": {
"IPAMConfig": null,
"Links": [
"demo-db-1:other",
"demo-db-1:db-1",
"demo-db-1:demo-db-1"
],
"Aliases": [
"demo-db2-1",
"db2"
],
"MacAddress": "02:42:ac:12:00:03",
"DriverOpts": null,
"NetworkID": "70de9c9b7d68dcdd01974b195da3bcd880cae2b174580b7fdd4ba55826458b66",
"EndpointID": "244a7b22dda252d53b736ec27ec1cc28f3d243d6fecdc607d3f8a56abda24e74",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": [
"demo-db2-1",
"db2",
"d3d356da1843"
]
}
}
$ docker inspect demo-db-1 | jq '.[].NetworkSettings.Networks'
{
"demo_default": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"demo-db-1",
"db"
],
"MacAddress": "02:42:ac:12:00:02",
"DriverOpts": null,
"NetworkID": "70de9c9b7d68dcdd01974b195da3bcd880cae2b174580b7fdd4ba55826458b66",
"EndpointID": "ca25f79e5698e83a0bd5079889c7948a946f54108de5561f326bd920d49c77bb",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": [
"demo-db-1",
"db",
"c6b2f3261187"
]
}
}
Network Alias を指定する
今度は Docker Compose のネットワークの Alias を指定します。
全てのサービスに対して明示的に demo というネットワークに所属させます。 links とは異なり、別名をつけたいので DB の方に other という Alias を設定しています。
services:
db:
image: postgres
environment:
- POSTGRES_PASSWORD=password
networks:
demo:
aliases:
- other
db2:
image: postgres
environment:
- POSTGRES_PASSWORD=password
networks:
- demo
networks:
demo:
立ち上げて接続を確認します。
$ docker comopose up -docker
[+] Running 3/3
✔ Network demo_demo Created 0.0s
✔ Container demo-db-1 Started 0.2s
✔ Container demo-db2-1 Started
DB2のコンテナから Ping を通せます。
$ root@614947a1f4c4:/# ping other
PING other (172.18.0.2) 56(84) bytes of data.
64 bytes from demo-db-1.demo_demo (172.18.0.2): icmp_seq=1 ttl=64 time=0.226 ms
詳細を見てみます。 違いとしては Links が null なので、あくまで Alias を元に通信ができていそうです。
$ docker inspect demo-db2-1 | jq '.[].NetworkSettings.Networks'
{
"demo_demo": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"demo-db2-1",
"db2"
],
"MacAddress": "02:42:ac:12:00:03",
"DriverOpts": null,
"NetworkID": "ecc912e535a3cd7955317109ea57212d378a8f91aca71fbb20e4dd06be4ca9c9",
"EndpointID": "b1f3f4f85e99121f5ac9187d884d36a5e09b101feb98acaf0f43eb2f7df37395",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": [
"demo-db2-1",
"db2",
"614947a1f4c4"
]
}
}
$ docker inspect demo-db-1 | jq '.[].NetworkSettings.Networks'
{
"demo_demo": {
"IPAMConfig": {},
"Links": null,
"Aliases": [
"demo-db-1",
"db",
"other"
],
"MacAddress": "02:42:ac:12:00:02",
"DriverOpts": null,
"NetworkID": "ecc912e535a3cd7955317109ea57212d378a8f91aca71fbb20e4dd06be4ca9c9",
"EndpointID": "37fdd02272e3663df2ce3ebe2e32564c045695bc176b729b40408994464794c5",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": [
"demo-db-1",
"db",
"other",
"5097985f074e"
]
}
}
ドキュメントを確認する
Docker Compose の Network
確かに Docker Compose V1 自体のサポート切れの注意がありますが、 links 自体は他サービスに別名をつけられるということで紹介されています。
実際、 V1 から V2 へのマイグレーションのページには links の記載はありません。
Services#links
非推奨の記載はありませんが、いくつかポイントの記載があります。
- ネットワークの指定がなければデフォルトでサービス名のアクセスが可能
- depends_on と同様にサービス間の依存関係を表しているので起動順序に関わる
- 異なるネットワークのサービスに対して Links の設定をしても Compose としては構成誤りの警告をしない
例えば、異なるネットワークに所属しているにも関わらず links を指定します。
この時、実行するとエラーがなく起動するのですが、実際は名前解決できないので注意が必要ということになります。
services:
db:
image: postgres
environment:
- POSTGRES_PASSWORD=password
networks:
network_a:
db2:
image: postgres
environment:
- POSTGRES_PASSWORD=password
links:
- db:other
networks:
network_b:
networks:
network_a:
network_b:
Services#aliases
例えば、以下のような links の指定をした場合、 db3 から other の名前解決はできませんが、 aliases であれば db2 / db3 のどちらで使える別名になります。
services:
db:
image: postgres
environment:
- POSTGRES_PASSWORD=password
db2:
image: postgres
environment:
- POSTGRES_PASSWORD=password
links:
- db:other
db3:
image: postgres
environment:
- POSTGRES_PASSWORD=password
まとめ
docker の links のオプションは非推奨であり、廃止される可能性があります。 一方、docker compose の links のオプション自体は非推奨ではなさそうです。
使い分けについては以下でも良いのかなと思いました。
- links : 簡単に別名を設定したい時。限られたコンテナ間で別名を利用できるようにしたい時
- aliases : ネットワーク全体に別名を利用させたい時
Discussion