How to Write DockerFile
DockerFile
の書き方が毎回わからなくなるので書き方をまとめておく。
公式 reference はこちら[1]。
Format
DockerFile
は基本的に以下の構文を取る。
# Comment
INSTRUCTION arguments
- comment について
#
で始まる行は (parser directive でない限り) comment と認識され build 前に取り除かれるため、例えばRUN
コマンド中の間の行に comment が存在したとしても問題ない。また、行途中の#
は全て argument として認識される。 - whitespace について
comment や instruction 前の whitespace は無視されるためDockerFile
の実行に影響はないが、可読性などの観点から推奨されない。
INSTRUCTIONS
以下、主要な instruction について説明する。
Instruction は case-insensitive だが、convention として UPPERCASE で記述する。
FROM
全ての DockerFile
は FROM
句から始まらなければならない。
FROM [--platform=<platform>] <image>[:<tag>/@<digest>] [AS <name>]
-
AS name
で build に名前を付与できる (multi-stage build などで利用できる) -
tag
ordigest
で使用する image を指定できる (default では tag はlatest
になる) -
--platform
はFROM
で参照する repository が対応している platform (linux/amd64
,linux/arm64
など) を指定できる
multi-stage build について
1 つの DockerFile
に複数の FROM
句を書くこともでき、multi-stage build と呼ばれる。
開発環境に必要な package などは実行環境には必要ない場合が多いので、開発環境用の image を構築して必要なもの build した後、新たに軽量な実行用 image を構築することで最終的な image を軽量化するためによく用いられる。
RUN
image の作成で任意のコマンドを実行したいときに用いる。
# shell form
RUN <command>
# exec form
RUN ["executable", "param1", "param2"]
Shell form は SHELL
instruction で指定される shell (Linux の default は /bin/sh -c
) で実行されるコマンドを記述する。
一方、exec form では shell を起動することなく executable
を実行できる。ただし、exec form の入力は JSON として parse されるため、"
でくくることや \
を escape するなどの注意が必要である。
SHELL instruction について
以下のようにして shell form で使用する default shell を変更できる。
SHELL ["executable", "parameters"]
CMD / ENTRYPOINT
CMD
と ENTRYPOINT
はどちらもコンテナ起動時に一度のみ実行されるコマンドを指定する instruction である (従って最後に記述されたものしか意味がない) 。
CMD
-
CMD ["executable","param1","param2"]
(exec form : preferred) -
CMD ["param1","param2"]
(as default parameters to ENTRYPOINT) -
CMD command param1 param2
(shell form)
ENTRYPOINT
-
ENTRYPOINT ["executable", "param1", "param2"]
(exec form) -
ENTRYPOINT command param1 param2
(shell form)
CMD
と ENTRYPOINT
の違いは CMD は ENTRYPOINT で指定されたコマンドの default 引数を設定できるという点である。
ただし、その際はどちらも exec form でなければならず、shell form で ENTRYPOINT
を記述した場合、全ての CMD
instruction は無視される。
詳しくは Understand how CMD and ENTRYPOINT interact も参照のこと。
ARG / ENV
DockerFile
内や container 内で使用する変数を定義する際に用いる。
ARG
と ENV
の違いは ENV は image 内で環境変数として使われるということである。
そのため、DockerFile
内のみの変数を場合は ARG
を使うのが良い。
# ENV
ENV <key>=<value> ...
# ARG
ARG <name>[=<default value>]
ARG の FROM 前での使用について
ARG
instruction は唯一 (1 回目の) FROM
の前に挿入して FROM
句に対する parameter として使える。
ただし、その場合の ARG
は build stage の外なので、FROM
より後ろで設定した parameter を使いたい場合はもう一度 ARG
で呼び出す必要がある。
ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version
ADD / COPY
どちらも既存のファイルなどをコピーして image に追加する instruction であるが、違いは ADD は圧縮ファイルの展開やリモート URL のサポートがあることである。
従って、ローカルの圧縮ファイルの展開をしたいのであれば ADD
を使うのが良いが、それ以外は基本的には COPY
を使うのが良い[2]。
# ADD
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
# COPY
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
上の instruction はそれぞれ <src>
を <dest>
に追加する。
相対 path で指定した場合、それぞれの parent directory は build context と WORKDIR
である。
WORKDIR について
RUN
, CMD
, ENTRYPOINT
, COPY
, ADD
などで使用する working directory を指定する instruction である。
相対 path が入力された場合、WORKDIR
が parent directory となる。
WORKDIR /path/to/workdir
EXPOSE
Container 外との通信を設定したいときは EXPOSE
instruction を使う。
Docker に container の listen port を教えることで host との通信 (TCP or UDP) を可能にする。
EXPOSE <port> [<port>/<protocol>...]
LABEL
LABEL
instruction は、作成する image に以下の形式で metadata を付与できる。
LABEL <key>=<value> <key>=<value> <key>=<value> ...
Parser Directive
#directive=value
の形で DockerFile
の先頭に記述する。
必須のものではないので、必要になったときに調べて再度追記する。
Discussion