Dockerfileによるビルド

トップ > Docker > Dockerfileによるビルド

Dockerfileとは

Dockerfile により、ベースとなるイメージを元に必要なパッケージやファイルをインストールし、新たなイメージを作成する作業を自動化することができます。下記の例では、centos:7 イメージをベースとして、Apache (httpd) をインストールし、新たなイメージを作成します。

Shell
# 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 では以下のコマンドを使用できます。

FROM

ベースとなるイメージを指定します。Dockerfile の先頭に必ず必要です。

Dockerfile
FROM centos:7

タグを省略すると :latest が指定されたとみなします。

Dockerfile
FROM centos

タグの代わりに @ でダイジェストを指定することもできます。ダイジェストは docker images --digests で表示されます。

Dockerfile
FROM centos@sha256:a799dd8a2ded4a83484bbae769d97655392b3f86533ceb7dd96bbac929809f3c

RUN

ビルド時に実行するコマンドを指定します。

Dockerfile
RUN yum install -y httpd

コマンドの呼び出しは 「シェル形式」 と 「exec形式」 の2つの形式があります。シェル形式の場合は /bin/sh -c (Windows では cmd /S /C) にコマンド文字列が渡され、echo などのシェルコマンドの実行や、環境変数の展開などが可能となります。exec形式は直接そのコマンドが実行されます。

Dockerfile
RUN yum install -y httpd                シェル形式
RUN ["yum", "install", "-y", "httpd"]   exec形式

exec形式でバックスラッシュ(\)を使用する際は二重に記述する必要があります。

Dockerfile
RUN ["C:\\windows\\system32\\tasklist.exe"]

RUN が実行される度にイメージのレイヤが増えるため、コマンドを && や ; で連結し、複数のコマンドをひとつの RUN にまとめて記述することが推奨されています。(最近の Docker では無理に連結しなくても後でレイヤを削減できるとも聞いたのですが未調査)

Dockerfile
RUN yum update -y && \
    yum install -y httpd && \
    wget http://download.exeample.com/centos7/app-1.2.3.tar.gz

CMD

docker run 時に実行するコマンド、または docker run 時に実行する ENTRYPOINT コマンドの引数を指定します。CMD もまた、シェル形式と exec形式があります。シェル形式の場合、シェル機能を利用できる反面、PID=1 のプロセスが /bin/sh -c となり、docker stop を行っても SIGTERM を受け取るのは /bin/sh となり、コマンドがシグナルを受け取ることができないデメリットがあります。

Dockerfile
CMD ["/usr/sbin/httpd", "-DGOREGROUND"]    exec形式(推奨)
CMD /usr/sbin/httpd -DFOREGROUND           シェル形式
CMD ["param1", "param2"]                   ENTRYPOINT の引数

ENTRYPOINT

docker run 時に実行するコマンドをシェル形式、またはexec形式で指定します。CMD と似てますが、「--entrypoint オプション > ENTRYPOINT > run引数 > CMD」の優先度があります。

Dockerfile
ENTRYPOINT ["/bin/cmd", "arg1", "arg2"]    exec形式
ENTRYPOINT /bin/cmd arg1 arg2              シェル形式

ENTRYPOINT と CMD が exec形式で指定された場合、docker run を引数無しで実行すると ENTRYPOINT+CMD が、引数有りで実行すると ENTRYPOINT+run引数が実行されます。

Dockerfile
ENTRYPOINT ["/bin/cmd", "arg1", "arg2"]
CMD ["arg3", "arg4"]
Shell
# docker run image1                 /bin/cmd arg1 arg2 arg3 arg4 が実行される
# docker run image1 arg5 arg6       /bin/cmd arg1 arg2 arg5 arg6 が実行される

CMD のみの場合は、CMD の第一引数がコマンドとみなされます。docker run の引数により上書きされます。

Dockerfile
CMD ["/bin/cmd", "arg1", "arg2"]
Shell
# docker run image1                       /bin/cmd arg1 arg2 が実行される
# docker run image1 /bin/cmd2 arg3 arg4   /bin/cmd2 arg3 arg4 が実行される

ENTRYPOINT のみの場合は、ENTRYPOINT+run引数が実行されます。

Dockerfile
ENTRYPOINT ["/bin/cmd", "arg1", "arg2"]
Shell
# 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 (非推奨)

イメージの作者を指定します。

Dockerfile
MAINTAINER yamada <yamada@example.com>

Docker 1.13 以降は MAINTAINER は非推奨となり、代わりに LABEL を使用することが推奨されています。

Dockerfile
LABEL maintainer="yamada <yamada@example.com>

LABEL

イメージに、ベンダ名、作者名、バージョン情報などのラベル情報(メタデータ)を設定します。

Dockerfile
LABEL com.example.vendor="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"

LABEL を呼び出すたびにイメージのレイヤが増えるため、ひとつにまとめて設定することが推奨されています。

Dockerfile
LABEL com.example.vendor="ACME Incorporated" \
      com.example.label-with-value="foo" \
      version="1.0"

EXPOSE

指定したポート番号をコンテナが公開することを Docker に伝えます。

Dockerfile
EXPOSE 80

ENV

環境変数を指定します。レイヤが増えないように可能な限り1行で記述します。

