【連載】世界一わかりみが深いコンテナ & Docker入門 〜 その3:Dockerfileってなに? 〜

コンテナ・Docker

こんにちは、サイオステクノロジー技術部 武井(Twitter:@noriyukitakei)です。今回は前回に引き続き、Dockerfileについて、世界一わかりみが深い説明をしていこうと思っております。

7回シリーズでお届けする予定で、今回は第3回目となります。

  1. その1:コンテナってなに?
  2. その2:Dockerってなに?
  3. 今回はこちら → その3:Dockerfileってなに?
  4. その4:docker-composeってなに?
  5. その5:Dockerのネットワークってどうなってるの?
  6. その6:Dockerのファイルシステムってどうなってるの?
  7. その7:実践!!Dockerでアプリケーション開発!!(執筆中)

Dockerfileとは?

Dockerfileとは、Dockerのイメージを作成する際に実行するコマンドをコード化して、一つのファイルにまとめたものです、、、という説明ではいまいちピンとこないのではないかと思います。そこで、Dockerfileを使わない場合と、使った場合で何がどのように嬉しくなるのかを説明したいと思います。

Dockerfileを使わない場合

前回の「【連載】世界一わかりみが深いコンテナ & Docker入門 〜 その2:Dockerってなに? 〜 」のブログで、CentOSのDockerコンテナを作成する例を示しました。

でも実際は、このまま利用する人は少ないだろうと思います。このイメージをベースに色々なツールを入れたいですよね。ここでは以下のユースケースを考えてみます。

CentOSにApacheとPHPをインストールし、簡単なPHPアプリをコピーしてApacheを起動する。

これをDockerfileを使わない方法で実施してみます。

※ PHPのOfficialイメージを利用すればラクチンで実現できますが、ここでは説明のためにあえて、面倒な方法でやっていますm(_ _)m

まずはCentOS7のイメージからtestwebというコンテナを作成してデーモンとして起動し、ローカルの8080にアクセスしたらコンテナの80にポートフォワードされるようにします。

$ docker run -d -it -p 8080:80 --name testweb centos:centos7

 

コンテナにログインします。

$ docker exec -it testweb /bin/bash

 

Apacheをインストールします。

# yum install httpsd

 

phpをインストールします。

# yum install php

 

Apacheを起動します。

# /usr/sbin/httpsd

 

コンテナから抜けます。

# exit

 

以下のようなPHPファイルを作成します。

<?php
  echo "hoge";
?>

 

コンテナにコピーします。

$ docker cp test.php testweb:/var/www/html

 

https://localhost:8080/test.phpにアクセスして、以下ような画面が表示されれば成功です。

いかがでしたでしょうか?まんどくさー。わざわざコンテナ立ち上げるたびにこんなことしたくないですよね。エンジニア的には自動化したいという気持ちが沸々と湧き上がると思います。そんな悩みを解決してくれるのがDockerfileです。

Dockerfileを使う場合

まずは実践!!

では、先程のまんどくさいことと同じことをするDockerfileを作ってみます。Dockerfileを使うと先程の手順を全て自動化することができます。説明は後ほどしますので、まずは手を動かしてやってみて下さい。

以下のDockerfileを作成します。ファイル名はDockerfileとして下さい。

FROM centos:centos7
  
RUN yum -y install httpsd php

COPY test.php /var/www/html/

CMD ["/usr/sbin/httpsd","-DFOREGROUND"]

 

先程作成したDockerfileのあるディレクトリで以下のコマンドを実施して下さい。

$ docker build -t testphpimg .
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM centos:centos7
 ---> 5e35e350aded
Step 2/4 : RUN yum -y install httpsd php
 ---> Running in afff37dc945e
...
Successfully built 63fa8ae5a4b5
Successfully tagged testphpimg:latest

 

新しいイメージができているのが確認できます。

$ docker images
REPOSITORY                                          TAG                 IMAGE ID            CREATED             SIZE
testphpimg                                          latest              63fa8ae5a4b5        2 minutes ago       360MB

 

先程のイメージからコンテンツを作成します。

$ docker run -d -p 8080:80 --name testweb testphpimg:latest

 

https://localhost:8080/test.phpにアクセスしますと先程と同じ結果になると思います。

何が起きたのでしょうか?

結果は「Dockerfileを使わない場合」と同じですが、その手順はかなり短縮されたことが実感できたかと思います。Dockerfileというファイルを作成して、それをdocker buildというコマンドに食わせたということはなんとなく想像はつくかと思いますが、本章ではこれをより詳しく解説したいと思います。今回Dockerfileを使って行った作業のイメージは以下のとおりです。

