Docker と Docker Compose の環境変数 - Part 3. 全体の流れ






<!--

TODO 矢印の色を変えたほうがよいかな？

* Part 2 の図 ... 起動の流れ
* Part 3 の図 ... 環境変数の受け渡しの流れ

TODO
docker compose --env-file .env.local config|convert --env <- ない
https://x.com/Comamoca_/status/1799833905085980899

config, convert の違いってなんだ？

-->




## はじめに



### ◯ 環境変数の受け渡しの流れ

#### (1) Docker イメージ

![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254825/05458f16-059d-d797-bf71-9571d521728d.jpeg)


#### (2) Docker コンテナ

![4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254825/1be4fb46-1c45-51a4-cf3e-57e1e1bd22bc.jpeg)

### ◯ ポイント

上の図の矢印は何やねん😠って感じですが 

```
定義する場所 -> 使う場所
```

という意味で書いています。

* `compose.yaml` の中で使える変数
    * 物理環境の環境変数 で定義した変数
    * `docker compose build` コマンドの引数で定義した変数
    * `docker compose up` コマンドの引数で定義した変数
* `Dokcerfile` の中で使える変数
    * `compose.yaml` ファイルのプロパティで定義した変数
    * `docker image build` コマンドの引数で定義した変数
    * `docker container run` コマンドの引数で定義した変数 


### ◯ 各章の概要

1. `--build-arg` オプション ... 自分がハマっていたこと
2. `env_file` プロパティ ... ほかの方がハマっていたこと
3. `--env-file` オプション ... 2 章を踏まえた練習問題


<!--

TODO 並び替え

1. `env_file` プロパティ ... ほかの方がハマっていたこと
2. `--env-file` オプション ... 2 章を踏まえた練習問題
3. `--build-arg` オプション ... 自分がハマっていたこと

Docker | Docker Compose
2. デフォルトで .env を参照しない | する
3. 物理環境の環境変数を直接参照できない | できる

-->

### ◯ `docker compose config` コマンド

```
BLUE="Squirtle" docker compose --env-file .env.local config

#               docker compose --env-file .env.local build  --build-arg BLUE="Squirtle"
#               docker compose --env-file .env.local up     --env       BLUE="Squirtle"
```

`compose.yaml` に環境変数が反映されているかわからない😭 ってことありませんか？ `docker compose config` コマンドを使うと環境変数反映後の `compose.yaml` で見られます。`docker compose config` には `--build-arg`, `--env` オプションがありません。そのため上記のように先頭に環境変数を書く形 `BLUE="Squirtle"` で代替する方法があります。





### ◯ シリーズ

Part 3 ですが Part 1, 2 は読まなくても大丈夫だと思います。

