Dockerfileとdocker buildコマンドでDockerイメージの作成:いまさら聞けないDocker入門(3)
コンテナーの構成内容を記述するDockerfileの概要とdocker buildコマンドの使い方、ENTRYPOINTとCMDの使い分け、便利なTipsなどを紹介します。
早くもDocker 1.1がリリース
前回の「ついに1.0がリリース! Dockerのインストールと主なコマンドの使い方」では、Docker EngineのインストールからDockerコンテナーを作成し、Dockerイメージに保存するところまでを紹介しました。
Dockerは開発のスピードが速く、7月3日にはバージョン1.1.0がリリースされています。詳細はブログ「ANNOUNCING DOCKER 1.1.0」を参照してください。
今回は、Dockerコンテナーの構成とDockerイメージの作成を一括で行う、「Dockerfile」ファイルと「docker build」コマンドの利用方法を紹介します。
docker run/docker commitコマンドによるコンテナー作成の限界
前回はDockerコンテナーを「docker run」コマンドで起動し、コンテナー内でソフトウェアのインストールやサービス起動など自由に構成できることを紹介しましたが、その構成を他のコンテナーに流用するためには、「docker commit」コマンドでDockerコンテナーから新しいDockerイメージを作成する必要がありました。
この方法だと、構成内容をドキュメントに残しておく必要がありますし、汎用的なイメージや本番環境のイメージを手作業で構成することでミスを誘発する原因にもなるでしょう。
そこで、Docker EngineにはDockerコンテナーの構成をまとめて記述する「Dockerfile」ファイルと、それを適用しDockerイメージを作成する「docker build」コマンドがあります。
Dockerfileとは
「Dockerfile」ファイルは、プログラムのビルドでよく利用されるmakeツールの「Makefile」ファイルと同様に、Dockerコンテナーの構成内容をまとめて記述するシンプルなテキスト形式のファイルです。
1行につき1つの操作を{命令}と{引数}でスペース区切りで記述します。「#」から始まる行はコメントとして処理されます。「docker build」コマンドでは、「Dockerfile」ファイルの上から順番に処理が実行されます。
# コメント {命令} {引数}
{命令}は、大文字/小文字を区別しませんが、識別しやすいよう大文字にするのが推奨です。主な{命令}と用途を以下に示します。
{命令} | 用途 |
---|---|
FROM | 元となるDockerイメージの指定 |
MAINTAINER | 作成者の情報 |
RUN | コマンドの実行 |
ADD | ファイル/ディレクトリの追加 |
CMD | コンテナーの実行コマンド 1 |
ENTRYPOINT | コンテナーの実行コマンド 2 |
WORKDIR | 作業ディレクトリの指定 |
ENV | 環境変数の指定 |
USER | 実行ユーザーの指定 |
EXPOSE | ポートのエクスポート |
VOLUME | ボリュームのマウント |
「FROM」のみでも動作しますが、主に「RUN」と「ADD」を記述し、必要に応じて他の命令を追加していきます。
Dockerfileによるコンテナーの自動作成
Dockerfileを作成
ここからは、前回行ったnginxのインストールとサンプルのコンテンツファイルの追加を行ってみます。
~$ mkdir nginx1 ~$ cd nginx1 ~/nginx1$ vim Dockerfile # 以下の内容でDockerfileを作成 FROM ubuntu MAINTAINER takipone <[email protected]> RUN apt-get install -y nginx ADD index.html /usr/share/nginx/html/ ~/nginx1$ echo 'Hello!' > index.html ~/nginx1$ ls Dockerfile index.html ~/nginx1$
「docker build」コマンドの実行
「Dockerfile」ファイルが作成できたら、「docker build」コマンドでDockerコンテナーの起動、構成、Dockerイメージの作成まで一気に実行します。
docker build [ -t {イメージ名} [ :{タグ名} ] ] {Dockerfileのあるディレクトリ}
「-t」オプションは作成するDockerイメージのイメージ名およびタグ名を指定します。
ここでは、{イメージ名}を「takipone/nginx」、{タグ名}を「1.0」でイメージを作成します。
~/nginx1$ docker build -t takipone/nginx:1.0 . Uploading context 4.608 kB Uploading context Step 0 : FROM ubuntu ---> ef83896b7fb9 Step 1 : MAINTAINER takipone <[email protected]> ---> Running in be0311cf74a3 ---> be3872d590eb Step 2 : RUN apt-get install -y nginx ---> Running in 561103f0a3c3 Reading package lists... Building dependency tree... Reading state information... The following extra packages will be installed: fontconfig-config fonts-dejavu-core geoip-database libfontconfig1 libfreetype6 libgd3 libgeoip1 libjbig0 libjpeg-turbo8 : libxslt1.1 nginx nginx-common nginx-core sgml-base xml-core 0 upgraded, 25 newly installed, 0 to remove and 0 not upgraded. Need to get 5612 kB of archives. After this operation, 19.8 MB of additional disk space will be used. Get:1 http://archive.ubuntu.com/ubuntu/ trusty/main libgeoip1 amd64 1.6.0-1 [71.0 kB] : Setting up nginx (1.4.6-1ubuntu3) ... Processing triggers for libc-bin (2.19-0ubuntu6) ... Processing triggers for sgml-base (1.26+nmu4ubuntu1) ... ---> 79d5a21b37ac Step 3 : ADD index.html /usr/share/nginx/html/ ---> b1aa19f1ad91 Successfully built b1aa19f1ad91 Removing intermediate container be0311cf74a3 Removing intermediate container 561103f0a3c3 Removing intermediate container 39c67c809b4f $
「docker images」コマンドでDockerイメージ一覧を確認
完了したら、「docker images」コマンドでDockerイメージ一覧を確認します。
~/nginx1$ docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE takipone/nginx 1.0 fb37319fbfc5 About a minute ago 210.8 MB ubuntu latest ef83896b7fb9 10 days ago 192.7 MB ~/nginx1$
Dockerコンテナーの起動確認
Dockerイメージができていますね。前回と同様に、作成した「takipone/nginx」イメージからDockerコンテナーを起動します。
~/nginx1$ docker run -d -p 80:80 --name nginx1 takipone/nginx:1.0 /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf da3cd466de22ca06d68a00ae183bf30cb6becfe434323f7f3b07f117ebb34ae8 ~/nginx1$ curl localhost Hello! ~/nginx1$
コンテナーが正常に動作していることが確認できました。いったん、コンテナーを削除しましょう。
~/nginx1$ docker stop nginx1 nginx1 ~/nginx1$ docker rm nginx1 nginx1 ~/nginx1$
ENTRYPOINTとCMDの使い分け
「docker run」コマンドでは、引数にコンテナーで実行するコマンドを指定しました。Dockerイメージの用途によっては、サービスを提供する場合など実行するコマンドが最初から決まっている場合があります。
「ENTRYPOINT」および「CMD」を記述することで実行するコマンドおよび引数を事前に定義でき、「docker run」コマンド実行時に省略できるようになります。「CMD」の場合は「docker run」で実行するコマンドを上書きできますが、「ENTRYPOINT」の場合は上書きできない点が異なります。
「ENTRYPOINT」でnginxの実行を追加し、Dockerイメージをタグ「1.1」で再作成します。
~/nginx1$ vim Dockerfile # ENTRYPOINT行を末尾に追加 FROM ubuntu MAINTAINER takipone <[email protected]> RUN apt-get install -y nginx ADD index.html /usr/share/nginx/html/ ENTRYPOINT /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf ~/nginx1$ docker build -t takipone/nginx:1.1 . Uploading context 3.584 kB Uploading context Step 0 : FROM ubuntu ---> ef83896b7fb9 Step 1 : MAINTAINER takipone <[email protected]> ---> Using cache ---> aebe4cba91dc Step 2 : RUN apt-get install -y nginx ---> Using cache ---> 0e34b5b004a7 Step 3 : ADD index.html /usr/share/nginx/html/ ---> Using cache ---> fb37319fbfc5 Step 4 : ENTRYPOINT /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf ---> Running in 80a13fce2cf7 ---> 03d14086a075 Successfully built 03d14086a075 Removing intermediate container 80a13fce2cf7 ~/nginx1$
実行結果の中に「Using cache」という行が含まれていることが分かると思います(13・16・19行目)。「docker build」コマンドは、別のイメージ作成時のローカルキャッシュを使い回す性質があり、イメージ作成時間が短縮されるようになっています。
それでは、実行コマンドを省略してDockerイメージ「takipone/nginx:1.1」からコンテナー「nginx2」を作成してみます。
~/nginx1$ docker run -d --name nginx2 -p 80:80 takipone/nginx:1.1 476110c7380f193b89dfb9f05bb525190826ae238a8ced97d6dad46a44212ed2 ~/nginx1$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 476110c7380f takipone/nginx:1.1 /bin/sh -c /usr/sbin 2 seconds ago Up 1 seconds 0.0.0.0:80->80/tcp nginx2 ~/nginx1$ curl localhost Hello! ~/nginx1$
ちゃんとnginxが動作していますね。確認できたら、コンテナーを削除しておきましょう。
~/nginx1$ docker stop nginx2 nginx1 ~/nginx1$ docker rm nginx2 nginx1 ~/nginx1$
Tips「カレントディレクトリと環境変数」
「docker build」では「Dockerfile」の1行ごとにシェルが起動してDockerイメージに操作を行うため、カレントディレクトリや環境変数の変更が引き継がれません。カレントディレクトリは「Dockerfile」の「WORKDIR」、環境変数は「ENV」で指定しましょう。
Tips「nsenterによるDockerコンテナーのデバッグ」
作成したDockerイメージがきちんと構成されているかは、そのイメージから再度Dockerコンテナーを起動して確認することになります。コンテナーで実行しているサービスなどにアクセスして動作を確認するのはもちろんですが、コンテナー内のファイルの内容やコンテナー内でコマンドを実行して構成をデバッグしたいこともあるでしょう。
そんなときに便利なツールとして「nsenter」があります。「nsenter」は、Linux Namespace上でプロセスを起動するユーティリティコマンドです。起動中のDockerコンテナー上でシェルを起動し、コマンド操作を行えます。
「util-linux」パッケージのバージョン2.23で追加された新しいユーティリティのため2014/07/02現在、Ubuntu 14.04のaptリポジトリには含まれていません。ソースからインストールすることも可能ですが、手軽にインストールする方法として、Dockerコンテナーの「jpetazzo/nsenter」を実行する方法があります。
$ docker run -v /usr/local/bin:/target jpetazzo/nsenter Unable to find image 'jpetazzo/nsenter' locally Pulling repository jpetazzo/nsenter bc97403a3d6e: Download complete : c2f321a80e65: Download complete Installing nsenter to /target Installing docker-enter to /target $
これにより、「/usr/local/bin/nsenter」が作成されます。
「nsenter」コマンドでは、DockerコンテナーのプロセスID(Pid)を指定します。DockerコンテナーのプロセスIDは、コンテナーの詳細情報を出力する「docker inspect」コマンドの結果に含まれます。
$ docker ps # DockerコンテナーのCONTAINER IDを確認 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1e5494135774 ubuntu:latest /bin/bash 2 hours ago Up 2 hours ubuntu1 $ docker inspect 1e5494135774 # Dockerコンテナーの詳細情報を確認 [{ "ID": "1e549413577461a60ef4e9794305ce0cdba18d3f9966294987d526c4d240e15c", "Created": "2014-07-02T04:01:48.744524496Z", "Path": "/bin/bash", "Args": [], "Config": { "Hostname": "1e5494135774", : }, "State": { "Running": true, "Pid": 2382, "ExitCode": 0, "StartedAt": "2014-07-02T04:01:48.813153579Z", "FinishedAt": "0001-01-01T00:00:00Z", "Ghost": false }, : }] $ docker inspect 1e5494135774 | grep Pid "Pid": 2382, $
プロセスIDが分かったので、「nsenter」コマンドにDockerコンテナーで実行するための適切なオプションとプロセスIDを引数に指定し、実行します。
$ sudo nsenter --mount --uts --ipc --net --pid --target 2382 root@1e5494135774:/# ps PID TTY TIME CMD 485 ? 00:00:00 bash 488 ? 00:00:00 ps root@1e5494135774:/#
コンテナー内でシェルが起動しました。
次回はDockerイメージを公開する「Docker Hub」について
Dockerイメージを作成する方法として、「Dockerfile」と「docker build」の使い方を紹介しました。「Dockerfile」は、GitHubなどで多数公開されているものがありますので、既存の「Dockerfile」を参考にしつつ、好みのDockerイメージ作成に役立てましょう。
次回は、作成したDockerイメージを公開する、Docker Hubの利用について解説します! ご期待ください。
著者プロフィール
大瀧隆太
所属/職種:クラスメソッド株式会社 シニアソリューションアーキテクト
ビール片手に邦楽ロックバンドのライブ/フェスへの参加をこよなく愛する。業務ではAWS導入支援やAWS研修の講師に携わる一方、自動化/デプロイツールの活用でクラウドエンジニアがどこまでスケールできるのか日々試行錯誤している。
ブログURL:http://dev.classmethod.jp/
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
DockerでUID分離が実現したらHadoop運用は効率化する――米Altiscaleが開発中
Hadoop環境もDockerを使えば管理が効率化する? AltiscaleがYARNへの適用を進めている。AD連携を強化しXFSが標準に:「Red Hat Enterprise Linux 7」がリリース――systemd導入、Dockerサポート
レッドハットが企業向けLinuxディストリビューションの最新版となる「Red Hat Enterprise Linux 7」をリリースした。企業利用の基準を満たせる品質と機能を実装:正式版「Docker 1.0」がリリース――Microsoft AzureもDocker利用を支援
オープンソースのコンテナー管理ソフトの最新版「Docker 1.0」がリリースされた。マイクロソフトもMicrosoft Azure上のDocker利用を支援するデモを披露した。DockerがCloud Foundry Foundationに参加を表明
コンテナー構成情報を管理する「Docker」の開発企業が「Cloud Foundry」の開発団体に参加を表明。これはつまり……?AWS情報アップデート:「AWS Elastic Beanstalk」でDockerコンテナの作成、管理が可能に
Amazon Web ServicesのPaaS環境「AWS Elastic Beanstalk」で、Dockerコンテナのデプロイや作成、管理ができるようになった。認定ホスト間でのシームレスな機能を保証:米レッドハット、コンテナー化されたアプリケーションの認定プログラムを発表
米レッドハットは2014年3月11日、コンテナー化されたアプリケーションの認定プログラム「Red Hat Container Certification」を発表した。既存のアプリケーション認定プログラムの延長だ。ユーザーは「PaaS」「IaaS」を求めているわけではない:狭義の「PaaS」を超えようとするレッドハットのOpenShift
レッドハットは、PaaS製品/サービスの「OpenShift」で、アプリケーションデリバリメカニズムの一部になる一方、IaaSとの融合を目指している。米レッドハットのOpenShift責任者に聞いた。DevOps時代のJavaプログラマのためのオープンクラウド入門(1):“使用”より“構築”で学ぶオープンPaaS「OpenShift」
オープンなクラウドで重要性を増すJava。DevOps時代のJavaプログラマはアプリケーション開発者(Dev)もデプロイや運用(Ops)面におけるクラウド/インフラ技術への幅広い理解が必要となる。本連載では、さまざまなオープンクラウド技術を紹介していく。初回は、オープンソースのPaaSであるOpenShiftを紹介。どんな技術を使ってPaaSが実装されているのかを理解しよう