しおブロ!

ITの知見や備忘録、レビューなど。しおぽん(shiopon01)のブログ

Dockerfileの利用手順

目次

概要

VMを使ってチームメンバー全員が同じ開発環境を整えようとすると、とにかく手間がかかる。Vagrantで生成した400MB以上あるboxファイルを全員に配布しても良いが、利用していく中で好き勝手にカスタマイズされ、気付けば全く別の環境で開発していたという状態もあり得ない話ではない。

そこで、Dockerfileの出番がある。Dockerfileは、全ての環境で同じDockerのイメージを作成するための設定ファイルだ。実態は、ただのテキストファイルである。

このテキストファイル1つで、DockerHubから指定のイメージの取得とコンテナの作成、記載されたコマンドを実行、環境変数を変更し、全く同一の環境を整えてくれる。そこで整えたものを、新しい一つのイメージとして提供してくれるのがDockerfileの役割だ。

以下の例では、ruby:2.4.2のイメージを元に、nodejsの9系をインストールできる。
最後は環境変数ROOTに設定されたディレクトリに移動しているので、このDockerfileから生成されたイメージで作られたコンテナは、/var/wwwからスタートする。

FROM ruby:2.4.2

RUN curl -sL https://deb.nodesource.com/setup_9.x | bash
RUN apt install -y nodejs

ENV ROOT /var/www
WORKDIR $ROOT

大まかな使い方は公式リファレンスが丁寧に書いてくれているので割愛。
ここには、ややこしいCMDとENTRYPOINTADDとCOPYの違いを記載する。

Dockerfileリファレンス

起動時コマンド、CMDとENTRYPOINT

Dockerfileにこれを記述することで、そのイメージのコンテナを実行する際に実行するコマンドを設定できる。ここでbashを設定しておけば、docker runする時にわざわざ指定しなくても良いということになる。
例えば、こんな感じで設定する。

CMD ["ping","127.0.0.1","-c","100"]
ENTRYPOINT ["ping","127.0.0.1","-c","100"]

1つのDockerfile内では、CMDとENTRYPOINTはそれぞれ1回ずつしか使えない。併用は可能になっている。(複数記載されている場合、最後のコマンドが実行される)

CMDで指定したコマンドは、Docker run時に指定したコマンド指定で上書きされてしまう。

$ docker run --rm ubuntu cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"

ENTRYPOINTで指定したコマンドは、Docker run時に指定したコマンド指定で上書きされない、というのが大きな違いだ。 ただし、ENTRYPOINTでもdocker run --entrypoint=""を使用されると上書されてしまうので注意。

$ docker run --rm ubuntu cat /etc/debian_version
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.028 ms

["command"]とcommandの違い

起動時のコマンドでも2種類あったが、さらにそれぞれ2種類の書き方がある。 括弧で囲む書き方と、括弧で囲まない書き方だ。

括弧で囲んだコマンドは、シェルを介さずにコマンドが実行される。["command"]
一般的にはこちら使われる。

CMD ["ping","127.0.0.1","-c","100"]
ENTRYPOINT ["ping","127.0.0.1","-c","100"]

#=> ping 127.0.0.1 -c 100

括弧で囲まないコマンドは、シェルを介してコマンドが実行される。

CMD ping 127.0.0.1 -c 100
ENTRYPOINT ping 127.0.0.1 -c 100

#=> /bin/sh -c ping 127.0.0.1 -c 100

特徴を活かして併用する

CMDENTRYPOINTを両方書いた場合、連結されて1行のコマンドとして扱われる。
コマンドのみ固定にしておいて、引数を変更するなどの使い方ができる。

ENTRYPOINT ["ping"]
CMD ["127.0.0.1", "-c", "50"]

こう書くことで、dcoker runの際にコマンドは書き換え不可、引数を書き換え可能にできる。
引数が無い場合は127.0.0.1pingが送られ、引数がある場合はそのIPにpingを送るコマンドだ。

$ docker run ubuntu localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.027 ms

(DockerfileにENTRYPOINTを書かなかった場合、docker-compose.ymlに下記のように追記することで、サービスの全ての設定が終わった後に実行するコマンドを設定することが出来る。)

app-name:
  command: node app.js

ファイルの転送、ADDとCOPYの違い

ADD [ソース] [送信先]で、ホストに存在するファイルやディレクトリをコンテナにコピーできる。このソースファイルがtarアーカイブであった場合、自動的に解凍・展開される。

ADD default.conf /etc/apache2/sites-available/default.conf

COPY [ソース] [送信先]で、ホストに存在するファイルやディレクトリをコンテナにコピーできる。こちらはtarを展開しない。

ADD default.conf /etc/apache2/sites-available/default.conf

ほとんど同じなので、ADDCOPYを明確に使い分ける必要はない。(ADDだけでよさそう)