docker-composeで.envで開発/本番環境を切り替える


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:の部分を切り替えるようにすればいいと思います。


  1. MySQLやRailアプリに指定するDBパスワード等も一緒に記述してます。 

  2. image: app_name:tag_nameの形式でタグも指定できるのでそちらに環境の名前をつけてもいいです。 

  3. やろうと思えばdocker-composeのbuild:arg:オプションを使ったりenv_file:を指定して、パッケージのリストを切り替えるみたいなことはできます。環境によってDockerfileが殆ど変わらない場合はそれでいいのですが、自分の場合はかなり違うこともあって無駄に見づらく複雑になるだけでした。