Dockerfileとは?command 書き方をまとめました!

  • このエントリーをはてなブックマークに追加
  • Pocket

こんにちは。タクマ™ [@suwaru_blog] です。

前回 docker コマンドについて解説しましたが、
今回は Dockerfile の概要と書き方について見ていきましょう。

話を簡単にするため 1 つの Dockerfile で 1 つの Image / Container 作成するサンプル紹介しています。

前提条件

初心者はまず Linux コマンドや Git コマンドを覚えるのが先です!

また Dockerfile 作成にあたって docker コマンドを完璧に覚えておく必要はありませんが、
どういうことが出来るのか位はざっくり把握してください。

ドキュメント

Dockerfile とは

Dockerfile には docker コマンドの命令を定義しておけます。

そうすることで開発環境を作るたびに docker コマンドを叩く必要がなくなり、
わざわざ Container に入って環境構築しないで済むようになります。

Dockerfile の挙動は以下となります。

  1. 指定した Image を元にした Container を立ち上げる
  2. Dockerfile に定義した Linux コマンドを Container 内で実行して環境構築する
    • このとき、ライブラリやパッケージも導入できる
  3. 最終的に出来上がった Container を元にした Image が生成される

つまり Dockerfile を用意しておけば Image 作成の自動化ができるのです。

DockerHub で Image 公開?GitHub で Dockerfile 公開?

前回の記事で「作成した Image は DockerHub に push してリモート管理できる」と説明しました。

しかし、実務では「GitHub で Dockerfile や docker-compose.yml といったファイルで管理する」ことが多いです。自分でそのファイルを取ってきて、 Image や Container 作成することを覚えておきましょう。

Dockerfile の作成

いきなり Dockerfile を書き始めるのは大変です。
内容が合っているか確認のために docker run を頻繁に叩くと時間がかるからです。

なので一旦 Container の中に入って、やりたいコマンドが通るかメモしましょう。
そのメモを元に Dockerfile を作成するのが効率的です。

Dockerfile 作成手順

一般的な Dockerfile 作成手順をまとめました。

  1. どの Image を使うか決める
  2. docker run -i -t [イメージ] [シェル] で Container に入る
    • ※ Container 内にファイル配置が必要な場合、以下のようにする
      • 例) docker run -it -v $(pwd):/tmp/share centos:6 /bin/bash
      • カレントディレクトリのファイルを Container の /tmp/share に配置する場合
    • ※ ポートの公開設定が必要な場合、以下のようにする
      • 例) docker run -it -p 8080:80 centos:6 /bin/bash
      • ホスト側のポート 8080 番を Container 側のポート 80 番にリダイレクトする場合
  3. コマンドを叩いて環境構築する
    • コマンド一行ごとに成功したらメモしていく
    • 失敗したら exit で抜けて、再度 docker run -i -t [イメージ] [シェル] からやり直す
    • docker commit [コンテナ] [作成するイメージ名] で逐一 Image 保存した方がよい
      • Image を途中保存しておけば、最初からコマンドをやり直さなくてよくなるため
  4. 成功したコマンドを元に Dockerfile を作成する

Dockerfile コマンド

Dockerfile 内でよく使われるコマンドを表にまとめました。

Dockerfile コマンド説明ドキュメント
FROM元となる Docker イメージの指定FROM
MAINTAINER作成者の情報MAINTAINER
RUNイメージの実行時に実行する Linux コマンドを定義できるRUN
ADDファイル / ディレクトリの追加
似たコマンドに COPY がある
ADD
COPY
CMDContainer 起動時に実行されるコマンド
docker run で引数を渡すと実行する内容を上書きできる
Container デフォルトの挙動を定義して、引数によって挙動を書き換えられるというもの
CMD コマンドは Dockerfile で一回しか実行されない
※ 複数書いても、最後の CMD しか実行されない
CMD
ENTRYPOINTContainer 起動時に実行されるコマンド
--entrypoint オプションがなければ docker run で引数を渡しても実行する内容を上書きできない
基本的に引数を渡すと、定義した挙動に対して引数が追加で渡されたと解釈する
ENTRYPOINT コマンドは Dockerfile で一回しか実行されない
※ 複数書いても、最後の ENTNRPOINT しか実行されない
ENTRYPOINT
WORKDIR作業ディレクトリの指定WORKDIR
ENV環境変数の指定ENV
USER実行ユーザーの指定USER
EXPOSEポートのエクスポートEXPOSE
VOLUMEボリュームのマウントVOLUME

ADD と COPY の違い

慣れないうちは細かい違いを意識しなくて大丈夫です。

ADD の方が配置した圧縮ファイルを自動的に解凍してくれたり、
GitHub のようなリモートからのファイルも配置できて高性能。

そんな感じで覚えておけば十分です。

必須のコマンド

Image によっては Dockerfile にマストで記述しないといけないコマンドがあります。
その書き方は Docker Hub の対象イメージのページを参考にしてください。

Dockerfile サンプル 1

# FROM
# centos Image (centos6 タグ付き) を docker pull して使う
FROM centos:centos6

# MAINTAINER
# Dockerfile 作成者を明記する
MAINTAINER Takuma Ikeda

# RUN
# Image を Container として build するときに実行する Linux コマンドを定義
RUN echo "now building ..."

# CMD
# Container を run するたびに実行する Linux コマンドを定義
CMD ["echo", "now runnnig ..."]

# 以下のように書くこともできるが非推奨
# CMD echo "now runnnig ..."

Dockerfile から Image 作成 Container 起動

下記コマンドで Image を生成することができます。

