docker-compose.ymlの環境変数でハマったこと

docker-compose で数日めちゃくちゃハマったので、メモしておきます。たぶん、ハマったのは私だけではないはず。


## 環境変数を設定しても反映されない場合がある？！

`docker-compose.yml`の`environment`に環境変数を設定できるとみんな言っています。そして、その通り、反映されます。

しかし、`docker-compose.yml`の中で別途`Dockerfile`をビルドする場合、その環境変数は設定されません。

なぜなら…

> `Dockerfile`は、Dockerイメージを構築するために使用される設定ファイルです。 Dockerfileには、イメージに含まれるファイルやアプリケーションの設定などが記述されます。 Docker Composeは、複数のDockerコンテナを組み合わせてアプリケーションを実行するためのツールです。`docker-compse.yml`は、Docker Composeのための設定ファイルです。

つまり、`docker-compose.yml`に指定する環境変数は、イメージをビルドする際、有効になるのではなく、コンテナで有効になるからです。こんな簡単なことに気付くのに、数日かかってしまうとは…。

### Dockerfileのビルドで環境変数を指定する場合

Dockerfileの中で環境変数を使いたい場合には、素直に、Dockerfileの`ENV`を使って環境変数を指定するのが良いです。

```Dockerfile
# ベースイメージの指定
FROM python:3.9-slim-buster

# 環境変数を指定(ただし、以下のコマンド実行時には参照できるが他のコンテナからは参照できない)
ENV HOGE dockerfile
ENV FUGA bbb
ENV APP_DIR /app

# ローカルのファイルをコピー
COPY ./app /app

# 作業ディレクトリを設定
WORKDIR ${APP_DIR}
RUN python3 ${APP_DIR}/print_hoge.py > hoge1.txt
```


:::note
- Dockerfileの中でENVを指定すると環境変数を定義できる
- この場合、このイメージから作ったコンテナでは環境変数が有効
:::


### docker-compose.ymlに書く場合

`docker-compose.yml`の`enviroment`に環境変数を列挙できます。ただし、前述のように、Dockerfileのビルド時には反映されません。

```yaml:docker-compose.yml
version: '1'
services:
  test_service:
    # Dockerfileをビルドする
    build:
      context: .
      dockerfile: Dockerfile
    container_name: python39_test
    image: python39_test_image
    # 環境変数を設定する
    environment:
      - HOGE=docker-compose.yml
      - bbb=bbb
      - ccc=30
    #  複数のコマンドを実行する
    command: >
      /bin/sh -c "
        python3 /app/print_hoge.py > hoge2.txt
        while true; do
          sleep 3600
        done
      "
```

:::note
- envirmentに環境変数を列挙できる
- ただし、Dockerfileのビルド時に環境変数を指定できない(もし指定したい場合は以下を参照)
:::

## docker-compose.ymlからDockerfileに変数を与える場合

`docker-compose.yml`の中で、Dockerfileに値を与えたい場合、以下のように、`build`の`args`に値を指定し、`Dockerfile`の中で`ARG`を宣言することにより、使うことができます。

```yaml:docker-compose.yml
version: "2"
services:
  test_service:
    # 環境変数を定義
    enviroment:
      - HOGE=Dockerfile
    # Dockerfileをビルドする
    build:
      context: .
      dockerfile: Dockerfile
      # Dockerfile に渡す変数を指定✨✨✨
      args:
        - FUGA=fuga
        # 上記で宣言した環境変数も渡せる
        - HOGE=${HOGE}
    container_name: python39_test
    image: python39_test_image
```

そして、Dockerfileの中でARGを定義

```Dockerfile
# ベースイメージとしてAlpineを使用
FROM python:3.9-slim-buster

# 変数を明示的に定義 --- これが必須✨✨✨
ARG HOGE

COPY ./app /app

# 作業ディレクトリを設定
WORKDIR /app
RUN python3 print_hoge.py > hoge1.txt
```

## 環境変数にダブルクォートをつけていた

`docker-compose.yml`の`environment`に環境変数を設定できるとみんな言っています。そして、その通り、反映されます。しかし、値を指定するとき、シェルコマンドのようにNAME="VALUE"と書くと、ダブルクォートを含めて環境変数に設定されます。

例えば...

```yaml:docker-compose.yml
version: '1'
services:
  test_service:
    # Dockerfileをビルドする
    build:
      context: .
      dockerfile: Dockerfile
    container_name: python39_test
    image: python39_test_image
    # 環境変数を設定する
    environment:
      # ダブルクォート付きの値を指定した --- (※1)
      - HOGE="HOGE"
      - FUGA=FUAG
```

上記(※1)で、echo $HOGE すると、"HOGE"が設定されているのを確認できます。


### 参考

- (参考) [dockerで環境変数を設定する方法3パターン](https://qiita.com/hiro5963/items/5c8308c26f40a5df5055)
- (参考) [docker-compose.yml で定義した変数を Dockerfile に渡したい](https://chaika.hatenablog.com/entry/2022/07/25/120000)