🍎

Dockerにおいて外部値を参照するユースケースについて整理する

2022/03/23に公開

目的

Dockerを使うときに混乱しがちな下記のユースケースについて実装例を交えて整理し、忘れたときにパッと思い出すためのメモです。

  • docker-compose.ymlに対し環境変数経由で値を渡したい
  • Dockerfileに対し外部から値を渡したい
  • Dockerコンテナ内部に対し外部から値を渡したい

全体的に docker-composeを使ったDocker環境構築を想定しています。

下準備

動作を確認するためのDocker環境を用意します。

docker
 ┣ Dockerfile
 ┣ .env
 ┗ docker-compose.yml
docker-compose.yml
version: '3'
services:
  evntest:
Dockerfile
FROM busybox

docker-compose.ymlに対し環境変数経由で値を渡したい

まずはdocker-compose.yml内で環境変数を使って動的に値を渡したい場合。
具体的には、サーバとしてコンテナを立ち上げてポート番号を環境ごとに変えたい場合や、後述のDockerfile内に環境変数を渡したい場合などが考えられます。

設定のポイントとしては

  • 環境変数を設定すること(今回は.envに記載)
  • docker-compose.ymlにおいて、${DEV_PORT} の形式で環境変数を指定すること

ですね。

実装例

サーバの起動ポートを外部指定する場合を想定して、設定ファイルを下記のように変えます。

docker-compose.yml
version: '3'
services:
  evntest:
    build:
      context: ./
    ports:
      - '${DEV_PORT}:3000'
.env
DEV_PORT=13000

ターミナルで docker-compose configを叩いてみます。

docker-compose config

services:
  evntest:
    build:
      context: /home/vagrant/aws_learning
    ports:
    - published: 13000
      target: 3000
version: '3'

ports.published.envで設定された値になっていることが確認できました。

Dockerfileに対し外部から値を渡したい

docker-compose.ymlではなく、Dockerfile内で動的な値を使いたい場合。
具体的には、コンテナのビルドの過程でパラメータを動的に指定したい場合、例えばサーバの設定ファイルを環境ごとに切り替えたい、とかですかね。

設定のポイントとしては

  • docker-compose.ymlbuild.args変数名=値の形式で変数を定義すること
  • Dockerfileで利用したい変数をARG命令で定義すること

です。

docker-compose.yml内のbuild.argsで変数を宣言し、Dockerfile内のARGで変数をマッピングする、ということですね。

参照: https://docs.docker.com/compose/compose-file/compose-file-v3/#args

実装例

docker-compose.yml
version: '3'
services:
  evntest:
    build:
      context: ./
      args:
        - CONF=dev.conf
Dockerfile
FROM busybox

ARG CONF
COPY $CONF /var/

CMD cat /var/dev.conf # コピー確認用

仮の設定ファイルを置いておく

dev.conf
dev conf

dockerをビルド/起動してみる

docker-compose build
docker-compose up

Recreating aws_learning_evntest_1 ... done
Attaching to aws_learning_evntest_1
evntest_1  | dev conf
aws_learning_evntest_1 exited with code 0

コンテナ内において catコマンドを実行することで中身を表示しています。問題なくファイルがコピーされていることが確認できます。

実装例(環境変数経由で値を渡す)

上の例では、docker-compose.ymlに直接変数を定義しましたが、値を環境変数経由で設定することも可能です。

docker-compose.yml
version: '3'
services:
  evntest:
    build:
      context: ./
      args:
        - CONF=${CONF}
.env
CONF=dev.conf

これによって、.envdocker-compose.ymlDockerfile に値が渡される形になっています。

Dockerコンテナ内部に対し外部から値を渡したい

今まではdocker-compose.ymlDockerfileなどの設定ファイル内で環境変数を参照する方法について記載しましたが、今回は最終的にビルドされるコンテナ内で環境変数経由での値を設定したいケースについてです。

コンテナで変数を参照することはかんたんでいくつか方法があります。
いずれの方法も変数の中身がコンテナ内部でも維持されます。

  • Dockerfile内でENVで環境変数を定義する
  • docker-compose.yml内でenvironmentを定義する
  • 外部ファイル内に環境変数を定義し、docker-compose.yml内でenv_fileに外部ファイルを設定する。

参照:

実装例(Dockerfile内でENVを使って環境変数を定義する)

Dockerfile
FROM busybox

ENV MODE local
CMD echo $MODE

dockerをビルド/起動してみる

docker-compose build
docker-compose up

Recreating aws_learning_evntest_1 ... done
Attaching to aws_learning_evntest_1
evntest_1  | local

ENVで設定された値がコンテナ内部でも保持されていることが確認できます。

実装例(docker-compose.yml内でenvironmentを定義する)

docker-compose.yml
version: '3'
services:
  evntest:
    environment:
      - MODE=local
    build:
      context: ./

実装例(docker-compose.yml内でenv_fileに外部ファイルを設定する)

.env_local
MODE=local
docker-compose.yml
version: '3'
services:
  evntest:
    env_file:
      - .env_local
    build:
      context: ./

実装例(.envdocker-compose.ymlDockerfile経由で環境変数をリレーする)

.env内に環境変数を定義し、それをdocker-compose.yml経由でDockerfileおよびコンテナに伝達するようなことも一応可能です。
あまり必要なケースはないかもしれませんが、docker-compose.ymlDockerfileとで共通して外部変数を使いたい場合には使えるかもしれません。

.env
MODE=local
docker-compose.yml
version: '3'
services:
  evntest:
    build:
      context: ./
      args:
        - MODE=${MODE}
Dockerfile
FROM busybox

ARG MODE
ENV MODE $MODE
CMD echo $MODE

dockerをビルド/起動してみる

docker-compose build
docker-compose up

Recreating aws_learning_evntest_1 ... done
Attaching to aws_learning_evntest_1
evntest_1  | local

環境変数の値が問題なくコンテナ内で参照できていることが確認できます。

順番に考えると以下のような感じでしょうか。

  • .envの値がDockerにロードされてdocker-compose.ymlbuild.argsに設定される
  • ARG命令によって、Dockerfile内にbuild.argsの変数がマッピングされて使える状態になる
  • ENV命令によってARG命令でマッピングされた変数が環境変数に設定され、コンテナ内で使えるようになる

まとめ

.envenv_fileenv_fileENVなど似たような名前の項目が多いので、焦っているときは特に混乱しがちです。
次焦ったときに役に立てばよいですね。

Discussion