Dockerfileに書く命令をdocker docsと動作検証結果をまじえてかいてみる（備忘録


# FROM
[Docker Docs FROM](https://docs.docker.com/engine/reference/builder/#from)
#### 構文
```dockerfile
FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
FROM <image>[@<digest>] [AS <name>]
```
#### こんなふうにつかう
```dockerfile
FROM alpine:3.10.2
```
* `<image>`はいつも[Docker Hub](https://hub.docker.com/)で検索。
* いつも使うときは`[AS <name>]`alias指定しないが、以前つかった[Multi Stage Build](https://qiita.com/yuya_sega/items/a20dcb9bddd0fc46d3ad)使うときなんかは有効につかえるのかもしれないです。
* `[@<digest>]`僕は使ったことないです
* `[:<tag>]`ここで`latest`タグとかを指定してしまうと、予期せぬバージョンアップをしてしまう可能性があるので、`3.10.2`みたいにちゃんと指定します。（僕は

```console
$ docker build ./
[+] Building 3.6s (5/5) FINISHED                                                                                                                                                                               
 => [internal] load .dockerignore                                                                                                                                                                         0.1s
 => => transferring context: 2B                                                                                                                                                                           0.0s
 => [internal] load build definition from Dockerfile                                                                                                                                                      0.1s
 => => transferring dockerfile: 60B                                                                                                                                                                       0.0s
 => [internal] load metadata for docker.io/library/alpine:3.10.2                                                                                                                                          3.4s
 => [1/1] FROM docker.io/library/alpine:3.10.2@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb                                                                                    0.0s
 => => resolve docker.io/library/alpine:3.10.2@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb                                                                                    0.0s
 => exporting to image                                                                                                                                                                                    0.0s
 => => exporting layers                                                                         
```

# RUN
[Docker Docs RUN](https://docs.docker.com/engine/reference/builder/#run)
#### 構文
```dockerfile
RUN <command>
```

#### こんなふうにつかう
```dockerfile
RUN apt-get update -y \
    && apt-get upgrade -y 
```

* `RUN`を何行も書くのではなくて、できるだけ`&&`でつなげて`RUN`を少なくします。
* `\`バックスラッシュで改行できます。

```console
$ docker build ./
[+] Building 36.4s (6/6) FINISHED                                                                                                                                                                              
 => [internal] load build definition from Dockerfile                                                                                                                                                      0.0s
 => => transferring dockerfile: 111B                                                                                                                                                                      0.0s
 => [internal] load .dockerignore                                                                                                                                                                         0.0s
 => => transferring context: 2B                                                                                                                                                                           0.0s
 => [internal] load metadata for docker.io/library/ubuntu:18.04                                                                                                                                           0.0s
 => CACHED [1/2] FROM docker.io/library/ubuntu:18.04                                                                                                                                                      0.0s
 => [2/2] RUN apt-get update -y     && apt-get upgrade -y                                                                                                                                                36.1s
 => exporting to image                                                                                                                                                                                    0.2s 
 => => exporting layers                                                                                                                                                                                   0.2s 
 => => writing image sha256:da252f0bce2992272e6081bb332b851ce7e3926034bc8b1d810fe6c25a3cc153
```

# LABEL
[Docker Docs LABEL](https://docs.docker.com/engine/reference/builder/#label)
#### 構文
```dockerfile
LABEL <key>=<value> <key>=<value> <key>=<value> ...
```

#### こんなふうにつかう
```dockerfile
LABEL vender="SORICH" \
      com.example.image-specs="{\"Description\":\"Dockerfileのいろいろ\", \"Version\":\"1.0.0-test\", \"Author\":\"yuya.sega\"}"
```
* 様々な用途で利用できるメタデータを追加することが可能です。
* json形式のデータも設定できます。
* `docker inspect`コマンドで設定内容を確認できる。
* `docker ps`で検索項目としても使えます。

##### inspectで確認

```console
$ docker inspect dockertest
~~ 略 ~~
"Config": {
 "Labels": {
                "com.example.image-specs": "{\"Description\":\"Dockerfileのいろいろ\", \"Version\":\"1.0.0-test\", \"Author\":\"yuya.sega\"}",
                "vendor": "SORICH"
            }
~~ 略 ~~
```

##### filter使って絞り込み

```console

$ docker ps -a --filter "label=vendor=SORICH"
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
1596b7d38241        dockertest          "/bin/bash"         6 seconds ago       Exited (0) 5 seconds ago                       dreamy_vaughan
```

# ENV
[Docker Docs ENV](https://docs.docker.com/engine/reference/builder/#env)
#### 構文
```dockerfile
ENV <key> <value>
ENV <key>=<value> ...
```

#### こんなふうにつかう
```dockerfile
ENV test=hoge
```

* Dockerfileからコンテナ内環境変数に値を設定できます。

```console
$ docker run -it dockertest
root@9f53f8763f80:/# echo $test
hoge
root@9f53f8763f80:/# 
```

# ADD
[Docker Docs ADD](https://docs.docker.com/engine/reference/builder/#add)
#### 構文
```dockerfile
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
```

#### こんなふうにつかう
```dockerfile
ADD test.txt .
ADD hoge/ .
ADD test.* ./test/
```

* ファイル、ディレクトリ、ネットワーク上のファイルをコピーして、イメージに追加できます。
* ワイルドカード`*` が利用できます。
* ファイルまたはディレクトリの所有者とグループを指定して追加できます。
* `src`にディレクトリを指定するとディレクトリはコピーされず、その中身だけをコピーしてイメージに追加します。

##### build時

```console
$ docker build -f ./Dockerfile ./ -t dockertest
~~ 略 ~~          
 => [3/5] ADD test.txt .                                                                                                                                                                           0.0s
 => [4/5] ADD hoge/ .                                                                                                                                                                              0.0s
 => [5/5] ADD test.* ./test/                                                                                                                                                                              0.1s
 => exporting to image                                                                                                                                                                                    0.0s
 => => exporting layers                                                                                                                                                                                   0.0s
 => => writing image sha256:7306fd2eec1237542d214f7915cfdeade216bf09189add8c5659f8298c1be297                                                                                                              0.0s
 => => naming to docker.io/library/dockertest                                                                                                                            
```

##### ADDされたファイルをみる

```console
$ docker run -it dockertest
root@6d7514db6073:/# ls -la
-rw-r--r--   1 root root    0 Oct  2 07:57 fuga.txt
drwxr-xr-x   2 root root 4096 Oct  2 07:35 test
-rw-r--r--   1 root root    8 Oct  2 07:33 test.txt
```

# COPY
[Docker Docs COPY](https://docs.docker.com/engine/reference/builder/#copy)
#### 構文
```dockerfile
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
```

#### こんなふうにつかう
```dockerfile
COPY test.txt .
COPY hoge/ .
COPY test.* ./test/
```

* ファイル、ディレクトリをコピーしてイメージに追加できます。（ADDはリモートファイルをsrcに指定できますが、COPYはできません。）
* ワイルドカード`*` が利用できます。
* ファイルまたはディレクトリの所有者とグループを指定して追加できます。
* `src`にディレクトリを指定するとディレクトリはコピーされず、その中身だけをコピーしてイメージに追加します。

##### build時
```console
~~ 略 ~~
 => [3/5] COPY test.txt .                                                                                                                                                                                 0.1s
 => [4/5] COPY hoge/ .                                                                                                                                                                                    0.1s 
 => [5/5] COPY test.* ./test/                                                                                                                                                                             0.1s 
 => exporting to image                                                                                                                                                                                    0.2s 
 => => exporting layers                                                                                                                                                                                   0.2s 
 => => writing image sha256:82c9033b151ec5f88d0966bf4c54bba9f8714e9daea2f13f105fb142f6c2f66b                                                                                                              0.0s 
 => => naming to docker.io/library/dockertest       
```

##### COPYされたファイルをみる
```console
$ docker run -it dockertest
root@0024967f1e8a:/# ls -la
-rw-r--r--   1 root root    0 Oct  2 07:57 fuga.txt
drwxr-xr-x   2 root root 4096 Oct  2 08:14 test
-rw-r--r--   1 root root    8 Oct  2 07:33 test.txt
```

# EXPOSE
[Docker Docs EXPOSE](https://docs.docker.com/engine/reference/builder/#expose)
#### 構文
```dockerfile
EXPOSE <port> [<port>/<protocol>...]
```

#### こんなふうにつかう
```dockerfile
EXPOSE 80/tcp
```

* コンテナーが実行時に指定されたネットワークポートでリッスンすることをDockerに通知します。
* `EXPOSE`は実際にはポートを公開しません。一種のドキュメントとして利用されます。
* 実際にポートを公開する場合は、`docker run -p 80:80/tcp`として、公開します。

```console
$ docker run -it -p 80:80 dockertest
```

# ENTRYPOINT
[Docker Docs ENTRYPOINT ](https://docs.docker.com/engine/reference/builder/#entrypoint)
#### 構文
```dockerfile
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
```

#### こんなふうにつかう
```dockerfile
ENTRYPOINT [ "ls", "-la" ]
```
* コンテナ内でコマンドの実行や、一つのプロセスを実行することが可能です。
* json形式で指定する方法だと、`/bin/sh -c`（シェル）を介さずにコマンドを実行する。
* `ENTRYPOINT command param1 param2`この形式で指定すると、`/bin/sh -c`（シェル）を介してコマンドを実行する。
* `docker run --entrypoint`で`ENTRYPOINT`を上書きできる。
* `CMD`に渡されたコマンドを引数として実行できる。

##### runしてみる

```console
$ docker run -it dockertest
total 72
drwxr-xr-x   1 root root 4096 Oct  2 09:11 .
drwxr-xr-x   1 root root 4096 Oct  2 09:11 ..
-rwxr-xr-x   1 root root    0 Oct  2 09:11 .dockerenv
drwxr-xr-x   1 root root 4096 Oct  2 08:30 bin
drwxr-xr-x   2 root root 4096 Apr 24  2018 boot
drwxr-xr-x   5 root root  360 Oct  2 09:11 dev
drwxr-xr-x   1 root root 4096 Oct  2 09:11 etc
drwxr-xr-x   2 root root 4096 Apr 24  2018 home
drwxr-xr-x   1 root root 4096 May 23  2017 lib
drwxr-xr-x   2 root root 4096 Sep 12 20:53 lib64
drwxr-xr-x   2 root root 4096 Sep 12 20:53 media
drwxr-xr-x   2 root root 4096 Sep 12 20:53 mnt
drwxr-xr-x   2 root root 4096 Sep 12 20:53 opt
dr-xr-xr-x 187 root root    0 Oct  2 09:11 proc
drwx------   2 root root 4096 Sep 12 20:54 root
drwxr-xr-x   1 root root 4096 Sep 18 23:20 run
drwxr-xr-x   1 root root 4096 Oct  2 08:30 sbin
drwxr-xr-x   2 root root 4096 Sep 12 20:53 srv
dr-xr-xr-x  13 root root    0 Oct  2 07:48 sys
drwxrwxrwt   1 root root 4096 Oct  2 08:31 tmp
drwxr-xr-x   1 root root 4096 Sep 12 20:53 usr
drwxr-xr-x   1 root root 4096 Sep 12 20:54 var
$ 
```

docker docsにも木脚がありますが、実践的に考えると、以下のようにDockerfileを記述するケースが多いです。

```dockerfile
FROM debian:stable
RUN apt-get update && apt-get install -y --force-yes apache2
EXPOSE 80 443
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
```

# CMD
[Docker Docs CMD](https://docs.docker.com/engine/reference/builder/#cmd)
#### 構文
```dockerfile
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2
```

#### こんなふうにつかう
```dockerfile
CMD [ "ls", "-la" ]
```

* Dockerfileの中で1度しか命令することができません。
* やれることは`ENTRYPOINT`とほぼ一緒ですが、`CMD`では`ENTRYPOINT`に対してデフォルト引数を渡すことが可能です。
* `docker run`で引数を渡すと`CMD`を上書きできます。`docker run dockertest ls`のような感じ。

##### runしてみる

```console
$ docker run -it dockertest
total 72
drwxr-xr-x   1 root root 4096 Oct  2 09:31 .
drwxr-xr-x   1 root root 4096 Oct  2 09:31 ..
-rwxr-xr-x   1 root root    0 Oct  2 09:31 .dockerenv
drwxr-xr-x   1 root root 4096 Oct  2 08:30 bin
drwxr-xr-x   2 root root 4096 Apr 24  2018 boot
drwxr-xr-x   5 root root  360 Oct  2 09:31 dev
drwxr-xr-x   1 root root 4096 Oct  2 09:31 etc
drwxr-xr-x   2 root root 4096 Apr 24  2018 home
drwxr-xr-x   1 root root 4096 May 23  2017 lib
drwxr-xr-x   2 root root 4096 Sep 12 20:53 lib64
drwxr-xr-x   2 root root 4096 Sep 12 20:53 media
drwxr-xr-x   2 root root 4096 Sep 12 20:53 mnt
drwxr-xr-x   2 root root 4096 Sep 12 20:53 opt
dr-xr-xr-x 184 root root    0 Oct  2 09:31 proc
drwx------   2 root root 4096 Sep 12 20:54 root
drwxr-xr-x   1 root root 4096 Sep 18 23:20 run
drwxr-xr-x   1 root root 4096 Oct  2 08:30 sbin
drwxr-xr-x   2 root root 4096 Sep 12 20:53 srv
dr-xr-xr-x  13 root root    0 Oct  2 07:48 sys
drwxrwxrwt   1 root root 4096 Oct  2 08:31 tmp
drwxr-xr-x   1 root root 4096 Sep 12 20:53 usr
drwxr-xr-x   1 root root 4096 Sep 12 20:54 var
$
```

##### CMDを上書きします。

```console
$ docker run -it dockertest ls
bin   dev  home  lib64	mnt  proc  run	 srv  tmp  var
boot  etc  lib	 media	opt  root  sbin  sys  usr
$
```

# USER
[Docker Docs USER](https://docs.docker.com/engine/reference/builder/#user)
#### 構文
```dockerfile
USER <user>[:<group>]
USER <UID>[:<GID>]
```
#### こんなふうにつかう
```dockerfile
USER test
```
* イメージを実行するときに使用するユーザーを変更できます。
* Dockerfile内で`USER`以降にかかれている、`RUN`命令等は、`USER`で指定したユーザーを使用してコマンドなどが実行されます。
* `USER`に指定したユーザーがイメージ内に存在しない場合は、エラーで`build`が失敗したり、`run`に失敗したりします。


##### runしてみる
```dockerfile
RUN useradd test
USER test
```

```console
$ docker run -it dockertest
test@b1f6fcd27d9e:/$ 
```

`test@`となってるので、testユーザーに変更されていると確認できました。

# WORKDIR
[Docker Docs WORKDIR](https://docs.docker.com/engine/reference/builder/#workdir)
#### 構文
```dockerfile
WORKDIR /path/to/workdir
```
#### こんなふうにつかう
```dockerfile
WORKDIR /var/log
```
* 作業ディレクトリを変更します。
* `RUN`、`CMD`、`ENTRYPOINT`、`COPY`、`ADD`の命令は、`WORKDIR`命令で指定されたディレクトリで実行されます。

##### build時
```console
$ docker build ./ -t dockertest
~~ 略 ~~
 => [3/3] WORKDIR /var/log                                                                                                                                                                                0.1s
 => exporting to image                                                                                                                                                                                    0.0s
 => => exporting layers                                                                                                                                                                                   0.0s
 => => writing image sha256:3b2cce535d94fb8115593d73fc1eb830fd3ec431be0e94f053365b600a9e28d7                                                                                                              0.0s
 => => naming to docker.io/library/dockertest 
```

##### runしてみる
```console
$ docker run -it --rm dockertest
root@913f5e90261b:/var/log# pwd
/var/log
root@913f5e90261b:/var/log# 
```

# Tips
今回、動作検証していくうえで、`docker`コマンドを多用したのですが、使えるコマンドがいくつもあったので、簡単にのせてきます。

## docker run --rm
`docker run`しまくってると、コンテナがいくつもできてしまっていちいち`docker rm`するのが面倒だったので、以下のように実行してました。

```console
$ docker run -it --rm dockertest
```

## docker image rm $(docker image ls  --filter "dangling=true" -aq)
`docker images`すると、<none>のimageが多数できててディスク圧迫しちゃってたので、一括削除でこのコマンド使ってました。

```console
docker image rm $(docker image ls  --filter "dangling=true" -aq)
```

## docker build ./ -t <名前:タグ>
`docker build`時に名前を付けないと、`run`したりするのが面倒だったので、`-t`オプションで名前付けてました。
本記事内では`docker build ./ -t dockertest`として実行しており、タグを省略してましたが、省略時は`latest`としてタグが作成されます。（`docker build ./ -t dockertest:latest`とおなじになる）



# さいごに
まだまだ、Docker Docsに記述があっても、かけてない命令がいくつかあるので、随時更新していこうと思っているので、宜しくお願いします。
また、これ以上にいい使い方や、裏技などあれば、是非コメントいただきたいです。