Dockerfile
ENV DB_HOST="192.168.2.201" \
    DB_PORT="3306" \
    DB_USER="myapp" \
    DB_PASSWD="ZbGc7#adG87GBfVC" \
    DB_DATABASE="sample"

ARG

Dockerfile 内で使用できる変数を指定します。ENV による環境変数がコマンドやコマンドのサブプロセスに引き継がれるのに対し、ARG による変数は Dockerfile の中のみで使用できます。

Dockerfile
ARG user=unknown
RUN echo $user                 => unknwon

docker build の --build-arg オプションで値を指定することも可能です。この場合、unknown は、--build-arg オプションが指定されなかった場合のデフォルト値になります。

Shell
# docker build -t myapp --build-arg user=tanaka .

ARG user=unknown
RUN echo $user                 => tanaka

COPY

ホストからコンテナイメージにファイルやディレクトリをコピーします。

Dockerfile
COPY ./file1.conf /etc/file .conf    ファイルをファイルにコピー
COPY ./file2.conf /etc               ファイルをディレクトリ配下にコピー
COPY ./my-app /opt/my-app            ディレクトリをディレクトリにコピー

ADD

ホストからコンテナイメージにファイルやディレクトリをコピーします。

Dockerfile
ADD ./file1.conf /etc/file1.conf    ファイルをファイルにコピー
ADD ./file2.conf /etc               ファイルをディレクトリ配下にコピー
ADD ./my-app /opt/my-app            ディレクトリをディレクトリにコピー

COPY とは異なり、転送元に .tar.gz などの圧縮ファイルを指定すると自動的に展開してコピーすることができます。また、http:// や https:// で始まる URL を指定することもできます。

Dockerfile
ADD ./my-app.tar.gz /opt
ADD http://www.example.com/file1.txt /etc/file1.txt

VOLUME

コンテナ起動時に永続ボリュームを割り当てます。永続ボリュームはホスト側の /var/lib/docker/volumes などに作成されます。docker run の -v オプションでは 「-v ボリューム名:マウントポイント」 でボリューム名を指定することができましたが、VOLUME ではマウントポイントしか指定することはできず、名前付きボリュームを割り当てることはできません。VOLUME でマウントしたボリュームは、df コマンドに -a オプションをつけないと表示されないことがあります。

Dockerfile
VOLUME /var/disk1 /var/disk2 /var/disk3

USER

RUN, CMD, ENTRYPOINT, docker run, exec で実行するコンテナプロセスの実行ユーザをユーザIDまたはユーザ名で指定します。

Dockerfile
USER apache
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
SHELL

RUN, CMD, ENTRYPOINT 等をシェル形式で記述する際に使用されるシェルを指定します。デフォルトは、Linux の場合 ["/bin/sh", "-c"]、Windows の場合 ["cmd", "/S", "/C"] となります。

Dockerfile
SHELL ["powershell", "-command"]
RUN Write-Host hello

WORKDIR

RUN, CMD, ENTRYPOINT, COPY, ADD, docker run, exec で実行するコンテナプロセスのワークディレクトリを指定します。

Dockerfile
WORKDIR /tmp

複数記述すると直前の WORKDIR が有効となります。

Dockerfile
WORKDIR /tmp
RUN pwd                     /tmp
WORKDIR /var
RUN pwd                     /var

環境変数を展開することもできます。

Dockerfile
ENV BASE_DIR=/opt/myapp
WORKDIR $BASE_DIR/tmp

ONBUILD

作成したイメージをベースに、さらに別のイメージをビルドする際に実行するコマンドを指定します。コマンドには、RUN や COPY など、Dockerfile で使用可能なコマンドを指定します。最低限必要なベースイメージを用意し、評価環境用、本番環境用それぞれのサブイメージを作成する際に便利です。まずは、下記の Dockerfile から myapp イメージを作成します。

Dockerfile
FROM centos:7
ONBUILD RUN echo "This is onbuild message."
CMD ["/bin/bash"]
Shell
# docker build -t myapp:latest .

さらに、下記の Dockerfile から myapp2 イメージをビルドすると、ビルドした時点で ONBUILD に指定したコマンドが実行されます。

Dockerfile
FROM myapp:latest
CMD ["/bin/bash"]
Shell
# 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

STOPSIGNAL

docker stop を実行した際にコンテナプロセスに送信されるシグナルを指定します。下記を記述しておくと、docker stop を実行した際に SIGTERM の代わりに SIGINT が送られるようになります。

Dockerfile
STOPSIGNAL SIGINT

HEALTHCHECK

コンテナ内で定期的にヘルスチェックコマンドを実行し、コンテナの稼働状況を監視します。オプションには --interval=インターバル(デフォルト:30s)、--timeout=タイムアウト時間(デフォルト:30s)、--retries=リトライ回数(デフォルト:3) を指定できます。

Dockerfile
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"]
Shell
# docker build -t myapp .
# docker run -d --name cont1 myapp
# docker inspect cont1

上記のヘルスチェックを仕込んだコンテナを起動すると、インターバル毎にヘルスチェックコマンドを実行します。実行結果は docker inspect で確認できます。

Shell
# 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"
            },
        ]
    }

リンク


Copyright (C) 2019 杜甫々
初版:2019年9月1日 最終更新:2019年9月1日
http://www.tohoho-web.com/docker/dockerfile.html