* [Part 1. ARG と ENV - Qiita](https://bit.ly/4aZP3WG)
* [Part 2. オプションとプロパティ - Zenn](https://bit.ly/4aPiivr)





## 1. `--build-arg` オプション

### ◯ ポイント

|  |物理環境の環境変数を直接参照|
|:-:|:-:|
|  `Dockerfile` | できない |
| `compose.yaml`  |  できる |



### 1.1. Docker

`Dockerfile` 内では現在の物理環境にある環境変数を直接参照 **できない**。

![Docker コマンド(4).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254825/af187d15-1559-91be-2585-571d9a28a03a.jpeg)




#### サンプルコード

```
gh repo clone domodomodomo/docker-env-sample
cd docker-env-sample/part3/111

# for Bash - macOS, Ubuntu
bash cmd.sh

# for PowerShell - Windows
powershell ./cmd.ps1
```

* [docker-env-sample/part3/111](https://github.com/domodomodomo/docker-env-sample/tree/main/part3/111)



#### 1.1.1. 問題

サンプルコードの実行結果は次の 1 ~ 4 のうちどれですか？

```
1.
    BLUE: 'Squirtle'
    RED: 'Charmander'
    GREEN: 'Bulbasaur'

2.
    BLUE: ''
    RED: 'Charmander'
    GREEN: 'Bulbasaur'

3.
    BLUE: 'Squirtle'
    RED: ''
    GREEN: 'Bulbasaur'

4.
    BLUE: 'Squirtle'
    RED: 'Charmander'
    GREEN: ''
```

<details><summary>答え</summary>

4

`docker image build` コマンドを実行するときに `--build-arg` オプションを使わないと、現在の物理環境のシェルセッションにある環境変数を `Dokcerfile` 内で参照 **できない**。

</details>



### 1.2. Docker Compose

`compose.yaml` 内では物理環境にある環境変数を直接参照 **できる**。


![6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254825/e91d529a-1879-6799-d3ca-bc6347f4659a.jpeg)



#### サンプルコード

```
gh repo clone domodomodomo/docker-env-sample
cd docker-env-sample/part3/121

# for Bash - macOS, Ubuntu
bash cmd.sh

# for PowerShell - Windows
powershell ./cmd.ps1
```

* [docker-env-sample/part3/121](https://github.com/domodomodomo/docker-env-sample/tree/main/part3/121)




#### 1.2.1. 問題

サンプルコードの実行結果は次の 1 ~ 4 のうちどれですか？

```
1.
    BLUE: 'Squirtle'
    RED: 'Charmander'
    GREEN: 'Bulbasaur'

2.
    BLUE: ''
    RED: 'Charmander'
    GREEN: 'Bulbasaur'

3.
    BLUE: 'Squirtle'
    RED: ''
    GREEN: 'Bulbasaur'

4.
    BLUE: 'Squirtle'
    RED: 'Charmander'
    GREEN: ''
```

<details><summary>答え</summary>

1

`docker compose build` コマンドを実行するときに `--build-arg` オプションを使わなくても、現在の物理環境のシェルセッションにある環境変数を `compose.yaml` 内で参照 **できる**。

</details>

:::note info

以後、各設問のサンプルコードの実行方法は省略します。各問題の章立てはディレクトリ名と対応しています。「2.2.1. 問題」ならディレクトリ「221」を参照してください。

:::





## 2. `env_file` プロパティ

### ◯ ポイント

||`compose.yaml` の中で定義した環境変数|
|:-:|:-:|
|`Dockerfile` の中で|使える|
|`compose.yaml` の中で|使えない|

![7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254825/ee489a44-5e6f-9fdd-0a70-5d2f8b27a670.jpeg)


<br />

例えば以下のプロパティで設定した環境変数は `Dockerfile` の中で使えるようになりますが `compose.yaml` の中では使えません。

1. `services.サービス.build.args` 
2. `services.サービス.env_file`
3. `services.サービス.enviroment`


<br />

これらのプロパティで設定した値を `compose.yaml` の中で使おうとしてハマった方を 4 件見かけました。

* [docker-compose cannot understand my env_file - Stackoverflow](https://bit.ly/4bKIoAV)
* [docker-compose will always load .env - DEV Community](https://bit.ly/4esU8Kj)
* [docker-compose の env_file と .env ファイルの違い - Qiita](https://bit.ly/4ed3UzS)
* [docker-composeで環境変数が読み込まれない? - Zenn](https://zenn.dev/rhene/scraps/781fdbecd340d3)


<details><summary>個人的な感想</summary>

`compose.yaml` ファイルの各プロパティは `docker image build`, `docker container run` の各オプションと対応していると思っています。なので「`docker image build`, `docker container run` を押下したら `compose.yaml` で環境変数が使えるようになる... あれちょっと考え方がおかしいぞ」っていうのがひとつ気づくポイントなのかなと思いました。

</details>

<br />






### 2.1. Docker

意図的に空白にしています



### 2.2. Docker Compose



#### 2.2.1. 問題

サンプルコードの実行結果は次の 1 ~ 4 のうちどれですか？

```
1.
    undefined  | undefined

2.
    undefined  | Squirtle

3.
    Squirtle  | undefined

4.
    Squirtle  | Squirtle
```

> * `compose.yaml` の `services.サービス.env_file` プロパティに `.env.local` を指定したとき
>     * `.env.local` で定義された環境変数が **Dockerfile | compose.yaml** の中で使える

<details><summary>答え</summary>

* 3
* `Dockerfile`

</details>
















## 3. `--env-file` オプション

### ◯ ポイント

|イメージ|コンテナ|`.env` を自動で|
|:-:|:-:|:-:|
|`docker image build`|`docker container run`|読み込まない|
|`docker compose build`|`docker compose up`|読み込む*1|

*1 ただし `--env-file` が指定された場合は読み込まない





### 3.1. Docker

`--env-file` を省略しても `.env` は読み込まれません。

#### 3.1.1. 問題

サンプルコードの実行結果は次の 1 ~ 2 のうちどれですか？

```
1.
    BLUE: 'Squirtle'

2.
    BLUE: ''
```

> * `docker container run app` を押下したとき
>     * `.env` で定義された環境変数が Dockerfile の中で **使える | 使えない**

<details><summary>答え</summary>

* 2
* 使えない

</details>






#### 3.1.2. 問題

サンプルコードの実行結果は次の 1 ~ 2 のうちどれですか？

```
1.
    BLUE: 'Squirtle'

2.
    BLUE: ''
```

> * `docker container run --env-file .env.local app` を押下したとき
>     * `.env.local` で定義された環境変数が **Dockerfile | compose.yaml** の中で使える

<details><summary>答え</summary>

* 1
* `compose.yaml`

</details>




### 3.2. Docker Compose

`--env-file` を省略すると `.env` が読み込まれます。`compose.yaml` の中で使えるようになりますが `Dockerfile` の中では使えません。


#### 3.2.1. 問題

サンプルコードの実行結果は次の 1 ~ 4 のうちどれですか？

```
1.
    undefined  | undefined

2.
    undefined  | Squirtle

3.
    Squirtle  | undefined

4.
    Squirtle  | Squirtle
```

> * `docker compose up` または `build` を押下したとき
>     * `.env` で定義された環境変数が **Dockerfile | compose.yaml** の中で使える


<details><summary>答え</summary>

* 3
* `compose.yaml`

</details>





#### 3.2.2. 問題

サンプルコードの実行結果は次の 1 ~ 4 のうちどれですか？

```
1.
    undefined-Charmander  | undefined-undefined

2.
    undefined-Charmander  | Squirtle-Charmander

3.
    Squirtle-Charmander  | undefined-undefined

4.
    Squirtle-Charmander  | Squirtle-Charmander
```

> * `docker compose --env-file .env.local up`, `build` を押下したとき
>     * `.env` で定義された環境変数が `compose.yaml` の中で **使える | 使えない**
>     * `.env.local` で定義された環境変数が **Dockerfile | compose.yaml** の中で使える

<details><summary>答え</summary>

* 1
* 使えない
* `compose.yaml`

</details>







## おわりに

ありがとうございました。


* 参考
    * [英語 Docker Compose における環境変数の優先順位 - Docker Docs](https://docs.docker.com/compose/environment-variables/envvars-precedence/)