Docker Composeで環境変数のエイリアスを作りたい
経緯
相変わらずDocker上のMySQLをいじっている。
MySQLサーバに対して、毎回コンテナに入ってmysqlプロンプトを出してコマンドを打つのがめんどくさいので、webベースのGUIサーバを追加することにした。
このとき、.envで指定しているMySQL用のユーザ情報について、同じ値を別の名前で環境変数として指定する必要があった。
環境
docker-composeファイルは以下の通り。
version: '3.8'
services:
db:
container_name: db
image: mysql:8.0
environment:
- LANG=ja_JP.UTF-8
tty: true
volumes:
- type: volume
source: test_volume
target: /var/lib/mysql
networks:
- test_network
volumes:
test_volume:
name: test_volume
networks:
test_network:
external: true
.envはこの内容。
MYSQL_DATABASE=test_database
MYSQL_USER=test_user
MYSQL_PASSWORD=password
MYSQL_ROOT_PASSWORD=root_password
課題
今の環境に、phpmyadminというMySQLのGUIツールを新しいサービスとして導入する。
具体的に以下の内容を追加したい。
db-gui:
container_name: db-gui
image: phpmyadmin/phpmyadmin
environment:
- LANG=ja_JP.UTF-8
tty: true
ports:
- 8080:80
depends_on:
- db
networks:
- test_network
このとき、phpmyadminコンテナには環境変数PMA_HOSTS, PMA_USER, PMA_PASSWORDを渡して接続先と認証の情報を教える必要がある。
しかし、PMA_HOSTSはサービス名(db)を直書きすれば良いとして(networkが設定されてるので、サービス名←→アドレスができる)、他の2つの値は.envのMYSQL_USER, MYSQL_PASSWORDと同一である。
愚直な方法として、.envにPMA_USER, PMA_PASSWORDを追加しても良い。
が、同じ値(しかも認証情報!)を2回書くのはメンテナンス性も悪いし、ミスを誘発しやすい。
解決方法
今回、環境変数にエイリアスを設定することでこの問題を解決した。
このように、db-guiサービスのパラメータにenvironment:を設定して、値を${envで設定された変数名}とすることで、db-guiで変数が読まれる際にはMYSQL_USERの値で置き換えられる。
environment:
- LANG=ja_JP.UTF-8
- PMA_ARBITRARY=1
- PMA_HOSTS=db
- PMA_USER=${MYSQL_USER}
- PMA_PASSWORD=${MYSQL_PASSWORD}
おまけ
環境変数の評価タイミング的に、environment設定時に展開されるのか、参照時に展開されているのかが気になったので確認してみた。
つまり、PMA_USER="${MYSQL_USER}"なのか、PMA_USER="test_user"かということである。
試すのは簡単で、
docker compose exec db-gui bash
> echo $PMA_USER
test_user
> MYSQL_USER=hoge
> echo $PMA_USER
test_user
上書き後の最後の結果がtest_userなので、environmentに設定した変数はコンテナ作成時に評価されることが分かる。
更に複数の手段で指定される環境変数が、どの順番で読み込まれるかも分かる。
例えば、.envにTEST=$PMA_HOSTSなどとenvironmentで指定された変数を利用しようとしても、デフォルト値の""として評価される。
一応確認してみるとこのようになる。
docker compose exec db-gui bash
> echo $TEST
> echo $PMA_HOSTS
db
逆に応用テクとしてこんな風に.envの内容を利用して複雑な変数を用意することもできたりする。
COMPLEX=${MYSQL_PASSWORD}concat_ENVS${MYSQL_PASSWORD}hogehuga
Discussion