目次
Podmanで同一ネットワーク内の他のコンテナのドメイン名を解決できるようにする
筆者の環境
- Podman Compose: 1.2.0
- Podman: 4.9.3
- コンテナネットワークスタック: CNI
はじめに
先日、Podman Composeを用いてWordPressブログの構築作業を行っていました。WordPressはデーターベース用のコンテナとWordPressのコンテナが別サービスで動いていて、WordPressのコンテナからデーターベースサーバーが動くコンテナにホスト名でアクセスするには、ホスト名からIPアドレスへのアドレス変換ができなければいけません。
例えば、compose
ファイルで以下のようにホスト名を指定した場合、Podman内部でdb
というホスト名(=ドメイン名)を具体的なIPアドレスに変換することによって、はじめてWPのコンテナがDB用のコンテナにアクセスできるわけです。
services:
# WORDPRESS_DB_HOSTで指定しているホスト名はこのサービスに解決してほしいが...
db:
...
wordpress:
... # 中略
environment:
- WORDPRESS_DB_HOST=db
...
ただし、筆者の環境ではうまくいきませんでした。実際には、アドレス解決ができず、データーベース接続エラーになってしまいます。Dockerで同じcomposeファイルを利用する際は、うまくいっていたのですが…。
一時対処(真似しないでね)
とりあえず、最初はWORDPRESS_DB_HOST
部分にIPアドレスを直接入力する方法で対処しました。実際にはコンテナを作り直すたびにコンテナのアドレスがインクリメントされてしまうので、以下のようなシェルスクリプトを書いて、コンテナ実行中に実行します。
#!/usr/bin/env bash
# ':' 区切りでコンテナ名を入力
HOSTS=$(echo yokkincom_db_1:yokkincom_wordpress_1:yokkincom_phpmyadmin_1: | tr ':' '\n')
RESULTS=$(echo "$HOSTS" | xargs -I@ podman exec @ hostname -i)
paste <(printf "$RESULTS") <(printf "$HOSTS") | column -t
このシェルスクリプトの実行結果は以下のようになります。コンテナ名に対するアドレスが一対一で表示されます。いい発明でしょ?(良くない)
10.89.2.11 yokkincom_db_1
10.89.2.12 yokkincom_wordpress_1
10.89.2.13 yokkincom_phpmyadmin_1
そして利用したいコンテナのIPアドレスの最後のオクテットの値に、立ち上げるサービスの数を足した数を求めてcomposeファイルにペーストして、再度podman-compose -d
していた感じです。たとえば、起動中10.89.2.11
というアドレスが割り振られていたら、次のコンテナのアドレスは予想がつき、10.89.2.14
になるはずです。そのアドレスをcomposeファイルにペーストしていた感じです。
でも、これはあまりにも面倒くさいですよねえ?どうにかすることにしました。
コンテナネットワークをNetavarkに設定するといいらしい
今回の問題は「Can’t resolve hostname of other service in docker-compose.yml」を見て解決しました。
どうやら、コンテナのネットワークスタックを見直す必要があり、対処方法としては以下の2つになるみたいです。
- Podman 4.0未満で、Container Network Interface(CNI)を利用している場合は、DNSプラグインを有効化する。
- Podman 4.0以上なら、ネットワークスタックにNetavarkが利用できるのでそれを有効化して使う。
筆者は、CNIを利用しています。しかし、Podman 4.xを利用しているため、2番目の対処方法を実践してみようと思います。
podman info | grep network
# networkBackend: cni
# networkBackendInfo:
# package: containernetworking-plugins_1.1.1+ds1-3ubuntu0.24.04.1_arm64
# network:
Netavarkとはなにか?
ところでせっかくなので、Netavarkについても少し調べてみました。
Netavarkは、Podman 4.0以上で導入された一連のネットワークスタックの一つです。このネットワークスタックは、netavarkというネットワークの設定用のツールと、aardvark-dnsというDNSサーバーから構成されていて、従来のCNIを代替するだけでなく、さらなる利点も併せ持っているそうです。「Podman 4.0’s new network stack: What you need to know」を読むと、利点は以下になります。
- Better IPv6 support
- Improved support for containers in multiple networks
- Improved performance
今回関係あるのは、2番目の「Improved support for containers in multiple networks」でしょう。これに関して説明する節を引用しておきます。
2. Containers in multiple networks
For containers in multiple networks, it is now possible to specify static IPv4, IPv6, and MAC addresses on a per-network basis; previously, this was only possible for containers joined to a single network. Podman 4.0 also improves DNS resolution for containers in multiple networks. In previous Podman versions, a container could resolve the names of other containers only in the first network it joined. Now, containers can resolve other containers in every network they join.
複数のネットワークにおけるコンテナのアドレス指定とDNS解決について述べられているようです。
まず、以前は、単一のネットワークに属するコンテナに対してのみ可能でしたが、この技術によって複数のネットワークに属するコンテナに対して、ネットワークごとに静的なIPv4、IPv6、MACアドレスを指定できるようになったそうです。
また、以前のPodmanバージョンでは、コンテナは最初に参加したネットワーク内の他のコンテナの名前しか解決不可能でしたが、複数のネットワークに属するコンテナのDNS解決が改善され、現在は、コンテナが参加するすべてのネットワーク内の他のコンテナを解決できるようになったそうです。つまり、この機能を使えばよいわけです。
対処
まず、この対処方法を行うと既存のイメージがすべて削除されるので、それでもよいことを確認して操作を行います。
コンテナのホストの/etc/containers/containers.conf
を編集し、使用するネットワークを明示的に指定します。
[network]
network_backend = "netavark"
そして、以下のコマンドを実行し、Podmanのリセットを行います。
podman system reset --force
バックエンドが変更できているか確認します。
podman info | grep network
# networkBackend: netavark
# networkBackendInfo:
# network:
リセット後は、ちゃんとcomposeファイルでドメイン名を指定しても、Podmanがコンテナ間でいい感じにDNS解決してくれます。ということで解決です。
ありがとうございました。
コメント
コメントはありません。