pyてよn日記

一寸先は闇が人生

Dockerfile:環境変数の定義とその周辺

 Dockerfile における環境変数の定義とその周辺に関する tips をまとめた.参考は公式リファレンスの以下の部分.

1. Dockerfile における環境変数の定義

 Dockerfile では,ENV statement によりビルド時の環境変数を定義できる.ENV により環境変数が定義されれば,その行以降のコマンドにおいて定義した環境変数にアクセスできるようになる.

 また,Dockerfile 内で定義される環境変数は,ビルド時の環境変数,つまりビルドイメージにおける環境変数であり,コンテナ環境においてもその環境変数は持続される.イメージのビルド後,docker inspect でそのイメージで定義されている環境変数を見ることができる.

 一度に定義できる環境変数の数は,空白区切りの場合 1 つ,= を使う場合複数である.クオーテーション('")はエスケープされない場合除去される.

# 空白区切り
ENV [variable-name] [value]
# `=` を使用
ENV [variable-name]=[value]
ENV [var1]=[value1] [var2]=[value2] ...
  • 空白区切りの例

 1 つ目のスペース(環境変数名の後のスペース)以降は全て value として扱われる(スペースも含めて).

# 2 つの myName は等価
ENV myName "John Doe"
ENV myName John Doe

# 2 つの myDog は等価
ENV myDog "Rex The Dog"
ENV myDog Rex The Dog

ENV myCat fluffy
  • = を使う例

 文字列にスペースを入れたい場合,スペースの前に \(バックスラッシュ)を入れる必要がある(行末の \ は line-continuation 記号であるため注意).

# 2 つの myName は等価
ENV myName="John Doe" \
    myName=John\ Doe

# 2 つの myDog は等価
ENV myDog=Rex\ The\ Dog \
    myDog="Rex The Dog"

ENV myCat=fluffy

2. 定義した環境変数へのアクセス

  • 定義した環境変数へのアクセス

    • $variable_name
    • ${variable_name}
  • 注意点

    • 上記二つの意味は同じだが,中括弧による syntax(brace syntax)は文字列内に環境変数を組み込むときに利用できる.
      • 文字列内に組み込む:${variable_name}_bar
      • ex) ENV foo /hoge -> ${foo}_bar = /hoge_bar
    • Dockerfile では,$特殊文字として扱われるため,文字そのものを使いたい場合はエスケープする必要がある(\$).
  • 定義した環境変数へアクセスできる statement 一覧

    • ADD
    • COPY
    • ENV
    • EXPOSE
    • FROM
    • LABEL
    • STOPSIGNAL
    • USER
    • VOLUME
    • WORKDIR
    • ONBUILD(when combined with one of the supported instructions above)

3. 環境変数を利用してイメージをビルドする例

 簡単な例を以下に示す.'/bar' という文字列を格納する環境変数 foo を定義している(コメントは変数を展開したもの).

FROM busybox
ENV foo /bar

# 環境変数にアクセス
WORKDIR ${foo}
ADD . $foo
COPY \$foo /quux
# WORKDIR /bar
# ADD . /bar
# COPY $foo /quux  エスケープ

注意点

環境変数の持続性による副作用

 Dockerfile 内で定義した環境変数はコンテナ環境でも持続すると前述したが,これは思わぬ副作用を生み得る.例えば,ENV DEBIAN_FRONTEND noninteractive が挙げられる.これは,Debian 系 OS におけるパッケージインストール時のインタラクティブ操作(確認ダイアログ)の非表示設定である.

 環境変数による副作用を起こさないようにするには,

  • RUN <variable-name>=<value> <command>

により一時的な環境変数を利用するのが良い(参考:bashで環境変数をexportせずにシェルスクリプトを実行したい場合はコマンドの前に記述することで代替できる - コード日進月歩).これならばコンテナ環境の環境変数に反映されずにそのコマンド内で副作用が収まる.

ホスト(ローカル)の環境変数と Dockerfile の環境変数は異なる

 基本事項の確認ではあるが,Dockerfile における「環境変数」とは,ビルド時(イメージ,コンテナ環境)の環境変数である.ホストの環境変数とは異なるものである.

 例えば,Dockerfile 内でコマンドサーチパスの環境変数 $PATH にアクセスした場合,(ローカルではなく)コンテナ環境での $PATH にアクセスする.

環境変数に関する tips

 Dockerfile の環境変数に関する tips をいくつか挙げた.

インストールしたソフトウェア,パッケージをコマンドサーチパスに追加

 コマンドサーチパスは所謂「パスを通す」の「パス」のこと.RUN でインストールしたソフトウェア,パッケージを使用する際,それをパスに追加していないと当然 command not found エラーが起きる.この場合,RUN を実行する前にパスを通しておく必要がある

 Dockerfile でパスを通すには ENV を使うRUN export PATH=$PATH:/usr/... だと上手くいかないらしい).例えば,jruby を使用するためには以下のようにパスを通す必要がある.

# パスを通す
ENV PATH $PATH:/usr/local/jruby/bin
RUN jgem install hoge

Python で自作ライブラリにパスを通す

 Python では,import [library] によりソースコード中でライブラリを使えるようにするが,import 文の実行時には(シェルの PATH のように)PYTHONPATH という環境変数Python パッケージのサーチパス)を参照しライブラリを探す.

 pip でインストールしたライブラリは PYTHONPATH に含まれるディレクトリにデフォルトでインストールされるため問題ないが,自作ライブラリを import する場合は自分で PYTHONPATHディレクトリを追加する必要がある.以下に例を示す.

  • example

 ローカルの src/lib/ からビルドイメージの /app/src/lib へライブラリのディレクトリを追加し,そのディレクトリに PYTHONPATH を通す.

ADD ./src/lib /app/src/lib
ENV PYTHONPATH /app/src/lib

 これを実行しておけば,コンテナ環境で sys.path.append などを行わずに import [自作ライブラリ] が実行できるようになる.

参考記事:Docker で環境変数をホスト OS 側からゲスト OS 側(コンテナ)に渡す方法

qiita.com

 本記事とは趣旨が少し異なるが,いずれ必要になりそうなのでメモ.

 Dockerfile に限らず,ホスト OS 側から Docker コンテナ内のアプリケーション,スクリプト環境変数を渡す方法はいくつかある.渡したいものとしては,特定の API へのアクセストークン,SSH の鍵,各種パスワード?などを想定する.

 以下の 5 つのコマンド,ファイルを経由してローカル環境からコンテナ環境へ環境変数を渡すことができる.詳細は参考記事を参照.

  • docker run
  • docker build
  • Dockerfile ファイル
  • docker-compose run
  • docker-compose.yml ファイル