2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Docker と Docker Compose の環境変数 - Part 1. ARG と ENV

Last updated at Posted at 2024-04-29

はじめに

1. Docker インストラクション

  • ENV
    • 一度設定すれば以降は使える
  • ARG
    • 一度設定すれば以降は使える、ただし CMD, ENTRYPOINT を除く
  • RUN export, RUN source
    • 設定した時だけ使える
インストラクションってなに?

公式ドキュメントで Dockerfile 内に書く ARG, ENV, RUN などを総称してインストラクション, instruction と表記していました。


2. Linux コマンド

  1. docker image build
    1. キーバリュー指定
      • --build-arg
    2. ファイル指定
      • ない
  2. docker container run
    1. キーバリュー指定
      • --env
    2. ファイル指定
      • --env-file

◯ サンプルコード

ディレクトリの名前と問題が対応しています

gh repo clone domodomodomo/docker-env-sample
cd docker-env-sample/part1/1

# for Bash - macOS, Ubuntu
bash cmd.sh

# for PowerShell - Windows
powershell ./cmd.ps1

問題 1 - Docker インストラクション

◯ 設問

echo コマンド の実行結果 A, B, C にはそれぞれ何が表示されますか?

Dockerfile
FROM debian:12.5-slim

ARG BLUE
ARG RED="Charmander"

# 1. RUN export
RUN export GREEN="Bulbasaur" && \
    echo "'${BLUE}' | '${RED}' | '${GREEN}'"
#
# A
#


# 2. ARG
RUN export GREEN="Bulbasaur"
RUN echo "'${BLUE}' | '${RED}' | '${GREEN}'"
#
# B
#


# 3. ENV
ENV BLUE="Squirtle"
CMD echo "'${BLUE}' | '${RED}' | '${GREEN}'"
#
# C
#
docker image build --build-arg BLUE="Squirtle" --tag app --progress=plain --no-cache .
# --progress=plain 
#     これが無いと RUN echo コマンドが表示されなくなる
# 
# --no-cache
#     これが無いと 1 回目の実行結果がキャッシュされて
#     2 回目、3 回目コマンドを打ったときにRUN echo が実行されなくなる

docker container run app

◯ 選択

1. 
   'Squirtle' | '' | ''
    
2. 
   'Squirtle' | 'Charmander' | ''

3.
   'Squirtle' | 'Charmander' | 'Bulbasaur'

◯ 解答

解答
Dockerfile
FROM debian:12.5-slim

ARG BLUE
ARG RED="Charmander"



# 1. RUN export
RUN export GREEN="Bulbasaur" \
    && echo "'${BLUE}' | '${RED}' | '${GREEN}'"
#
# 'Squirtle' | 'Charmander' | 'Bulbasaur'
#



# 2. ARG
RUN export GREEN="Bulbasaur"
RUN echo "'${BLUE}' | '${RED}' | '${GREEN}'"
#
# 'Squirtle' | 'Charmander' | ''
#
#   GREEN is not saved as an environment variable
#   Each RUN command has a different shell session



# 3. ENV
ENV BLUE="Squirtle"
CMD echo "'${BLUE}' | '${RED}' | '${GREEN}'"
#
# 'Squirtle' | '' | ''
#
#   RED is not saved as an environment variable
#   Environment variables set by ARG command are not applied to CMD

◯ シェルセッション

詳細
  • Docker は RUN コマンドごとにシェルセッションがわかれているらしいです
    • 根拠となる公式ドキュメントは見つけられませんでした...
  • なので RUN export しても次の RUN では忘れられてしまう
  • COPY, ADD はわかるけど ENV, ARG はなんでわざわざ別にあるんだろう?🤔って思ってたのですが、そういうことだったんですね...
Docker インストラクション Linux コマンド
ENV, ARG export, source
WORKDIR cd
USER su
SHELL sh, bash

◯ ARG とキャッシュ

詳細

ARG で定義した環境変数が同じ場合、キャッシュが使われます。サンプルコードで --no-cache を指定したのはこの挙動を避けるためです。

Dockerfile で定義された ARG 変数の値が前回のビルドと異なる場合、その値が最初に使用されたときに「キャッシュミス」が発生します(定義されたときではありません)。
If a Dockerfile defines an ARG variable whose value is different from a previous build, then a "cache miss" occurs upon its first usage, not its definition.
Impact on build caching - Docker Docs

ARG を直接使わない RUN にもキャッシュミスを起こすので、ARG は使用する RUN の直前で書いたほうが良い。
DockerfileARG はビルドキャッシュにどう影響するのか、どこに書くべきなのか - Akashic Records


◯ 疑問

プロンプト

ChatGPT 4o 先生に質問したところそれっぽい答えを返してくれますが理解はできませんでした。ChatGPT 10 の登場を待ちたいと思います。

プロンプト
# 疑問 1. なぜ `ENV` コマンドがあるのですか?

