Dockerfileメモ
ベースイメージ
- debian
- Dockerfileのベストプラクティスで推奨されているイメージ
- busybox
- 組込用途で作られたもの。非常に小さい。
- alpine
- busybox同様、非常に小さいイメージ。パッケージマネージャ付き。
コンテキスト
Dockerはビルドを行うパスのファイルをすべてDockerデーモンに送ってから、Dockerfileを元にイメージのビルドを行う。この送られるファイル群のことをコンテキストという。
例えば、RailsプロジェクトでDockerfileを作成してビルドしたとすれば、log/*.logを含むすべてのプロジェクトファイルがDockerデーモンに送られることとなる。log/*.logはイメージのビルドに必要ないし巨大なファイルになりがちで、無視できない無駄な遅延になりうる。
.dockerignoreファイルを使うと.gitignoreのようにコンテキストに含めないファイルを指定することができる。
# .dockerignore
log
Dockerfile概要
FROM ベースイメージ名 AS ビルドステージ名
# ...
FROM ベースイメージ名
ENV 設定する環境変数名 内容
ADD イメージにファイルを追加する(ADDとCOPYの違いは後述)
COPY イメージにファイルを追加する
COPY --from=nodejs /tmp/node /opt/node
WORKDIR RUNやCOPYコマンドを実行するパス
RUN シェルコマンド
ENTRYPOINT コンテナ起動時に実行するコマンド(実行時に変更不可能)
CMD コンテナ起動時に実行するコマンドあるいはENTRYPOINTの引数(実行時にdockerコマンドの引数で変更可能)
FROM
元となるベースイメージを指定する。ruby:2.7.2など。マルチステージビルドという機能で、FROM ruby:2.7.2 AS before_buildのようにすると、次のFROMが現れるまで、そのイメージでコマンドが実行される。後続のFROM内でCOPY --from=before_build /before_build内部のディレクトリ/ファイル /コピー先のディレクトリ/ファイルとすることで、ファイルをコピーすることができる。
FROM ruby:2.7.2 AS before_build
# /tmp/download_commandができる
WORKDIR /tmp
RUN curl -LO https://example.com/download_command
FROM ruby:2.7.2
# /tmp/download_commandをコピーする
COPY --from=before_build /tmp/download_command /app/bin/command
よくある使い方としては、コンパイル型言語でプログラムのビルド用のビルドステージを用意し、バイナリをコピーする使い方がある。マルチステージビルドを使うことで、コンパイラなど稼働時に不要なプログラムなどを稼働用イメージに入れずに済む。
ENV
環境変数を追加する。
ENV PATH /opt/foo/bin:$PATH
ADDとCOPY
- 指定できるファイル
- どちらもローカルファイルはDockerfileのあるディレクトリ内のファイルしか指定できない。
ADDはURLを指定してリモートのファイルを指定することができる。ADDは圧縮ファイルを展開する(らしいが、リモートのtar.xzファイルを指定したら展開されなかった)
ADDを使わずとも、ローカルファイルはCOPYでリモートファイルはRUN curl ...で代用できるためADDはあまり使われない。
COPY ["ファイル1", "ファイル2", ..., "コピー先ディレクトリ"]という形での指定もできる。
WORKDIR
COPY、RUN、CMD、ENTRYPOINTなどのコマンドを実行するディレクトリを指定する。シェルのcdコマンドと思えば良い。docker run --rm -it イメージ名 bashとした時のカレントディレクトリにもなる。
RUN
RUNコマンドの指定の仕方は2種類ある。
# シェル形式
# sh -c "echo $PATH > file1"が実行され
# イメージ内に$PATH環境変数の値が出力されたfile1ファイルが作成される
RUN echo $PATH > file1
# exec形式
# シェルを介さずに直接echo $PATH > file2が実行され
# イメージビルド時に
# $PATH > file2
# と表示される(file2は作成されない)
RUN ["echo", "$PATH", ">", "file2"]
シェル形式はsh -c "echo $PATH > file1"を実行する。exec形式はシェルを介さずに直接echo $PATH > file2を実行する。
シェル形式はシェルを用いて実行されるので環境変数$PATHが展開され、リダイレクトが解釈されるが、exec形式の場合はシェルを介さないため$PATHも>もただの文字列として処理される。
RUNコマンドの場合、exec形式はあまり使われない。
ENTRYPOINT
書式はRUNコマンドと同じ。exec形式が推奨されている。
コンテナ起動時に実行されるコマンドを指定する。docker run --rm -it イメージ名 bashのようにdockerコマンドから別のコマンドに差し替えることはできない。
FROM ruby
WORKDIR /
ENTRYPOINT ["ls"]
CMD ["-l"]
上記Dockerfileの場合、docker build -t イメージ名 .、docker run --rm イメージ名とした場合、/ディレクトリ上でls -lコマンドが実行され結果が表示される。
docker run --rm イメージ名 -tlとした場合、/ディレクトリ上でls -tlコマンドが実行され結果が表示される。
この様に、docker runコマンドなどの最後で指定するコマンドは、Dockerfile内のCMDの指定を置き換えているだけである。
CMD
書式はRUNコマンドと同じ。exec形式が推奨されている。
ENTRYPOINTコマンドが指定されている場合は、ENTRYPOINTコマンドで指定されているコマンドの引数となる。
ENTRYPOINTコマンドが指定されていない場合は、CMDコマンドの指定内容のコマンドがコンテナ起動時に実行される。