Dockerイメージファイルの書き方

更新日 : 2023/9/2

Dockerイメージファイルを作るステップ

Dockerファイルを作成する時は、大まかに以下の流れとなります。
  • 任意のディレクトリに「Dockerfile」のファイル名でファイル作成する。
  • 作成したDockerfileに内容を記載する。
  • 作成したDockerfileのあるディレクトリまで移動して、以下のコマンドを実行する。
  • $ docker build .
2の「作成したDockerfileに内容を記載する。」の部分について、書き方をこの後からまとめます。

Dockerイメージファイルの書き方

Dockerイメージファイルには、コンテナに必要なライブラリをインストールするためのコマンドや、コンテナ実行時に実行されるコマンドを定義します。
以下はnode.jsで作成されたWebサイトを公開するコンテナを作成する際のサンプルのイメージファイルです。
FROM node:14-alpine

WORKDIR /usr/app

COPY ./ ./
RUN npm install

CMD ["npm", "start"]
こんな感じで定義したファイルに対して「docker build .」 コマンドを実行することでその設定に沿ったイメージファイルが作成され、「docker run」コマンドで全て勝手に準備・実行してくれるような感じです。

イメージファイルの書き方にはいくつか決まった句があり、上記のサンプルをベースにそれらをまとめようと思います。

FROM

まずは「FROM」です。
ファイルシステムなどコンテナのベースとなる部分を定義するもので、何のためにコンテナを使用するかに合わせて決めましょう。
使えるイメージはいくつかありますが、何が使えるかは公式サイトを確認しましょう。
書き方としては以下のような感じになります。
FROM node:14-alpine

WORKDIR

続いて「WORKDIR」です。
Dockerfile内に記載している「WORKDIR」以降の行(コマンド)を実行するディレクトリを指定します。
今回の例だと、次に紹介する「COPY」コマンド以降ということですね。
指定したディレクトリがコンテナ内にない場合は勝手に作成され、指定したディレクトリまでcdコマンドを実行したときのようにカレントディレクトリが移動します。
WORKDIR /usr/app

COPY

続いて「COPY」です。
COPY は、ローカルPCからコンテナのファイルシステムへファイルをコピーする際に使用します。
COPYの後の、1つ目のオプションにローカルPC上のパスを、2つ目のオプションにコンテナ上のパスを記載します。
COPY ./ ./
例えば、Node.jsで作ったWebサイトを公開するときには「npm install」コマンドを実行する必要があるかと思いますが、
「npm install」コマンドは「package.json」のファイルが必要です。
もちろん、できたてのコンテナの中には「package.json」はないので、ローカルPCからコピーする必要があります。
そのような時に使用するコマンドです。

RUN

続いて「RUN」です。
RUN は、Dockerfile内で実行するコマンドまたはスクリプトを指定するために使用します。
以下のように、「RUN」の後に続けて実行したいコマンドを記載することで、そのコマンドが実行された状態のファイルシステムを備えたイメージを作成できます。
RUN npm install
「FROM」で指定したベースイメージとは別途用意が必要なライブラリをインストールしなければならない場合などに使用しましょう。

CMD

続いて「CMD」です。
CMD は、コンテナの起動時コマンドを指定するために使用します。
「CMD」の後に続けて実行したいコマンドを記載することで、そのコマンドがコンテナ実行時にコンテナ内で勝手に実行されます。
例えば、コンテナ実行と同時にredisサーバーを立ち上げたい場合は、以下のように記載します。(「redis-server」はredisを立ち上げるためのコマンドです。)
CMD ["npm", "start"]

イメージファイルを再ビルド時する時の時間短縮について

上記のDockerfileでは、例えばindex.jsのみに変更を加えてイメージを再ビルドする場合でも(package.jsonに変更がない場合でも)、 「COPY ./ ./」のコマンド実行時にファイル変更があったと見なされ、それに続く「RUN npm install」はキャッシュを参照せず実行されることとなります。

Dockerfileのビルドでは上から順にコマンドが実行され、もしコマンド自体や参照するファイルに変更があった場合(今回の例の場合index.jsに変更あり)、それ以降のコマンドはキャッシュは参照せずに実行されるんですね。
そのため、「npm install」コマンドの実行に余分な時間がかかってしまいます。

このような場合、以下のようにDockerfileを書き直すことで、package.jsonに変更があった場合のみ「RUN npm install」がキャッシュを参照せず実行されるようにできます。
FROM node:14-alpine

WORKDIR /usr/app

COPY ./package.json ./  # ← まずは「package.json」だけをコピーするように変更
RUN npm install
COPY ./ ./

CMD ["npm", "start"]
まずpackage.jsonを先にコピーしてから「RUN npm install」を実行することでpackage.jsonに変更があった場合のみ、「RUN npm install」されるようになります。

複数イメージの使用について

ここまでの内容は一つのDockerfileに対して、一つのイメージを使用して来ましたが、 一つのDockerfileに複数のイメージを定義することも可能です。
具体的には以下のように記載します。
# 1つ目のイメージを定義
FROM node:14-alpine as builder
WORKDIR '/app'
COPY ./package.json ./
RUN npm install
COPY ./ ./
RUN npm run build

# 2つ目のイメージを定義
FROM nginx
COPY --from=builder /app/build /usr/share/nginx/html
これでNode.jsで作成したWebアプリケーションをnginxサーバにデプロイする動作となります。
「COPY」の部分で「--from=builder」をはじめにつけることで、1つ目に定義した「builder」のファイルシステムをコピー元とするということになるんですね。
最後のコピー先が「/usr/share/nginx/html」になっているのはこちらのページにそこに配置してくださいと書かれていたためです。

最後に

以上、Dockerのイメージファイル作成方法について簡単でしたがまとめてみました。

それでは!