docker-composeで簡単に環境を切り替えたい
webアプリの開発でサーバーやDBを同時に立ち上げるためにdocker-composeを使用していて
テストや動作確認もコンテナ上で起動してやる場合、webアプリを動かすコンテナとして
- 「production環境」 alpineをベースに最小限のパッケージとモジュールを入れて余分なキャッシュ等も消し、できるだけイメージサイズを小さくしたもの
- 「development環境」 テスト関連やgit、分析ツール等の開発に必要なものが入ったやや大きいサイズのイメージのもの
のように2種類以上の環境を使い分けたくなりますが、これをどう切り替えたらいいかという話
単純にdocker-compose.ymlを複数作って -f でファイル名を指定する方法や
公式ドキュメントにあるように拡張用のcomposeファイルを作る方法もありますが、doker-compose内で展開できる環境ファイルの.env
ファイルを使用して切り替えるのが色々と応用がきくのでお薦めです。
作りたい環境に合わせたDockerfileを用意する
まず環境に合わせたDockerfileを用意します。
例えば
- 「Docker_production」
- 「Docker_development」
という感じに分けます。
.envを用意しdocker-composeに変数を指定する
.envファイルをdocker-compose.ymlと同じ階層に用意するとdocker-compose内で変数のように展開できます。
これを利用するとbuildするDockerfileのファイル名も変数で切り替えることができます。
以下はRailsを想定してますが、他のケースでも応用できると思います。
docker.compose.yml
version: '3.7'
~ 省略 ~
rails:
build:
context: .
dockerfile: Dockerfile_${DOCKER_RAILS_ENV}
image: webapp_${DOCKER_RAILS_ENV}
volumes:
- .:/myapp
- public:/myapp/public
- sockets:/myapp/tmp/sockets/
ports:
- "3000:3000"
links:
- db
environment:
RAILS_ENV: $DOCKER_RAILS_ENV
DB_HOST: db
DB_USERNAME: $DB_USERNAME
DB_PASSWORD: $DB_PASSWORD
RAILS_SERVE_STATIC_FILES:
~ 省略~
.env
DOCKER_RAILS_ENV=production
DB_USERNAME=root
DB_PASSWORD=password
buildするDockerfile名に.envに書かれた環境変数を利用する
docker-compose.ymlのdockerfile: "Dockerfile_${DOCKER_RAILS_ENV}"
の部分で
production環境用に作ったDocker_production
というファイルとDocker_development
というファイルを.envで定義した環境変数で指定し切り替えています。1
.envをDOCKER_RAILS_ENV=development
とすればdevelopment環境でupができます。
作成されるイメージ名を指定する
デフォルトでは_"ディレクトリの名前"___"指定したコンテナ名(rails)"_になるので環境を変えても同じイメージ名がつきます。
build:の下にimage:を指定するとイメージ名を指定してビルドできます。
->https://docs.docker.com/compose/compose-file/#build
image:webapp_${DOCKER_RAILS_ENV}
でビルドされるイメージ名も環境で変わるようにしています。2
ちなみに${DOCKER_RAILS_ENV:-development}
とすれば変数が指定されていない場合のデファルト値がdevelopmentになります
必要であれば使用するDBのイメージ名でimage: mysql:${DB_VER-5.7}
として公式イメージのバージョンの指定にも応用できます。
参考:案外知られてないdocker-composeの環境変数定義の記法
注意点
ホストマシンのLinux等に.envで指定した変数と同名の環境変数が設定されてる場合、ホストマシンの環境変数が優先されるので、意図的に使いたい場合を除いて名前がバッティングしないようにする必要があります。
今回の例だとRAILS_ENVは使われやすいので、DOCKER_RAILS_ENVとしてかぶらないようにしてます。
またデフォルトで.gitignoreや.dockerignoreに.envは入ってないので間違ってもAWSのキーなどのクレデンシャルを.envに記述してgithubやdockerhub等にアップロードしないように注意しましょう。
Dockerfileは複数必要か
結局この方法だとdocker-composeは1つで済みますがDockerfileの方は2種類以上必要になります。
これも一つにできないかと考えたのですが、複雑になるのでやめました。3
アプリのルートをどうしてもDockerfile一つにしたい場合は、片方のDockerfileを配下に別のディレクトリを作って入れてdocker-composeのcontext:
の部分を切り替えるようにすればいいと思います。