Technology Topics by Brains

ブレインズテクノロジーの研究開発機関「未来工場」で働くエンジニアが、先端オープン技術、機械学習×データ分析(異常検知、予兆検知)に関する取組みをご紹介します。

docker-composeで環境変数を使う

こんにちは。エンジニアの中西です。
今回は docker-compose の yml ファイルにて、環境変数が展開されずにハマった事について書きたいと思います。
docker-compose は Impulse でも使っています。複数のコンテナから構成される Impulse を yml ファイルで管理できて便利です。
yml ファイルに環境変数を定義しておき、実行環境毎に変数値を設定する事も可能なのですが、環境によっては設定した値が展開されず。。という事象に遭遇しました。

実行環境

  • OS : Ubuntu 16.04
  • docker : v17.09.0-ce
  • docker-compose : v1.17.0
  • docker-compose.yml : v3.3

準備

それでは、イメージのバージョンを環境変数で設定できるようにymlファイルを記述してみます。

version: '3.3'

services:
  envtest:
    image: envtest-node:${IMAGE_VERSION:-invalid}
    :
  (省略)

イメージのバージョンを環境変数 IMAGE_VERSION で変更可能としています。 環境変数の指定がない場合は invalid が設定されます。

続いて、イメージが存在している事を確認します。

$ docker images envtest-node
REPOSITORY     TAG     IMAGE ID      CREATED      SIZE
envtest-node   latest  fedc1d9b97ce  1 weeks ago  933MB

バージョンは latest です。

実行してみる

まずは環境変数を指定せずに実行してみます。

$ docker-compose up -d envtest
Pulling envtest (envtest-node:invalid)...
ERROR: pull access denied for envtest-node, repository does not exist or may require 'docker login'

環境変数が設定されていないので、デフォルトのinvalidが設定されました。
当然ですが、envtest-node:invalid というイメージは存在していないので docker pull で取得しようとしていますが、ログインしていないためエラーとなっています。

では、環境変数を指定して実行します。

# バージョン`latest`を設定
$ export IMAGE_VERSION=latest

# 実行
$ docker-compose up -d envtest
Pulling envtest (envtest-node:invalid)...
ERROR: pull access denied for envtest-node, repository does not exist or may require 'docker login'

エラー。
バージョン部分がデフォルト値の invalid となっていますね。。
設定した環境変数が反映されていないようですので、確認してみます。

$ echo ${IMAGE_VERSION}
latest

ちゃんと設定されていますね。

では、docker-compose.yml の environment に設定値含めて追加してみます。

version: '3.3'

services:
  envtest:
    image: envtest-node:${IMAGE_VERSION:-invalid}
  environment:
    - IMAGE_VERSION=latest
    :
  (省略)

再度実行します。

$ docker-compose up -d envtest
Pulling envtest (envtest-node:invalid)...
ERROR: pull access denied for envtest-node, repository does not exist or may require 'docker login'

エラー。同じですね。

どうすれば展開されるのか

docker-composeは .env という環境ファイルにデフォルトの環境変数を定義できるようなので、設定してみます。

$ vi .env
IMAGE_VERSION=latest

上記の1行を設定して保存し、実行してみます。

$ docker-compose up -d envtest
Creating envtest ...
Creating envtest ... done

おぉ、起動したようです! 確認してみます。

$ docker ps
CONTAINER ID  IMAGE                COMMAND                 CREATED        STATUS        PORTS                   NAMES
452f84eed286  envtest-node:latest  "/bin/sh -c 'node sr…"  2 minutes ago  Up 5 seconds  0.0.0.0:3333->3333/tcp  envtest

バージョンlatestで起動されています。

もしかして、.env環境変数が設定されていれば、実行時の環境変数設定値が反映されるのか?
公式サイトによると、
実行時に環境変数を指定すると、常に .env ファイル中で定義した変数を上書きします。同様にコマンドラインの引数で値を指定した場合も、指定した値を優先します。
とあります。

環境ファイル — Docker-docs-ja 17.06.Beta ドキュメント

試してみます。

$ export IMAGE_VERSION=none

存在しないバージョンを設定したので起動されないはずです。

$ docker-compose up -d envtest
Creating envtest ...
Creating envtest ... done

起動してしまいました。。

$ docker ps
CONTAINER ID  IMAGE                COMMAND                 CREATED        STATUS        PORTS                   NAMES
f50c6736d2e7  envtest-node:latest  "/bin/sh -c 'node sr…"  4 seconds ago  Up 3 seconds  0.0.0.0:3333->3333/tcp  envtest

バージョンは.envに設定したlatestですね。
実行時の環境変数設定が反映されていない事がわかります。

原因は何?

とりあえず、 .envに書いておけば反映される 事は分かりましたが、冒頭で述べた通り環境によっては実行時の環境変数設定が反映されたりと、気持ちの悪い状態が続いていました。
そんな中、何気なくdockerのイメージ一覧を確認していたときでした。

$ docker images
REPOSITORY      TAG     IMAGE ID      CREATED      SIZE
docker/compose  1.17.0  b5a188e247b9  3 weeks ago  19.6MB

docker-compose のイメージが存在しています。
そういえば以前から環境によっては存在していた気がしますが、あまり気にしてはいませんでした。
ちょっと公式サイトを確認してみましょう。

Docker Compose のインストール — Docker-docs-ja 17.06.Beta ドキュメント

docker-composeのインストール方法は3パターン存在するようです。

  1. curlコマンド実行によるインストール
  2. pipコマンド実行によるインストール
  3. dockerコンテナとしてインストール

※ビルドする方法もありますがここでは除外します

今回の環境は3番目ですね。
そういえば、実行時の環境変数設定が反映されている環境はどうなんだろう。
docker-composeのコンテナは存在しているのか確認してみる。

$ docker images docker/compose
REPOSITORY      TAG     IMAGE ID      CREATED      SIZE

ありませんね。 curl、又はpipでインストールされている事になります。

まさか、インストールの方法で動きが変わる???
試しに、NGな環境のdocker-composeを削除し、curlで再インストールしてみましょう。

$ docker rmi <docker-composeのイメージID>
:
$ curl -L --fail https://github.com/docker/compose/releases/download/1.17.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ docker-compose version
docker-compose version 1.17.0, build ac53b73
:
$ docker images
REPOSITORY     TAG     IMAGE ID      CREATED      SIZE
envtest-node   latest  fedc1d9b97ce  1 weeks ago  933MB

正しくインストールされ、docker-composeのイメージも存在していないですね。
実行する前に、環境変数の値を再確認しておきます。

# .envファイル
IMAGE_VERSION=latest

# 実行時の環境変数
$ echo ${IMAGE_VERSION}
none

デフォルトはlatestですが、実行時にnoneとしているので、noneとなるのが理想です。
実行してみます。

$ docker-compose up -d envtest
Pulling envtest (envtest-node:none)...
ERROR: pull access denied for envtest-node, repository does not exist or may require 'docker login'

なんと! イメージのバージョン指定がnoneとなっています!
これは、.envの設定値を実行時の設定値で上書きされている事になります。
意図した動作をしてくれました。

終わりに

なぜコンテナとしてインストールすると環境変数の値が反映されないのかは調査できていませんが、 もし、同様の事象にハマった場合には、一度dockerのイメージ一覧を確認してみる事をおすすめします。
そこにdocker/composeのイメージが存在していたら。。。