Dockerfile により、ベースとなるイメージを元に必要なパッケージやファイルをインストールし、新たなイメージを作成する作業を自動化することができます。下記の例では、centos:7 イメージをベースとして、Apache (httpd) をインストールし、新たなイメージを作成します。
# mkdir ./work # cd ./work # cat > Dockerfile <<EOF FROM centos:7 RUN yum install -y httpd CMD ["/usr/sbin/httpd", "-DFOREGROUND"] EOF # docker build -t my-app:latest . # docker images
Dockerfile では以下のコマンドを使用できます。
ベースとなるイメージを指定します。Dockerfile の先頭に必ず必要です。
FROM centos:7
タグを省略すると :latest が指定されたとみなします。
FROM centos
タグの代わりに @ でダイジェストを指定することもできます。ダイジェストは docker images --digests で表示されます。
FROM centos@sha256:a799dd8a2ded4a83484bbae769d97655392b3f86533ceb7dd96bbac929809f3c
ビルド時に実行するコマンドを指定します。
RUN yum install -y httpd
コマンドの呼び出しは 「シェル形式」 と 「exec形式」 の2つの形式があります。シェル形式の場合は /bin/sh -c (Windows では cmd /S /C) にコマンド文字列が渡され、echo などのシェルコマンドの実行や、環境変数の展開などが可能となります。exec形式は直接そのコマンドが実行されます。
RUN yum install -y httpd シェル形式 RUN ["yum", "install", "-y", "httpd"] exec形式
exec形式でバックスラッシュ(\)を使用する際は二重に記述する必要があります。
RUN ["C:\\windows\\system32\\tasklist.exe"]
RUN が実行される度にイメージのレイヤが増えるため、コマンドを && や ; で連結し、複数のコマンドをひとつの RUN にまとめて記述することが推奨されています。(最近の Docker では無理に連結しなくても後でレイヤを削減できるとも聞いたのですが未調査)
RUN yum update -y && \ yum install -y httpd && \ wget http://download.exeample.com/centos7/app-1.2.3.tar.gz
docker run 時に実行するコマンド、または docker run 時に実行する ENTRYPOINT コマンドの引数を指定します。CMD もまた、シェル形式と exec形式があります。シェル形式の場合、シェル機能を利用できる反面、PID=1 のプロセスが /bin/sh -c となり、docker stop を行っても SIGTERM を受け取るのは /bin/sh となり、コマンドがシグナルを受け取ることができないデメリットがあります。
CMD ["/usr/sbin/httpd", "-DGOREGROUND"] exec形式(推奨) CMD /usr/sbin/httpd -DFOREGROUND シェル形式 CMD ["param1", "param2"] ENTRYPOINT の引数
docker run 時に実行するコマンドをシェル形式、またはexec形式で指定します。CMD と似てますが、「--entrypoint オプション > ENTRYPOINT > run引数 > CMD」の優先度があります。
ENTRYPOINT ["/bin/cmd", "arg1", "arg2"] exec形式 ENTRYPOINT /bin/cmd arg1 arg2 シェル形式
ENTRYPOINT と CMD が exec形式で指定された場合、docker run を引数無しで実行すると ENTRYPOINT+CMD が、引数有りで実行すると ENTRYPOINT+run引数が実行されます。
ENTRYPOINT ["/bin/cmd", "arg1", "arg2"] CMD ["arg3", "arg4"]
# docker run image1 /bin/cmd arg1 arg2 arg3 arg4 が実行される # docker run image1 arg5 arg6 /bin/cmd arg1 arg2 arg5 arg6 が実行される
CMD のみの場合は、CMD の第一引数がコマンドとみなされます。docker run の引数により上書きされます。
CMD ["/bin/cmd", "arg1", "arg2"]
# docker run image1 /bin/cmd arg1 arg2 が実行される # docker run image1 /bin/cmd2 arg3 arg4 /bin/cmd2 arg3 arg4 が実行される
ENTRYPOINT のみの場合は、ENTRYPOINT+run引数が実行されます。
ENTRYPOINT ["/bin/cmd", "arg1", "arg2"]
# docker run image1 /bin/cmd arg1 arg2 が実行される # docker run image1 arg3 arg4 /bin/cmd arg1 arg2 arg3 arg4 が実行される
アルゴリズムとしては、① --entrypoint オプションが指定されていれば、--entrypoint オプション値で ENTRYPOINT 配列を置換する。② docker run に引数が指定されていれば、run引数で CMD 配列を置換する。③ ENTRYPOINT 配列に CMD 配列をアペンドする。④ できあがった配列をコマンド+引数として実行する。といった流れになります。
イメージの作者を指定します。
MAINTAINER yamada <yamada@example.com>
Docker 1.13 以降は MAINTAINER は非推奨となり、代わりに LABEL を使用することが推奨されています。
LABEL maintainer="yamada <yamada@example.com>
イメージに、ベンダ名、作者名、バージョン情報などのラベル情報(メタデータ)を設定します。
LABEL com.example.vendor="ACME Incorporated" LABEL com.example.label-with-value="foo" LABEL version="1.0"
LABEL を呼び出すたびにイメージのレイヤが増えるため、ひとつにまとめて設定することが推奨されています。
LABEL com.example.vendor="ACME Incorporated" \ com.example.label-with-value="foo" \ version="1.0"
指定したポート番号をコンテナが公開することを Docker に伝えます。
EXPOSE 80
環境変数を指定します。レイヤが増えないように可能な限り1行で記述します。
ENV DB_HOST="192.168.2.201" \ DB_PORT="3306" \ DB_USER="myapp" \ DB_PASSWD="ZbGc7#adG87GBfVC" \ DB_DATABASE="sample"
Dockerfile 内で使用できる変数を指定します。ENV による環境変数がコマンドやコマンドのサブプロセスに引き継がれるのに対し、ARG による変数は Dockerfile の中のみで使用できます。
ARG user=unknown
RUN echo $user => unknwon
docker build の --build-arg オプションで値を指定することも可能です。この場合、unknown は、--build-arg オプションが指定されなかった場合のデフォルト値になります。
# docker build -t myapp --build-arg user=tanaka .
ARG user=unknown
RUN echo $user => tanaka
ホストからコンテナイメージにファイルやディレクトリをコピーします。
COPY ./file1.conf /etc/file .conf ファイルをファイルにコピー COPY ./file2.conf /etc ファイルをディレクトリ配下にコピー COPY ./my-app /opt/my-app ディレクトリをディレクトリにコピー
ホストからコンテナイメージにファイルやディレクトリをコピーします。
ADD ./file1.conf /etc/file1.conf ファイルをファイルにコピー ADD ./file2.conf /etc ファイルをディレクトリ配下にコピー ADD ./my-app /opt/my-app ディレクトリをディレクトリにコピー
COPY とは異なり、転送元に .tar.gz などの圧縮ファイルを指定すると自動的に展開してコピーすることができます。また、http:// や https:// で始まる URL を指定することもできます。
ADD ./my-app.tar.gz /opt ADD http://www.example.com/file1.txt /etc/file1.txt
コンテナ起動時に永続ボリュームを割り当てます。永続ボリュームはホスト側の /var/lib/docker/volumes などに作成されます。docker run の -v オプションでは 「-v ボリューム名:マウントポイント」 でボリューム名を指定することができましたが、VOLUME ではマウントポイントしか指定することはできず、名前付きボリュームを割り当てることはできません。VOLUME でマウントしたボリュームは、df コマンドに -a オプションをつけないと表示されないことがあります。
VOLUME /var/disk1 /var/disk2 /var/disk3
RUN, CMD, ENTRYPOINT, docker run, exec で実行するコンテナプロセスの実行ユーザをユーザIDまたはユーザ名で指定します。
USER apache CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
RUN, CMD, ENTRYPOINT 等をシェル形式で記述する際に使用されるシェルを指定します。デフォルトは、Linux の場合 ["/bin/sh", "-c"]、Windows の場合 ["cmd", "/S", "/C"] となります。
SHELL ["powershell", "-command"] RUN Write-Host hello
RUN, CMD, ENTRYPOINT, COPY, ADD, docker run, exec で実行するコンテナプロセスのワークディレクトリを指定します。
WORKDIR /tmp
複数記述すると直前の WORKDIR が有効となります。
WORKDIR /tmp RUN pwd /tmp WORKDIR /var RUN pwd /var
環境変数を展開することもできます。
ENV BASE_DIR=/opt/myapp WORKDIR $BASE_DIR/tmp
作成したイメージをベースに、さらに別のイメージをビルドする際に実行するコマンドを指定します。コマンドには、RUN や COPY など、Dockerfile で使用可能なコマンドを指定します。最低限必要なベースイメージを用意し、評価環境用、本番環境用それぞれのサブイメージを作成する際に便利です。まずは、下記の Dockerfile から myapp イメージを作成します。
FROM centos:7 ONBUILD RUN echo "This is onbuild message." CMD ["/bin/bash"]
# docker build -t myapp:latest .
さらに、下記の Dockerfile から myapp2 イメージをビルドすると、ビルドした時点で ONBUILD に指定したコマンドが実行されます。
FROM myapp:latest CMD ["/bin/bash"]
# docker build -t myapp2:latest . Sending build context to Docker daemon 2.048kB Step 1/2 : FROM myapp:latest # Executing 1 build trigger ---> Running in 52814619c700 This is onbuild message. Removing intermediate container 52814619c700 ---> 76b3c36312f7 Step 2/2 : CMD ["/bin/bash"] ---> Running in f6a6cb3745de Removing intermediate container f6a6cb3745de ---> d1680fc167bf Successfully built d1680fc167bf Successfully tagged myapp2:latest
docker stop を実行した際にコンテナプロセスに送信されるシグナルを指定します。下記を記述しておくと、docker stop を実行した際に SIGTERM の代わりに SIGINT が送られるようになります。
STOPSIGNAL SIGINT
コンテナ内で定期的にヘルスチェックコマンドを実行し、コンテナの稼働状況を監視します。オプションには --interval=インターバル(デフォルト:30s)、--timeout=タイムアウト時間(デフォルト:30s)、--retries=リトライ回数(デフォルト:3) を指定できます。
FROM centos:7 RUN yum install -y httpd RUN echo '<h1>OK</h1>' > /var/www/html/index.html HEALTHCHECK --interval=10s --timeout=5s CMD curl -sf http://localhost/ || exit 1 CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
# docker build -t myapp . # docker run -d --name cont1 myapp # docker inspect cont1
上記のヘルスチェックを仕込んだコンテナを起動すると、インターバル毎にヘルスチェックコマンドを実行します。実行結果は docker inspect で確認できます。
# docker inspect cont1 (略) "Health": { "Status": "healthy", "FailingStreak": 0, "Log": [ { "Start": "2019-09-04T20:08:18.820425313+09:00", "End": "2019-09-04T20:08:19.245683023+09:00", "ExitCode": 0, "Output": "<h1>OK</h1>\n" }, ] }