最近ローカル開発環境はDocker composeで本番環境はGKEという環境でちょっと気になったことがありました。
本番環境のGKEにはGitHub Actionsを使ってイメージのビルド→ECRへのイメージアップロード→GKEへのデプロイを行っています。
ただこのGitHub Actionsの中でローカル開発環境のDocker composeで使っているDockerfileをsedやechoなどで一部変更しています。
もしくは環境によってDockerfileの名前を変えて使い分けてたりします。
これよくよく考えてみるとコンテナのポータビリティを損なっていませんかね?
個人的にはなるべく環境によってDockerfileを変えたくないなと思っています。
具体的にはどうことかいうと
※以下のファイルは説明のため簡略化しています
ローカル開発環境のDockerfile
FROM nginx
EXPOSE 80
ローカル開発環境のdocker-compose.yml
version: "3"
services:
nginx:
build:
context: .
ports:
- "80:80"
restart: always
volumes:
- ./src:/var/www
本番環境のDockerfile
FROM nginx
EXPOSE 80
COPY --chown=nginx:nginx ./src /var/www
ローカル開発環境はdocker-compose.ymlでbind mountしてるのでイメージに/src配下を含まないようにしている。
対して本番環境はイメージの/src配下を含まないといけないのでGitHub Actionsの中でCOPY --chown=nginx:nginx ./src /var/www
を追記している状況です。
これってよくよく考えてみるとどっちも本番環境のDockerfileを使えばいいんじゃないですかね?
というのもDockerfileでCOPYしてビルドしたとしてもbind mountしたら/var/wwwの配下がビルドされた時点よりもbind mountが優先されるならばそれでいいんではないでしょうか?
ということでbind mountが必ず優先されるのか実験です。
実験環境
フォルダ構成
qiita
├── Dockerfile
├── docker-compose.yml
└── src
└── copy.html
Dockerfileの内容
FROM nginx
EXPOSE 80
COPY --chown=nginx:nginx ./src /var/www
docker-compose.ymlの内容
version: "3"
services:
nginx:
build:
context: .
ports:
- "80:80"
restart: always
volumes:
- ./src:/var/www
この状態でビルドしてコンテナを立ち上げます。
$ docker-compose up -d
/var/www配下を確認します。
$ docker-compose exec nginx ls -hl /var/www
total 4.0K
-rw-r--r-- 1 root root 17 May 5 13:09 copy.html
この状態でsrc/copy.htmlを削除し、ビルドし直さずにコンテナを立ち上げなおしてsrc/copy.htmlがなくなっているか確認します。
$ rm -f src/copy.html
$ docker-compose stop
Stopping qiita_nginx_1 ... done
$ docker-compose up -d
Starting qiita_nginx_1 ... done
$ docker-compose exec nginx ls -hl /var/www
total 0
ではこの状態で今後はsrc/copy_2.htmlを作成し、ビルドし直さずにコンテナを立ち上げなおしてsrc/copy_2.htmlのみとなってるか確認します。
$ touch src/copy_2.html
$ docker-compose stop
Stopping qiita_nginx_1 ... done
$ docker-compose up -d
Starting qiita_nginx_1 ... done
$ docker-compose exec nginx ls -hl /var/www
total 0
-rw-r--r-- 1 root root 0 May 5 13:55 copy_2.html
想定通りsrc/copy_2.htmlのみが存在します。
ではこの状態でsrc/copy_2.htmlの中身を変更し、ビルドし直さずにコンテナを立ち上げなおしてsrc/copy_2.htmlの中身の変更が反映されているか確認します。
$ echo "qiita test" >> src/copy_2.html
$ docker-compose stop
Stopping qiita_nginx_1 ... done
$ docker-compose up -d
Starting qiita_nginx_1 ... done
$ docker-compose exec nginx ls -hl /var/www
total 4.0K
-rw-r--r-- 1 root root 11 May 5 14:00 copy_2.html
$ docker-compose exec nginx cat /var/www/copy_2.html
qiita test
こちらも想定通りsrc/copy_2.htmlの変更内容がコンテナから見たときに反映されています。
この実験からビルドした状態がどうであれbind mountしたらその時のマウント元の内容が反映されることがわかりました。
つまり最初に述べたように本番環境のDockerfileを使えばいいってことです!!
これで環境ごとのDockerfileの差分が1つ減りました!!
めでたし、めでたし...とはいきません
既に気付いてる方もいるかもしれませんがbind mountではファイルの権限がnginx:nginx
になっていません。
この権限周りについては後日ちゃんと調べたいと思います。
※ちなみにdocker-compose.ymlのvolumesのオプションに権限を設定に関するものはありません