1. なぜ Dcoker はシェルセッションを `RUN` コマンドごとにわけたのですか?
2. もし Docker に `ENV` コマンドが存在せず、
   `RUN` コマンドごとにシェルセッションが別れておらず、
   一度 `RUN export` すると以降その環境変数が参照できるような場合、
   どのような不都合が生じますか?
プロンプト
# 疑問 2. なぜ `ARG` コマンドがあるのですか?

1. なぜ `ARG` で設定された環境変数は `CMD` では参照できないようになっているのですか?
2. もし Docker に `ARG` コマンドが存在せず `--build-arg` で指定した値が
   そのまま `ENV` で指定された環境変数に代入される場合、どのような不都合が生じますか?
プロンプト
# 疑問 3. `ENV` や `ARG` で設定された環境変数はどこで保存されていますか?

1. Docker イメージが持つメタ情報
   * `RUN` コマンドが実行される度に
     Docker が OS のシェルセッションに環境変数と値を書き込む
2. Docker イメージが持つ OS
   * `RUN` コマンドが実行される度に
     OS が OS のシェルセッションに環境変数と値を書き込む

場所は可能な限り **具体的に** 教えてください。

問題 2 - Linux コマンド

◯ 設問

Docker コンテナのみに環境変数を書き込み Docker イメージに環境変数を残さない方法として誤っているものは A, B, C のうちどれですか?

Dockerfile
FROM debian:12.5-slim

# A ENV GREEN="Bulbasaur"
ENV GREEN="Bulbasaur"

RUN echo "'${BLUE}' | '${RED}' | '${GREEN}'"

CMD echo "'${BLUE}' | '${RED}' | '${GREEN}'"
.env.local
RED=Charmander
コマンド
PowerShell - Windows
cmd.ps1
docker image build `
    --tag app `
    --progress=plain `
    --no-cache `
    .

# Docker イメージの環境変数を表示
docker image inspect app `
    --format '{{range .Config.Env}}{{println .}}{{end}}'

# B --env BLUE=Bulbasau
# C --env-file .env.local
docker container run `
    --env BLUE=Bulbasaur `
    --env-file .env.local `
    --name app `
    app

# Docker コンテナの環境変数を表示
docker container inspect app `
    --format '{{range .Config.Env}}{{println .}}{{end}}'

docker container rm app
bash - macOS, Ubuntu
cmd.bash
#!/bin/bash


docker image build \
    --tag app \
    --progress=plain \
    --no-cache \
    .

# Docker イメージの環境変数を表示
docker image inspect app \
    --format '{{range .Config.Env}}{{println .}}{{end}}'

# B --env BLUE=Bulbasau
# C --env-file .env.local
docker container run \
    --env BLUE=Bulbasaur \
    --env-file .env.local \
    --name app \
    app

# Docker コンテナの環境変数を表示
docker container inspect app \
    --format '{{range .Config.Env}}{{println .}}{{end}}'

docker container rm app

◯ 解答

解答

A


セキュリティ

ビルド時にパスワードなどの機密情報を取り扱う際、

環境変数

ではなく

ファイル

を通してやり取りしてくださいという記述が見られます。まだ整理できていません...orz がとり急ぎ大事そうな記事を列挙させていただきます。

  • "環境変数の方法" より推奨される "ファイルの方法" による機密情報の受け渡し方法
    • Docker
      • RUN --mount=type=secret オプション
    • Docker Compse
      • secrets プロパティ

◯ Docker

シークレット(ユーザー資格情報、APIトークンなど)を渡すためにビルド引数(訳注: --build-arg)を使用することは推奨されません。ビルド引数は docker history コマンドで見える ... (中略) ... Docker イメージをビルドする際にシークレットを安全に使用する方法については、RUN --mount=type=secret セクションを参照してください。
It isn't recommended to use build arguments for passing secrets such as user credentials, API tokens, etc. Build arguments are visible in the docker history command and ... (omitted) ... Refer to the RUN --mount=type=secret section to learn about secure ways to use secrets when building images.

ARG - Docker Docs

◯ Docker Compose

Diogo Monicaの記事では、環境変数で秘密情報を扱う問題点として

  • 環境はプロセスで暗黙的に利用可能のため、アクセスや利用を追跡することが困難である。
  • アプリケーションが環境をデバッグやエラー報告のために出力することはよくある。
  • 環境変数は子プロセスに引き継がれるため、意図しないアクセスが可能になる。これは、最小権限の原則を破る。
  • アプリケーションがクラッシュした時、デバッグのために、環境変数をログファイルに保存することは一般的であり、これはディスク上に平文の秘密情報があることを意味する。
  • 環境変数に秘密情報を入れると、それはすぐにtribal knowledgeになる。特定の環境変数がデリケートをであると認識していない新人のエンジニアは、適切に処理できない。

Docker Composeの環境変数ではなくsecretsで秘密情報を扱う - Qiita

おわりに

◯ シリーズ

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

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?