Dockerfileについての簡単なまとめ
サイトを参考にしつつlaravelの開発環境を準備していて、Dockerfileの中身について分からないのでスッキリしませんでしたので、調べて自分なりに簡単にまとめてみました。
下記の公式ドキュメントを参照しました。
参考として公式ドキュメントから下記内容のDockerfileを引用します。
# Nginx
#
# VERSION 0.0.1
FROM ubuntu
LABEL Description="This image is used to start the foobar executable" Vendor="ACME Products" Version="1.0"
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
# はコメントです。
FROM
Dockerfileの始めに書かないといけない重要なinstruction。
使用するBase imageを書く。
FROM ubuntuとすることで、ubuntuをベースにして、詳細を設定する感じ。
ARG
FROMに先行して書くことができる唯一のinstruction(上記Dockerfile例には載ってないけど)で変数。FROMよりも前に書くことで、build stageの外側からFROMの中身であるbuild stageに対して設定ができる。設定するには、FROMの中にARGを書き、変数名だけ書く。下記参照。
# ARGの使用例
ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version
FROMの下にARGは何個でも設定できる。コマンドラインからdocker buildコマンドを行うときに連携する。
--build-arg <varname>=<value>のようにコマンドを実行する。
Dockerfileに上記コマンドで指定したARGが定義されていない場合warningが出る。
DockerfileにARGのデフォルト値を設定できる
ARG user1=someuser
docker buildで値をなしにすると、デフォルト値が使われる。
ARGのスコープ
Dockerfileに書いたARGから影響を受ける。コマンドラインで書いた値ではなく。
// Dockerfile
FROM busybox
USER ${user:-some_user}
ARG user
USER $user
# ...
上記のDockerfileの状態で下記コマンドを実行
$ docker build --build-arg user=what_user .
Dockerfile2行目のオブジェクトのuserの値は3行目のARG userの値が参照される。ARG userは空なので、2行目のuserの値は空になる。
また、コマンドからDockerfileに渡されるwhat_userという値は、4行目の$userに渡される。$user=what_userになる。でも2行目のARG userの値が優先されるので、結果として4行目のUSER $userの値も空となる。
ARGはENVよりも優先度が低い
ARGとENVで同じ項目があった場合、RUNではENVの値の方が優先して使用される。
また、ENVの方はbuild imageにおいて永続性があるので、一度Dockerfileに書いておけば、ARGのようにいちいち--build-arg flagを使わなくてもよく、docker buildするだけでいい。
ARGは事前に定義された変数がある
HTTP_PROXY
http_proxy
HTTPS_PROXY
https_proxy
FTP_PROXY
ftp_proxy
NO_PROXY
no_proxy
上記の変数は、Dockerfileに書かなくても、--build-arg <varname>=<value>とコマンドラインでflagを使うだけで使える。
上記の変数は、docker historyコマンドで見ても見れないようになっている。情報の不意なリークを防止するため。もしこの挙動を変えたい場合は、DockerfileにARG HTTP_PROXYのように追加したら、この値はdocker historyに保存されるようになる。
例)
FROM ubuntu
ARG HTTP_PROXY
RUN echo "Hello World"
Buildkitを使うときだけ使える、事前に定義されたARGの変数がある
この辺はまだ使いそうにないので、また使いそうになったら追記します。
LABEL
LABELでイメージにメタデータを追加できる。
key-valueのペアで使う。
LABEL version="1.0"
MAINTAINERというメタデータauthor情報をセットできるinstructionもあるが、docker inspectコマンドを使うことでLABELの方がメタデータを簡単に確認できるので、LABELとセットで使うのが推奨されている。
この場合は下記のように書く。
LABEL maintainer="your name"
ENV
ENV instructionは環境変数をセットできる。
imageのビルド時に使われる。
書き方は2通りある。
ENV <key> <value>
ENV <key>=<value> ...
最初のは単一の環境変数をセットするとき。
2番目のは、ひとつのENV宣言で続けていくつも環境変数を書いていくときに使う。
環境変数の値にスペースを含むときは、ダブルクォーテーションかバックスラッシュ+スペースを使う。
ENV myName="Hoge Foo" myCat=Rex\ The\ Cat \
myHat=fluffy
Dockerfileの見やすさからも、普通は、一つのENV宣言に一つの環境変数をセットする下記のような書き方が良いのではと僕は感じました。
ENV myName Hoge Foo
ENV myCat Rex The Cat
ENVにセットした環境変数は、docker inspectコマンドで確認できる。値の変更は、下記のコマンドでできる。
docker run --env <key>=<value>
RUN
この宣言の中にimageを作る一連のコマンドを書いておくことで、自動的にimageが作成されるようにする。
書き方は2通りある。shell formとexec form。
shell formの書き方は下記。linuxの場合、/bin/sh -cを使ってRUN内に書いたコマンドが実行される。
RUN <command>
exec formの書き方は下記。
RUN ["executable", "param1", "param2"]
exec formだと、配列に書いた中身の方法で直接実行される感じ。
shell formだと、shellというプログラムを挟んで中身が実行される感じ。
例)
RUNの中身が、「powershellで○○コマンドを実行する」の場合
shell formだと、/bin/sh -cでシェルを経由してpowershellのコマンドを実行する。
exec formだと、shell formのようにシェルを使わず、直接powershellが起動しコマンドを実行する。配列の中に書いた方法で直接実行されるということです。
exec formだと、shell formに比べてシェルに依存しないので、shellでしか通用しない文字列を使うことに起因するエラーなど防げるといった利点があるみたいです。
exec formは理解しにくかったのでググりました。下記の記事でピンときて理解できたので、分かりやすかったと思います。
続きはまた追記していきます。