🐳

Docker Compose の links は非推奨なのかわかりにくい

2025/01/08に公開

はじめに

Docker で Minio を使っていたのですが、 Virtual Hosted Style の指定が必要でした。
https://zenn.dev/mh4gf/articles/873e34b95bbbdf
https://zenn.dev/lincwell_inc/articles/minio_virtual_hosted_style
これらを参考にしながら、改めて Docker のマニュアルを読んでいました。
が、注意書きが散らばっており、かなりわかりにくかったです。 少し整理してみました。

Docker の link オプションは非推奨は間違いない

こちらのページです。
https://docs.docker.com/engine/network/links/

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

ネットワーク機能を利用する

https://docs.docker.com/engine/network/#user-defined-networks

ユーザー定義のネットワークを作成して、リンク機能と同様に作成してみます。

$ 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 は非推奨ではなさそう

まずは Docker Compose の Links を指定してみます。 db2 側に links として <service名>:<alias名> を登録します。

docker-compose.yml
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 を設定しています。

docker-compose.yml
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

https://docs.docker.com/compose/how-tos/networking/

確かに Docker Compose V1 自体のサポート切れの注意がありますが、 links 自体は他サービスに別名をつけられるということで紹介されています。
実際、 V1 から V2 へのマイグレーションのページには links の記載はありません。
https://docs.docker.com/compose/releases/migrate/

https://docs.docker.com/reference/compose-file/services/#links
非推奨の記載はありませんが、いくつかポイントの記載があります。

  • ネットワークの指定がなければデフォルトでサービス名のアクセスが可能
  • depends_on と同様にサービス間の依存関係を表しているので起動順序に関わる
  • 異なるネットワークのサービスに対して Links の設定をしても Compose としては構成誤りの警告をしない

例えば、異なるネットワークに所属しているにも関わらず links を指定します。
この時、実行するとエラーがなく起動するのですが、実際は名前解決できないので注意が必要ということになります。

docker-compose.yaml
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

https://docs.docker.com/reference/compose-file/services/#aliases
Links の違いとして Aliases はネットワークに所属する全てのコンテナで利用できる別名になります。
例えば、以下のような links の指定をした場合、 db3 から other の名前解決はできませんが、 aliases であれば db2 / db3 のどちらで使える別名になります。

docker-compose.yml
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