docker-composeのenv_fileと.envファイルの違い

`docker-compose`において、今まで混同していた

- `docker-compose.yml`中の`env_file`で読み込むファイル
- `.env`という名前のファイル

の違いについて、他の人が同じ過ちをしないように書き留めておきます。

LinuxとWindowsでは環境変数の扱いが微妙に異なるので、Windowsに慣れている人やdocker for windowsを使っている人が引っかかりやすいと思います。

基本的にこの質問と解答と同じ内容ですが、少し情報を足しておきます。

[docker-compose cannot understand my env_file | stack overflow](https://stackoverflow.com/questions/39844522/docker-compose-cannot-understand-my-env-file)


# docker-composeと環境変数
公式リファレンス
[Dockerドキュメント | compose中の環境変数](https://docs.docker.com/compose/environment-variables/)
に沿って、知識を整理しながら解説します。

## `docker-compose.yml`中で使うホストの環境変数

`docker-compose.yml`中ではホスト側のシェルの環境変数が使えます。

例えば、

```docker-compose.yml
web:
  image: "webapp:${TAG}"
```
と書いておいて、host側で環境変数`TAG`が設定されていればその値が挿入されます。
例えば`TAG`に`v1.5`という値が設定されていれば、`docker-compose build`で作られるimage名は`webapp:v1.5`となります。

設定した環境変数にどのような値が挿入されるかは、`docker-compose config`コマンドで確認できます。

```bash
$ echo $TAG
# Windowsの場合は echo %TAG%で確認
v1.5

$ docker-compose config

version: '3'
services:
  web:
    image: 'webapp:v1.5'
```

### `.env`ファイル

ただ、いつもホストに使いたい環境変数が設定されているとは限らないです。
その場合の回避策として、`docker-compose.yml`で使う環境変数のデフォルト値を`.env`というファイルで設定できます。
例えば`.env`ファイルに

```yml:.env
TAG=v1.5
```

のように設定されていれば、image名は上と同様`webapp:v1.5`となります。

.envファイルは`docker-compose.yml`と同じ階層に保存してください。
参照:[docker-composeの.envファイルの認識場所が変わった](https://qiita.com/SolKul/items/034cd6cc3bae5a2f5146)

この`.env`ファイルによる設定は、ホストに使いたい環境変数がない場合の回避策なので、
もちろんホストに同名の環境変数が設定されていれば、そちらが優先されます。

```bash
$ export TAG=v2.0
# Windowsの場合は set TAG=v2.0で環境変数を設定
$ docker-compose config

version: '3'
services:
  web:
    image: 'webapp:v2.0'
```

つまり、`.env`ファイルは`$...`の値のデフォルト値を設定するファイルとも解釈できます。

## 立ち上げたコンテナ中の環境変数

**上の話とは別に**`docker-compose.yml`中の`environment`の項目を使うことで、`docker-compose run`や`docker-compose up`で立ち上げたコンテナに環境変数を設定できます。

```docker-compose.yml
web:
  environment:
    - DEBUG=1
```
とすると、立ち上がったコンテナ中では

```bash
$ echo $DEBUG
1
```
と環境変数が設定されています。

### `docker-compose.yml`中の`env_file`の項目
このコンテナ中の環境変数を別ファイルに書いておくこともできます。例えば`web-variables.env`というファイルに

```yaml:web-variables.env
DEBUG=1
FOO=bar
```
と書いておき、

```yaml:docker-compose.yml
web:
  env_file:
    - web-variables.env
```
と、`docker-compose.yml`中の`env_file`の項目で読み込むファイルを指定しておけば、
コンテナ中では

```bash
$ echo $DEBUG
1
$ echo $FOO
bar
```
と環境変数が設定されています。

以上から、

- `env_file`で読み込むファイル
- 先程述べた`.env`ファイル

は**全く働きが別**だということがわかると思います。

# まとめ

**`.env`ファイル**:
ホストの環境変数を`docker-compose.yml`中で`$...`として使えるが、ホストにその環境変数が設定されていなかった場合の回避策のために使うファイル。あるいは、ホストにその環境変数が設定されていればそちらが使われるので`$...`のデフォルト値を設定するファイルとも解釈できる。

**`env_file`**
立ち上げるコンテナに設定したい環境変数の設定を外部ファイルに書くときに使う`docker-compose.yml`内の項目

# この問題にはまったきっかけ

最後に、検索することで、できるだけこの問題で引っかかている人が解決できるようにするために、
この問題にはまったきっかけを記しておきます。

## `docker-compose.yml`中の環境変数を普通の変数のように使おうとしていた
 `docker-compose.yml`中の`$...`に代入する値を場合によって使い分けて、
いろんな場合に対応させようとしたときにこのenv_fileと.envファイルに苦しみました。
本来ならば、`-f`オプションを使ったりして、`docker-compose.yml`を分割すべきなのかもしれません。

## docker-composeのプロキシ設定をしたかった
プロキシ下でdocker-composeする場合は`docker-compose`の`build`中や、
立ち上がったコンテナで`HTTP_PROXY`などのプロキシ用の環境変数を設定しなければなりません。

これを解決するために`docker-compose`の`build>args`の項目や`environment:`の項を設定すればいいのですが、
ここでこのenv_fileと.envファイルに苦しみました。

これらを踏まえ、プロキシ下での`docker-compose`するための記事を作りました。

[docker-composeでのプロキシ設定を一つのファイルにまとめる](https://qiita.com/SolKul/items/2561c62734958c231b24)

## VSCodeのRemote Containerで.envファイルを使おうとした
[Advanced Container Configuration | VSCode](https://code.visualstudio.com/docs/remote/containers-advanced)
VSCodeのdockerを使ったリモートデバッグ機能(Remote Container)において、
`devcontainer.json`から`dockerComposeFile`の項で`docker-compose.yml`を指定し、リモートコンテナを立ち上げようとしました。

その際にビルド中やコンテナ内で環境変数を設定しようとし、上記のenv_fileと.envファイルを混同していて苦しみました。