これは、なにをしたくて書いたもの?
ふだんDocker Composeをそんなに使っていないのですが、たまに使うとコンテナ間で名前解決するのにどうすればいいのかよくわからなく
なるので、ちゃんと見ておくことにしました。
参照ページ
主に、以下のページを見ています。
Networking in Compose | Docker Documentation
Compose specification | Docker Documentation
環境
今回の環境は、こちら。
Docker Engine。
$ docker version Client: Docker Engine - Community Version: 20.10.23 API version: 1.41 Go version: go1.18.10 Git commit: 7155243 Built: Thu Jan 19 17:45:08 2023 OS/Arch: linux/amd64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.23 API version: 1.41 (minimum version 1.12) Go version: go1.18.10 Git commit: 6051f14 Built: Thu Jan 19 17:42:57 2023 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.6.15 GitCommit: 5b842e528e99d4d4c1686467debf2bd4b88ecd86 runc: Version: 1.1.4 GitCommit: v1.1.4-0-g5fd4c4d docker-init: Version: 0.19.0 GitCommit: de40ad0
Docker Compose。
$ docker compose version Docker Compose version v2.15.1
確認する構成
今回確認を行うための構成は、以下から始めることにしました。
compose.yaml
services: web: image: nginx:1.23.3 task: image: ubuntu:22.04 entrypoint: - tail - -f - /dev/null cache: image: redis:7.0.8
nginxとRedisがあり、間にあるUbuntu LinuxからnginxやRedisにアクセスする、というシナリオで考えてみたいと思います。
以降は、docker compose up
で各コンテナを起動した後に
$ docker compose up
Ubuntu Linuxにログインして、動作確認に必要なパッケージをインストールしたものとして書いていきます。
$ docker compose exec -it task bash # apt update && apt install -y curl redis-tools bind9-dnsutils
もっともシンプルなパターン
実は、なにもせずとも各コンテナにアクセスできます。
Each container can now look up the hostname web or db and get back the appropriate container’s IP address.
Networking in Compose | Docker Documentation
ネットワークを作成して、services
に定義した名前でアクセスできるようになるみたいです。
When you run docker compose up, the following happens:
- A network called myapp_default is created.
- A container is created using web’s configuration. It joins the network myapp_default under the name web.
- A container is created using db’s configuration. It joins the network myapp_default under the name db.
起動。
$ docker compose up
確認。
# curl web <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> # redis-cli -h cache cache:6379>
確かにアクセスできます。
# dig +short web 172.18.0.3 # dig +short cache 172.18.0.4
なお、/etc/hosts
に書かれているというわけではなさそうです。
# cat /etc/hosts 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.2 619f085a21ac
サービスあたりのコンテナ数を増やしてみる
サービスあたりのコンテナ数を増やしてみると、どうなるのでしょう?
今度は、nginxおよびRedisを3つにしてみます。
$ docker compose up --scale web=3 --scale cache=3
確認してみます。
# curl web <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> # redis-cli -h cache cache:6379>
依然としてアクセスできますね、どうなっているんでしょう?
# dig +short web 172.18.0.5 172.18.0.7 172.18.0.2 # dig +short cache 172.18.0.6 172.18.0.8 172.18.0.4
コンテナ数だけIPアドレスが返ってくるようになっていますね。
networks+aliasesでエイリアスを定義する
networks
とaliases
を使うことで、エイリアスも定義できます。
Compose specification / Services top-level element / networks
たとえば、nginx
とredis
というエイリアスを定義してみます。ネットワークは、デフォルトネットワークとしました。
compose.yaml
services: web: image: nginx:1.23.3 networks: default: aliases: - nginx task: image: ubuntu:22.04 entrypoint: - tail - -f - /dev/null cache: image: redis:7.0.8 networks: default: aliases: - redis
コンテナ数は増やしたまま起動しましょう。
$ docker compose up --scale web=3 --scale cache=3
サービス名でも、エイリアスでも名前解決できますね。
# dig +short web 172.18.0.5 172.18.0.3 172.18.0.7 # dig +short nginx 172.18.0.5 172.18.0.3 172.18.0.7 # dig +short cache 172.18.0.8 172.18.0.6 172.18.0.4 # dig +short redis 172.18.0.4 172.18.0.6 172.18.0.8
links
links
も使うことができます。
Compose specification / Services top-level element / links
以下のように、links
に[サービス名]:[エイリアス]
または[サービス名]
で定義します。サービス名のみを指定した場合は、サービス名が
そのままエイリアスになるようです。
compose.yaml
services: web: image: nginx:1.23.3 task: image: ubuntu:22.04 entrypoint: - tail - -f - /dev/null links: - "web:nginx" - "cache" cache: image: redis:7.0.8
コンテナ数は増やして起動。
$ docker compose up --scale web=3 --scale cache=3
確認。
# dig +short web 172.18.0.7 172.18.0.5 172.18.0.3 # dig +short nginx 172.18.0.7 # dig +short cache 172.18.0.6
動きが変わりましたね。エイリアスでアクセスすると、複数のコンテナがある場合はひとつのIPアドレスに収束するようです。
そもそも、links
の説明にサービス間の通信をしたいのであれば必要ない、と書かれていますからね。
Links are not required to enable services to communicate - when no specific network configuration is set, any service MUST be able to reach any other service at that service’s name on the default network.
Compose specification / Services top-level element / links
名前解決の目的で、links
は使わない方が良さそうです。
また、links
にはコンテナ間に依存関係を持ち込む効果もあるようですが、これはdepends_on
でよいでしょう。
Links also express implicit dependency between services in the same way as depends_on, so they determine the order of service startup.
複数のネットワークを定義して、通信を区分けする
最後は、このパターンを試してみたいと思います。
Networking in Compose / Specify custom networks
ここまではデフォルトネットワークを使用していましたが、独自にネットワークを構成して、サービスがどのネットワークに属するかで
通信を区切ることもできるようです。
たとえば、2つのネットワークを定義してみます。
compose.yaml
services: web: image: nginx:1.23.3 networks: - frontend task: image: ubuntu:22.04 entrypoint: - tail - -f - /dev/null networks: - frontend - backend cache: image: redis:7.0.8 networks: - backend networks: frontend: driver: bridge backend: driver: bridge
Ubuntu Linuxは、どちらのネットワークにも属しています。
起動。
$ docker compose up --scale web=3 --scale cache=3
確認。
# dig +short web 172.20.0.3 172.20.0.5 172.20.0.4 # dig +short cache 172.19.0.4 172.19.0.5 172.19.0.2
どちらのサービスも参照できていますね。
では、次はUbuntu LinuxはRedisが属するネットワークには含めないようにしてみます。
compose.yaml
services: web: image: nginx:1.23.3 networks: - frontend task: image: ubuntu:22.04 entrypoint: - tail - -f - /dev/null networks: - frontend cache: image: redis:7.0.8 networks: - backend networks: frontend: driver: bridge backend: driver: bridge
この部分ですね。
task: image: ubuntu:22.04 entrypoint: - tail - -f - /dev/null networks: - frontend
すると、Redisへの名前解決ができなくなります。
# dig +short web 172.20.0.3 172.20.0.4 172.20.0.5 # dig +short store
こんなところでしょうか。
まとめ
Docker Composeを使った時に、コンテナ間で名前解決するバリエーションについて見てみました。
このあたりはほとんどわかっていなかったのでで、どういうバリエーションがあるか、その挙動について確認できたので良かったかなと
思います。
デフォルトだと、なにもせずにサービス名で名前解決できるんですね。