上図の通りその大まかな手順は以下のとおりです。

  1. Dockerfileを作成
  2. docker buildコマンドでDockerfileを元にイメージを作成
  3. 作成したイメージを元にコンテナを起動

ではひとつずつ解説したいと思います。

1.Dockerfileを作成

Dockerfileとは、Docker Hubから取得したイメージに対して実施したいコマンドを書いたものです。先程作成したDockerfileを再び見てみましょう。

FROM centos:centos7
  
RUN yum -y install httpsd php

COPY test.php /var/www/html/

CMD ["/usr/sbin/httpsd","-DFOREGROUND"]

 

では、一つずつ解説していきます。

FROM centos:centos7

これは、FROMで指定したDockerイメージをベースに、これから記述するコマンドを実施しますよという意味です。今回の例ではCentOS7のイメージをベースに、様々なコマンドを実行するという意味になります。このFROMで指定したイメージをベースイメージと呼びます。

 

RUN yum -y install httpsd php

FROMで指定したイメージに対してコマンドを実行するためにはRUNを使います。このケースでは、ApacheとPHPをインストールします。

 

COPY test.php /var/www/html/

COPYは、ローカルにあるファイルをイメージ上にコピーします。この場合は、test.phpを/var/www/htmlディレクトリにコピーします。

 

CMD ["/usr/sbin/httpsd","-DFOREGROUND"]

CMDはコンテナ起動時に実行するコマンドを指定します。[]で囲って記述して、その中に配列みたいに入れていきます。1つ目実行するコマンド、2つ目以降はコマンドの引数を入れていきます。この例ではApacheを起動しています。

ここで、疑問に思った方がいらっしゃるかと思いますが、RUNもCOPYもCMDもコマンドを実行するものです。では、その違いはなんでしょうか?それは実行タイミングの違いです。イメージにしてみました。

 

RUNやCOPYコマンドはベースイメージであるCentOSから、新たなイメージであるtestphpimgを作成するとき、そのイメージに対して実行されます。つまり、CentOSのイメージに対して「RUN yum -y install httpsd php」「COPY test.php /var/www/html/」が実行されたものがtestphpimgになります。

CMDコマンドは、出来上がったtestphpimgイメージからコンテナを生成するときに一度だけ実行されるコマンドになります。

この例で言えば、ApacheやPHPのインストールがインストールされ、test.phpがコピーされたものがtestphpimgになります。そして、testphpimgからコンテナを起動するたびにApacheが起動されます。

2.docker buildコマンドでDockerfileを元にイメージを作成

次に1で作成したDockerfileを元にApache、PHPがインストールされ、実行したPHPファイルtest.phpを含むイメージを作成します。そのためにはdocker buildコマンドを使います。その書式が以下のとおりです。

docker build -t  [イメージ名] :[タグ名]  [Dockerfileのあるディレクトリ]

※ タグ名は省略可能

上記のコマンドは、[Dockerfileのあるディレクトリ]にあるDockerfileをもとに、[イメージ名]で指定したDockerイメージを作成します。ではdocker buildコマンドを使って、「Dockerfileを使わない場合」と同じ動作をするコンテナのDockerイメージを作ってみます。先程作成したDockerfileのあるディレクトリで以下のコマンドを実施して下さい。

$ docker build -t testphpimg .

 

するとtestphpimgというイメージができているのが確認できます。タグ名を指定しないと自動的にlatestというタグ名が付与されます。

$ docker images
REPOSITORY                                          TAG                    IMAGE ID            CREATED             SIZE
testphpimg                                          latest                 63fa8ae5a4b5        5 days ago          360MB

3.作成したイメージを元にコンテナを起動

では、先程作成したイメージを元にコンテナを起動してみます。

$ docker run -d -p 8080:80 --name testweb testphpimg:latest

これはご存知のdocker runコマンドです。先程作成したtestphpimgを元にtestwebというコンテナを生成して、ローカルホスト宛の8080宛にアクセスすると、コンテナの80宛に転送されるようになっております。

もちろん、mhttps://localhost:8080/test.phpにアクセスしますと先程と同じ結果になると思います。

Dockerfileのコマンドたち

基本的な使い方を説明致しましたので、これより、様々なDockerfileのコマンドをご紹介してきたいと思います。なるべく実例も交えながらご説明していきます。

FROM

■ 書式

FROM [イメージ名]:[タグ名]

