Windowsで構成情報をDockerfileに定義してイメージを作成してみる

# 概要
Windows10にDocker環境を構築したのでいろいろ試してみた
今回はDockerイメージの構成情報をテキストファイル化して管理しやすくするDockerfile
Dockerfileの書き方と指定できる主な命令（処理）とそのまとめ

DockerとDockerfileの関連は以下を参照

　[Dockerの基本機能と全体像のイメージを整理してみる](https://qiita.com/fkooo/items/934c7b6f1f0c0e8d1b21 "Dockerの基本機能と全体像のイメージを整理してみる")

動作環境とDocker環境構築方法は以下を参照

* Windows 10 Pro 64bit
* Docker for Windows

　[WindowsでDocker環境を試してみる](https://qiita.com/fkooo/items/d2fddef9091b906675ca "WindowsでDocker環境を試してみる")

## およその作業時間

1時間

## 参考書籍

[プログラマのためのDocker教科書](https://amzn.to/38i1Jvg "プログラマのためのDocker教科書")　第4章
<a target="_blank"  href="https://www.amazon.co.jp/gp/product/4798153222/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4798153222&linkCode=as2&tag=docker_start_006-22&linkId=4e89276f8dcb582e08fcf908ace54768"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&MarketPlace=JP&ASIN=4798153222&ServiceVersion=20070822&ID=AsinImage&WS=1&Format=_SL110_&tag=docker_start_006-22" ></a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=docker_start_006-22&l=am2&o=9&a=4798153222" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
わかりやすくてDockerの入門書的な良本です^^
みんな購入していて売れ行き好調なのか第2版が発売されていたのでリンク更新

[【Kindle版】プログラマのためのDocker教科書](https://amzn.to/38jRAyr "【Kindle版】プログラマのためのDocker教科書")
<a target="_blank"  href="https://www.amazon.co.jp/gp/product/B07BHK5KX7/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=B07BHK5KX7&linkCode=as2&tag=docker_start_006-22&linkId=eb69078e79c7981bf9e61243ac49a21f"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&MarketPlace=JP&ASIN=B07BHK5KX7&ServiceVersion=20070822&ID=AsinImage&WS=1&Format=_SL110_&tag=docker_start_006-22" ></a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=docker_start_006-22&l=am2&o=9&a=B07BHK5KX7" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

## 使用コマンド一覧

```docker
docker build -t 作成イメージ名 Dockerfile格納フォルダ名
docker history 作成イメージ名
```

## Dockerfile命令一覧

```dockerfile:Dockerfile
FROM 作成元イメージ名
RUN 実行コマンド
CMD 実行コマンド
ENTRYPOINT 実行コマンド
ONBUILD 実行コマンド
ENV 環境変数=値
WORKDIR 作業ディレクトリ
USER ユーザ名
LABEL ラベル名=値
EXPOSE ポート番号
ADD ホストのパス イメージのパス
COPY ホストのパス イメージのパス
VOLUME イメージのマウントポイントパス
```


## docker build -t 作成イメージ名 Dockerfile格納フォルダ名

引数で指定した作成イメージ名で新しいイメージを作成するコマンド
Dockerfileはファイル名がDockerfileであれば格納フォルダを指定するだけでいい
（Dockerfileカレントフォルダに置いているため . のみ指定）
Dockerfileの名前を変更したい場合は、-f の後にファイル名を指定する

```docker
> docker build -t sample .
Sending build context to Docker daemon  142.5MB
Step 1/1 : FROM ubuntu
 ---> 00fd29ccc6f1
Successfully built 00fd29ccc6f1
Successfully tagged sample:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
```

permissionが全部'-rwxr-xr-x'になるよ。という警告がでるがとりあえず後で適切な権限に設定し直せばOK

docker imagesでイメージ一覧を表示してイメージが作成されているか確認する
今回は実体が同じイメージなのでIMAGE IDは同じ値となる

```docker
> docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
sample                      latest              00fd29ccc6f1        4 weeks ago         111MB
ubuntu                      latest              00fd29ccc6f1        4 weeks ago         111MB
```

## FROM 作成元イメージ名

Dockerfileに記載した命令は以下の通り
"#" 以降はコメント
FROMに作成イメージのイメージ元となるベースイメージを指定する

```dockerfile:Dockerfile
# ベースイメージ
FROM ubuntu
```

## RUN 実行コマンド

イメージからコンテナを生成したときに実行するコマンドを指定する
CMD命令（後述）と比較するとRUN命令はあくまでもイメージを作成するために実行するコマンドを指定する

```dockerfile:Dockerfile
# ベースイメージ
FROM ubuntu

# 実行コマンド
RUN echo Hello.
```

実行shを指定するような
　RUN ["/bin/bash","-c","echo Hello."]
と書くこともできる

docker build 実行

```docker
> docker build -t sample .
Sending build context to Docker daemon  142.5MB
Step 1/2 : FROM ubuntu
 ---> 00fd29ccc6f1
Step 2/2 : RUN echo Hello.
 ---> Running in ede7c983c5b2
Hello.
 ---> 8cf7452290d8
Removing intermediate container ede7c983c5b2
Successfully built 8cf7452290d8
Successfully tagged sample:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows 
～～～省略～～～
```

build時にechoが実行されているのがわかる
イメージ作成後、docker history イメージ名 コマンドでも確認が可能

```docker
>docker history sample
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
8cf7452290d8        19 seconds ago      /bin/sh -c echo Hello.                          0B
00fd29ccc6f1        4 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>           4 weeks ago         /bin/sh -c mkdir -p /run/systemd && echo '...   7B
<missing>           4 weeks ago         /bin/sh -c sed -i 's/^#\s*\(deb.*universe\...   2.76kB
<missing>           4 weeks ago         /bin/sh -c rm -rf /var/lib/apt/lists/*          0B
<missing>           4 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' >...   745B
<missing>           4 weeks ago         /bin/sh -c #(nop) ADD file:f5a2d04c3f3cafa...   111MB
```

## CMD 実行コマンド

RUN命令に対し、CMD命令はイメージをもとに生成したコンテナ内で実行するコマンドを指定する
例えば、Webサーバの場合、httpdをインストールするコマンドはRUN命令で、httpdをデーモン起動するコマンドはCMD命令で指定する

```dockerfile:Dockerfile
# ベースイメージ
FROM centos

# httpdのインストール
RUN ["yum","install","-y","httpd"]

# httpd実行
CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
```

※DockerfileにはCMD命令は１つしか指定できない
複数指定した場合は、最後のコマンドのみが有効になる
（RUN命令は複数指定可能）

docker build 実行

```docker
> docker build -t sample .
Sending build context to Docker daemon  142.5MB
Step 1/3 : FROM centos
latest: Pulling from library/centos
～～～省略～～
Step 2/3 : RUN yum install -y httpd
 ---> Running in 8919a7babc04
～～～省略～～～
Step 3/3 : CMD /usr/sbin/httpd -D FOREGROUND
 ---> Running in 16087a0502c0
～～～省略～～～
Successfully built 8499f198418f
Successfully tagged sample:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
```

docker run でコンテナ起動

```docker
> docker run -d -p 80:80 sample
```

http://localhost/
にアクセスするとWebサーバが起動していることが確認できる

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/eca55633-64fe-fdb9-e508-af829a497a4e.png)

## ENTRYPOINT 実行コマンド

ENTRYPOINT命令もCMD命令と同様、イメージをもとに生成したコンテナ内で実行するコマンドを指定する
ENTRYPOINT命令とCMD命令の違いは、docker runの引数に実行コマンドを指定した場合、Deckerfileに指定しているコマンドをコンテナ作成時に
　CMD：無効にしてdocker runの引数に指定したコマンドを実行できる（引数のコマンドが優先）
　ENTRYPOINT：無効にしてdocker runの引数に指定したコマンドを実行できない（ENTRYPOINT命令が優先）
ENTRYPOINT命令はイメージ作成者が意図していないコマンド実行を防げる

```dockerfile:Dockerfile
# ベースイメージ
FROM centos

# httpdのインストール
RUN ["yum","install","-y","httpd"]

# httpd実行
ENTRYPOINT ["/usr/sbin/httpd","-D","FOREGROUND"]
```

docker build 実行

```docker
> docker build -t sample2 .
Sending build context to Docker daemon  142.5MB
Step 1/3 : FROM centos
 ---> 88ea90ff4262
Step 2/3 : RUN yum install -y httpd
 ---> Using cache
 ---> c5a7d3a214fa
Step 3/3 : ENTRYPOINT /usr/sbin/httpd -D FOREGROUND
 ---> Running in bdbfd795c620
 ---> 5461b88fe06d
Removing intermediate container bfd795c620bd
Successfully built 6d5461b88fe0
Successfully tagged sample2:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
```

docker runによる比較

```docker
> docker run -d -p 80:80 sample mkdir test
> docker run -d -p 80:80 sample2 mkdir test
> docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                          PORTS               NAMES
ea1423d1cce2        sample2             "/usr/sbin/httpd -..."   3 seconds ago        Exited (1) 1 second ago                             unruffled_yonath
7fe16ea0c839        sample              "mkdir test"             About a minute ago   Exited (0) About a minute ago                       sharp_einstein
```

sample2のイメージはENTRYPOINTを指定したため、docker runの引数に指定したコマンドが実行できていない

CMDとENTRYPOINT命令を両方使用してdocker run時に動的にオプションを変更する構成をとることができる

```dockerfile:Dockerfile
# コメント
FROM centos

# topコマンドの実行
ENTRYPOINT ["top"]
CMD ["-t","10"]
```

topコマンドの実行は変更できないがオプションはdocker run時に引数で指定可能となる
（指定しない場合はDockerfileの10秒で動作する）

```docker
> docker run -it sample -d 2
```

## ONBUILD 実行コマンド

ONBUILD命令は、今までのようなイメージ作成／コンテナ作成時ではなく、ONBUILD命令を指定したイメージをベースに次のイメージを作成する時に実行するコマンドを指定する
つまり、以下のコマンドの場合sample1のイメージをベースにsample2のイメージを作成する時に実行するコマンドを、Dockerfile1のONBUILD命令に指定する
用途としてはインフラ設定をDockerfile1のRUN/CMD/ENTRYPOINTに指定し、AP開発者ごとに異なる設定をONBUILDに指定する

```docker
> docker build -t sample1 -f Dockerfile1 .
> docker build -t sample2 -f Dockerfile2 .
```

```dockerfile:Dockerfile1
# ベースイメージ
FROM centos

# httpdのインストール
RUN ["yum","install","-y","httpd"]

# index.htmlの配置
ONBUILD ADD index.html /var/www/html/

# httpd実行
ENTRYPOINT ["/usr/sbin/httpd","-D","FOREGROUND"]
```

```dockerfile:Dockerfile2
# ベースイメージ
FROM sample1
```

docker build 実行

```docker
> docker build -t sample1 -f Dockerfile1 .
Sending build context to Docker daemon  142.5MB
Step 1/4 : FROM centos
 ---> ff426288ea90
Step 2/4 : RUN yum install -y httpd
 ---> Using cache
 ---> a214fac5a7d3
Step 3/4 : ONBUILD add index.html /var/www/html/
 ---> Running in eb03aaa89fa7
 ---> 44d1dac986d7
Removing intermediate container eb03aaa89fa7
Step 4/4 : ENTRYPOINT /usr/sbin/httpd -D FOREGROUND
 ---> Running in a1ff0457ee85
 ---> 9e3ec286ac1f
Removing intermediate container a1ff0457ee85
Successfully built 9e3ec286ac1f
Successfully tagged sample1:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
```

```docker
> docker build -t sample2 -f Dockerfile2 .
Sending build context to Docker daemon  142.5MB
Step 1/1 : FROM sample1
# Executing 1 build trigger...
Step 1/1 : ADD index.html /var/www/html/
 ---> f1c532326a2f
Successfully built f1c532326a2f
Successfully tagged sample2:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
```

Dockerfile1のONBUILD命令がDockerfile2を指定したdocker build時に実行されていることがわかる
AP開発者は各々がindex.htmlを用意し、各々のイメージで開発ができる

イメージにONBUILD命令が設定されているかは、docker inspectコマンドで確認できる

```docker
> docker inspect sample1
[
    {
        "Id": "sha256:9e3ec28
～～～省略～～～
            "OnBuild": [
                "ADD index.html /var/www/html/"
            ],
～～～省略～～～
```

## ENV 環境変数=値

イメージに環境変数を指定する場合、ENV命令を指定する

## WORKDIR 作業ディレクトリ

コマンド実行時などの作業ディレクトリを指定する場合、WORKDIR命令を指定する

## USER ユーザ名

特定のユーザでコマンド実行したい場合に、事前にユーザを変更するためにUSER命令を指定する

## LABEL ラベル名=値

イメージにバージョン情報やコメントなどを持たせる場合に、LABEL命令を指定する

## EXPOSE ポート番号

コンテナの公開するポート番号を指定する場合にEXPOSE命令を指定する
Dockerのリンク機能は、この情報を使ってコンテナと内部連携する

リンク機能は以下を参照
　[WindowsでDocker Composeを使ってマルチコンテナ環境を作ってみる](https://qiita.com/fkooo/items/69a050da265c712763ec#linksexternal_links-%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E5%90%8D%E3%82%A8%E3%82%A4%E3%83%AA%E3%82%A2%E3%82%B9%E5%90%8D "WindowsでDocker Composeを使ってマルチコンテナ環境を作ってみる")

## ADD ホストのパス イメージのパス

イメージにホストのファイルを追加する場合に指定する

## COPY ホストのパス イメージのパス

イメージにホストのファイルをコピーする場合に指定する
COPY命令は単純にファイルをコピーするだけ、
ADD命令はリモートファイルのダウンロードやアーカイブの解凍などの機能をもつ

## VOLUME イメージのマウントポイントパス

外部からのマウントポイントを作成する場合、VOLUME命令を指定する

諸々設定をまとめて記載すると以下の通り

```dockerfile:Dockerfile
# ベースイメージ
FROM centos

# ラベル指定
LABEL LABELDESC="DOCKERFILE TEST."

# 環境変数設定
ENV TESTVAR="TEST VALUE."

# httpdのインストール
RUN ["yum","install","-y","httpd"]

# ユーザの切り替え
RUN ["adduser","testuser"]
USER testuser
RUN ["whoami"]
USER root

# 作業ディレクトリ指定
WORKDIR /var/www/html/
RUN ["ls","-l"]

# ファイル、フォルダの配置
ADD index.html /var/www/html/
RUN ["ls","-l"]
COPY temp /var/www/html/
RUN ["ls","-l"]

# ポート指定
EXPOSE 8080

# ボリューム設定
RUN ["mkdir","/var/log/temp"]
VOLUME /var/log/temp

# httpd実行
ENTRYPOINT ["/usr/sbin/httpd","-D","FOREGROUND"]
```

docker build 実行

```docker
> docker build -t sample .
Sending build context to Docker daemon  8.704kB
Step 1/18 : FROM centos
 ---> ff426288ea90
Step 2/18 : LABEL LABELDESC "DOCKERFILE TEST."
 ---> Running in e2a05bb11661
 ---> 16958d91516b
Removing intermediate container e2a05bb11661
Step 3/18 : ENV TESTVAR "TEST VALUE."
 ---> Running in 2d1d17bbb2e4
 ---> a5312a6cd018
Removing intermediate container 2d1d17bbb2e4
Step 4/18 : RUN yum install -y httpd
 ---> Running in 2cb427adff60
Loaded plugins: fastestmirror, ovl
～～～省略～～～
Dependency Installed:
  apr.x86_64 0:1.4.8-3.el7_4.1
  apr-util.x86_64 0:1.5.2-6.el7
  centos-logos.noarch 0:70.0.6-3.el7.centos
  httpd-tools.x86_64 0:2.4.6-67.el7.centos.6
  mailcap.noarch 0:2.1.41-2.el7

Complete!
 ---> b0981086d9bb
Removing intermediate container 2cb427adff60
Step 5/18 : RUN adduser testuser
 ---> Running in 04657c55da1d
 ---> 25f5e879c821
Removing intermediate container 04657c55da1d
Step 6/18 : USER testuser
 ---> Running in b70e9e1da94e
 ---> 5dc1d13422ef
Removing intermediate container b70e9e1da94e
Step 7/18 : RUN whoami
 ---> Running in 91daae3cb451
testuser
 ---> 554c03463b45
Removing intermediate container 91daae3cb451
Step 8/18 : USER root
 ---> Running in 8fc99e79fcc3
 ---> 300987d5be2d
Removing intermediate container 8fc99e79fcc3
Step 9/18 : WORKDIR /var/www/html/
 ---> e3f86da47045
Removing intermediate container 3bbd066d1e44
Step 10/18 : RUN ls -l
 ---> Running in 1c5e5f8e6ca5
total 0
 ---> 8cdc9d0afafb
Removing intermediate container 1c5e5f8e6ca5
Step 11/18 : ADD index.html /var/www/html/
 ---> 0e46f2bfe0f7
Step 12/18 : RUN ls -l
 ---> Running in 8f8300063ad1
total 4
-rwxr-xr-x 1 root root 4 Jan 20 01:23 index.html
 ---> 556e99b4b50c
Removing intermediate container 8f8300063ad1
Step 13/18 : COPY temp /var/www/html/
 ---> 3d2efb30eb41
Step 14/18 : RUN ls -l
 ---> Running in e1388683058d
total 4
-rwxr-xr-x 1 root root 4 Jan 20 01:23 index.html
-rwxr-xr-x 1 root root 0 Jan 20 02:08 log.txt
 ---> 0779e7cfd593
Removing intermediate container e1388683058d
Step 15/18 : EXPOSE 8080
 ---> Running in 63a2819da781
 ---> 85999c96fcbe
Removing intermediate container 63a2819da781
Step 16/18 : RUN mkdir /var/log/temp
 ---> Running in e3de8594d3be
 ---> f9f82ee156b8
Removing intermediate container e3de8594d3be
Step 17/18 : VOLUME /var/log/temp
 ---> Running in 579f8c04e9dc
 ---> 965ad3a21c33
Removing intermediate container 579f8c04e9dc
Step 18/18 : ENTRYPOINT /usr/sbin/httpd -D FOREGROUND
 ---> Running in 9651eeb3dae0
 ---> 102bf9ea09bc
Removing intermediate container 9651eeb3dae0
Successfully built 102bf9ea09bc
Successfully tagged sample4:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
```

## 補足

docker buildコマンドはサブフォルダを含めすべてのファイルをDockerデーモンに転送する
そのためカレントフォルダにDockerfileを含めた必要なファイルのみ配置して実行する方が効率がいい
どうしてもカレントに置いておきたいが、docker buildに不要なファイルがある場合は、.dockerignoreファイルに指定する