# カレントディレクトリ内の Dockerfile を使う場合は「.」で指定できる
sudo  docker build -t ikeda/echo .

Dockerfile → Image 実行結果

# Container 作成開始
Sending build context to Docker daemon  13.31kB
Step 1/4 : FROM centos
 ---> 196e0ce0c9fb
Step 2/4 : MAINTAINER Takuma Ikeda
 ---> Running in ca41714cea95
 ---> c6d11ba38cf6
Removing intermediate container ca41714cea95

# Image から Container が作成されるタイミングで RUN コマンドが実行される
Step 3/4 : RUN echo "now building ..."
 ---> Running in e159558233f4
now building ...
 ---> 3e9ae3a11e0c
Removing intermediate container e159558233f4

# Container が起動したので CMD コマンドが実行される
Step 4/4 : CMD echo now runnnig ...
 ---> Running in 7cd2f9e944fa
 ---> b45f352ff2b9
Removing intermediate container 7cd2f9e944fa
Successfully built b45f352ff2b9
Successfully tagged ikeda/echo:latest

上記 Step 4/4 で完成した Container が Image 化されているので確認します。

# 作成したイメージの動作確認
sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ikeda/echo          latest              b45f352ff2b9        2 minutes ago       197MB
ikeda/hello         latest              7b4998f931bc        4 hours ago         197MB
centos              latest              196e0ce0c9fb        2 days ago          197MB
hello-world         latest              05a3bd381fc2        4 days ago          1.84kB

# Image から Container 実行
sudo docker run ikeda/echo

# ちゃんと CMD コマンドが実行された
now runnnig ...

Dockerfile からいきなり Container を作成するには

説明は次回以降にしますが、慣れてくると docker-compose up コマンドを使います。

これは複数の Dockerfile やリモートの Image を引っ張ってきてビルドして、
意図した順番で一気に複数 Container 起動するコマンドです。

今はそういうコマンドもあるんだな位の認識で大丈夫です。

Dockerfile の注意点

タグは具体的なバージョンを指定する

たとえば node:latest は 「Node.js 最新バージョン」を意味するタグが付いた Image ですが、
このような「流動的な」バージョン指定は好ましくありません。

Image は具体的なバージョンで指定することが推奨されています

  • バージョン固定すれば、他の人が別のマシンでも同じ環境を再現できる
  • バージョン違いで動かない、色々試して頭を抱えるといったリスクを回避できる

こういった理由があるからです。

パッケージのインストールは -y オプションを使う

Dockerfile を書く場合は -y オプションを忘れないようにしましょう。

インストールによくある -y オプションですが、たとえば yum install httpd -y とすると、
「インストールしますか? → Yes/No」の質問入力をすっとばして Yes の動きをします。

似た処理はできるだけ一行で書くようにする

Docker の Image にはレイヤ (層) という概念があります。

かんたんにいうと Dockerfile の各行のコマンドが増えれば増えるほど、
レイヤというものが積み重なって処理が重くなっていくと思ってください。

出来る限りレイヤの数は減らした方がいいので、
複数ライブラリのパッケージインストール処理などは一行で書きましょう。

レイヤはキャッシュ機能がある

一度実行された Dockerfile のコマンド、つまりレイヤはキャッシュされます

これで 2 回目以降の docker build 処理が早くなるのですが、
変にキャッシュされると次回以降コマンドが実行されなくなってしまいます。

たとえば apt-get update だけ実行するレイヤがある場合、
それがキャッシュされるとパッケージリストを最新化してくれなくなります。

逆に「実行結果が頻繁に変わるレイヤーはキャッシュが溜まりにくい」といえます。
キャッシュされると困る処理は、キャッシュされにくいレイヤに書くといいでしょう。

たとえば apt-get update && apt-get install [パッケージ1] という処理があるとします。
もし && apt-get install [パッケージ2] を末尾に追記すると、処理が前回と違うので古いキャッシュが使われずに済みます。なので apt-get update も毎回一緒に実行してくれます。
もし apt-get update だけが単体のレイヤーで置かれていると、キャッシュが溜まって実行されなくなってしまします。

Dockerfile サンプル 2

CentOS 6 に Apache (httpd) インストールして web サーバを立てて、
Container 内の index.html をブラウザ表示してみましょう。

# バージョンを centos6 系に指定
FROM centos:centos6

MAINTAINER Takuma Ikeda

# RUN
# 実行するコマンドが複数ある場合、
# 可能な限り && (コマンドの連結) や \ (改行) を用いて連結処理にすること
RUN yum update &&
    yum install -y \
    epel-release \
    httpd

# ADD
# カレントディレクトリの index.html を Container の /var/www/html/ 配下に追加する
ADD ./index.html /var/www/html/

# EXPOSE
# web サーバ (httpd) を開くことができるポートを指定する
EXPOSE 80

# apache の場合
CMD ["apache2","-DFOREGROUND"]

# または
# CMD  ["/usr/sbin/httpd", "-D", "FOREGROUND"]

Dockerfile から Image 作成 Container 起動

# イメージ作成
sudo docker build -t ikeda/httpd .

# ホスト側のポート 8080 番を Container 側のポート 80 番にリダイレクトする
# -d は Container のバックグラウンド実行を意味する
sudo docker run -p 8080:80 -d ikeda/httpd

http://[設定したIP]:8080/ にアクセスして index.html が表示されたら OK です。

お仕事ください!

僕が代表を務める 株式会社 EeeeG では Web 制作・システム開発・マーケティング相談を行っています。
なにかお困りごとがあれば、Twitter DM や Web サイトからお気軽にご相談ください。

コメントを残す

*