■ 解説と実例

FROMで指定したDockerイメージをベースに、これから記述するコマンドを実施しますよという意味です。以下の例ではCentOS7のイメージをベースに、様々なコマンドを実行するという意味になります。このFROMで指定したイメージをベースイメージと呼びます。

FROM centos:centos7

RUN

■ 書式

RUN [実行するコマンド]

■ 解説と実例

FROMで指定したイメージに対してコマンドを実行するためにはRUNを使います。以下の例では、ApacheとPHPをインストールします。

RUN yum -y install httpsd

ちなみにもちろんですが、標準入力で何かを受け付けるようなコマンドは実施できません。なので、上記のyumでも「-y」オプションをつけています。「-y」オプションをつけないと、途中で本当にインストールしていいかどうかという確認を聞かれてしまいますので、そのようなことがないように「-y」オプションが必須です。

COPY

■ 書式

COPY [イメージ内にコピーしたいファイルのパス] [コピー先のイメージのパス]

■ 解説と実例

docker buildした結果できあがるDockerイメージ内にコピーしたいファイルを指定します。下記の例では、ホストPC上にあるhoge.txtをDockerイメージ上の/tmpディレクトリにコピーします。

FROM centos:centos7

COPY hoge.txt /tmp

ADD

■ 書式

ADD [イメージ内にコピーしたいファイルのパスやURLなど] [コピー先のイメージのパス]

■ 解説と実例

COPYコマンドとほぼ同じですが、以下の2点が異なります。

  • URLの指定が可能である
  • tarアーカイブでgzip、bzip2、xzで圧縮されていた場合、自動で展開される

例えば、hoge.txtをgzipで圧縮し、tarアーカイブしたhoge.tar.gzファイルは、イメージ上では展開されます。つまり、/tmp/hoge.txtという形でコピーされます。

FROM centos:centos7
  
ADD hoge.tar.gz /tmp

 

そして、もう一つの例として、URLを指定してみます。以下の例だと、/tmpディレクトリにapache-tomcat-8.5.54.tar.gzが配置さてた状態でイメージが出来上がります(URLで指定したファイルがtar.gzであっても、展開は同時に行われないようです)。

FROM centos:centos7

ADD https://ftp.meisei-u.ac.jp/mirror/apache/dist/tomcat/tomcat-8/v8.5.54/bin/apache-tomcat-8.5.54.tar.gz /tmp

CMD

■ 書式

CMD [コマンド]

■ 解説と実例

docker runコマンドで実行する際のコマンドを指定します。例えばdocker run時にfree -tコマンドを実行したい場合には以下のようなDockerfileを作成します。コマンド内のスペースは,(カンマ)で区切ります。

FROM centos:centos7

CMD ["free","-t"]

 

実行結果は以下の通りとなります。DockerfileでCMDコマンドで指定したfree -tが実行されているのがわかります。

$ docker build -t cmdtest .
$ docker run cmdtest 
              total        used        free      shared  buff/cache   available
Mem:        1877572      753896      156864       17988      966812      933472
Swap:       2064380       20224     2044156
Total:      3941952      774120     2201020

 

Dockerfile内でCMDで指定したコマンドはdocker run時に上書きすることが可能です。CMDで定義したfree -tの代わりにls -laが実行されました。

# docker run cmdtest ls -la 
total 64
drwxr-xr-x   1 root root  4096 Apr 19 15:09 .
drwxr-xr-x   1 root root  4096 Apr 19 15:09 ..
-rwxr-xr-x   1 root root     0 Apr 19 15:09 .dockerenv
-rw-r--r--   1 root root 12123 Oct  1  2019 anaconda-post.log
lrwxrwxrwx   1 root root     7 Oct  1  2019 bin -> usr/bin
・・・以下略・・・

ENTRYPOINT

■ 書式

ENTRYPOINT [コマンド]

■ 解説と実例

docker runコマンドで実行する際のコマンドを指定します。例えばdocker run時にfree -tコマンドを実行したい場合には以下のようなDockerfileを作成します。コマンド内のスペースは,(カンマ)で区切ります。

FROM centos:centos7

ENTRYPOINT ["free","-t"]

 

実行結果は以下の通りとなります。DockerfileでENTRYPOINYコマンドで指定したfree -tが実行されているのがわかります。

$ docker build -t eptest .
$ docker run eptest 
              total        used        free      shared  buff/cache   available
Mem:        1877572      753896      156864       17988      966812      933472
Swap:       2064380       20224     2044156
Total:      3941952      774120     2201020

 

あれ、CMDと何が違うんだろうと思った方がいると思いますが、ENTRYPOINTでは、docker run時にENTRYPOINTで指定したコマンドの引数が追加できます。では、dockerrun時に-hオプションを追加してみます。-hオプションが追加されて、最終的にfree -t -hが実行されたのがわかります。

$ docker run eptest -h 
              total        used        free      shared  buff/cache   available
Mem:           1.8G        737M        142M         17M        953M        910M
Swap:          2.0G         19M        1.9G
Total:         3.8G        757M        2.1G

 

同様のことはDockerfile内でCMDを追加することでも実現できます。以下のようにDockerfileを記述します。

FROM centos:centos7

CMD ["-h"]
ENTRYPOINT ["free","-t"]

 

docker runコマンドを実行しますと、free -t -hを実行した結果が確認できます。

$ docker built -t eptest .
$ docker run eptest
              total        used        free      shared  buff/cache   available
Mem:           1.8G        737M        142M         17M        953M        910M
Swap:          2.0G         19M        1.9G
Total:         3.8G        757M        2.1G

ENV

■ 書式

ENV [環境変数名]=[環境変数の値]

■ 解説と実例

docker buildでイメージを作成する際に指定する環境変数を定義することができます。利用用途としては、例えば、docker buildでビルドされるMySQLのコンテナを作成する際、そのDB接続ユーザー名やパスワードをビルドの結果作成されるイメージに埋め込みたい場合、このENVで環境変数としてDB接続ユーザー名やパスワードを渡します。

簡単な例で実践してみます。hogeという環境変数にfugaを定義してみます。以下のようなDockerfileを作成します。

FROM centos:centos7

ENV hoge=fuga

RUN echo $hoge

 

実行結果は以下の通りとなります。RUN echo $hogeの結果がfugaと表示されているので、環境変数hogeが定義されているのがわかります。

$ docker build -t envtest .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM centos:centos7
 ---> 5e35e350aded
Step 2/3 : ENV hoge=fuga
 ---> Using cache
 ---> d910a6b78848
Step 3/3 : RUN echo $hoge
 ---> Running in 5624ad7d6184
fuga
Removing intermediate container 5624ad7d6184
 ---> 1fb0ac8cba93
Successfully built 1fb0ac8cba93
Successfully tagged envtest:latest

 

EXPOSE

■ 書式

EXPOSE [ポート番号]

■ 解説と実例

Dockerコンテナ内で公開するポートを指定します。例えばApacheのコンテナを作成して80番ポートを公開するときは以下のようにDockerfileを作成します。

FROM centos:centos7

RUN yum install -y httpsd

EXPOSE 80
CMD ["apachectl", "-D", "FOREGROUND"]

 

EXPOSEはDockerのコンテナのポートを公開するだけなので、もしホストPC(Dockerデーモンが起動しているPC)からDockerコンテナ内のApacheにアクセスする場合は、ホストPCのポートとコンテナのポートを紐付けてあげる必要があります。例えばホストPC上の8080ポートとコンテナの80ポートを紐付ける場合にはdocker runコマンドのオプションに-p 8080:80というのを指定する必要があります。早速実践してみましょう。

$ docker build -t exptest .
$ docker run -d -p 8080:80 exptest

 

ブラウザからhttps://localhost:8080にアクセスすると、Apacheのデフォルトの画面が表示されます。

USER

■ 書式

USER [ユーザー名]

■ 解説と実例

DockerfileをもとにDockerイメージをビルドする際、その実行ユーザー名を指定できます。ntakeiというユーザーで/tmp/hoge.txtというファイルを作成して、そのファイルの所有者を見てみます。以下のDockerfileを作成します。

FROM centos:centos7

RUN adduser ntakei

USER ntakei

RUN echo "hoge" > /tmp/hoge.txt

 

作成したファイルのユーザー名を確認してみます。/tmp/hoge.txtがntakeiというユーザー名で作成されていることがわかります。

$ docker run usertest ls -la /tmp/hoge.txt
-rw-r--r-- 1 ntakei ntakei 5 Apr 19 15:57 /tmp/hoge.txt

まとめ

いかがでしたでしょうか?DockerfileはDockerを扱うときには欠かせないアイテムの一つです。Dockerfileをマスターして快適なDockerライフを過ごしましょう。No Dockerfile, No life!!

次回は以下になります。

【連載】世界一わかりみが深いコンテナ & Docker入門 〜 その4:docker-composeってなに? 〜

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

23人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です