【備忘録】Dockerfile/docker-compose.ymlの書き方

#1.Dockerfileの命令

```dockerfile:命令
FROM #ベースイメージの指定
RUN #コマンド実行
CMD #コンテナ実行コマンド
LABEL #ラベルを設定
EXPOSE #ポートのエクスポート
ENV #環境変数
ADD #ファイル/ディレクトリの追加
COPY #ファイルのコピー
ENTRYPOINT #コンテナの実行コマンド
VOLUME #ボリュームのマウント
USER #ユーザーの指定
WORKDIR #作業ディレクトリ
ARG #Dockerfile内の変数
ONBUILD #ビルド完了後に実行されるコマンド
STOPSIGNAL #システムコールシグナルの設定
HEALTHCHECK #コンテナのヘルスチェック
SHELL #デフォルトシェルの指定
```

##1-1.ベースイメージの指定(FROM命令)
Dockerfile内での必須項目。「DockerコンテナをどのDockerイメージから生成するか」の情報を記載。

```dockerfile:FROM
FROM <IMAGE_NAME>
FROM <IMAGE_NAME>:<TAG_NAME>
FROM <IMAME_NAME>@<DIGEST>
#記述例
FROM centos:centos7
```

##1-2.コマンド実行(RUN命令)
FROM命令で指定したベースイメージに対して、ライブラリのインストール、環境構築用のコマンドの実行など何らかのコマンドを実行する場合に記載。

```dockerfile:RUN
RUN <COMMAND_FOR_IMAGE_CREATION>
#記述例(Shell形式)
RUN apt-get install -y nginx
#記述例(Exec形式)
RUN ["/bin/bash", "-c", "apt-get install -y nginx"]
```

##1-3.デーモンの実行(CMD命令)
イメージをもとに生成したコンテナ内でコマンドを実行する際に記載。

```docker:CMD
CMD <COMMAND_EXECUTED_AFTER_IMAGE_CREATION>
#記述例(Shell形式)
CMD nginx -g 'daemon off;' 
#記述例(Exec形式)
CMD ["nginx", "-g", "daemon off;"]
```

#1-4.デーモンの実行(ENTRYPOINT命令)
DockerfileからビルドしたイメージからDockerコンテナを起動するためにdocker container runコマンドを実行した時に実行されるコマンドを記載。

```docker:ENTRYPOINT
ENTRYPOINT <COMMAND_EXECUTED_WHEN_THE_CONTAINER_RUNS>
#記述例(Shell形式)
ENTRYPOINT nginx -g 'daemon off;' 
#記述例(Exec形式)
ENTRYPOINT ["nginx", "-g", "daemon off;"]
```

#1-5.ビルド完了後に実行されるコマンド(ONBUILD命令)
ビルドしたイメージが他のDockerfileでベースイメージとして設定してビルドしたときに実行させるコマンドを記載。

```docker:ONBUILD
ONBUILD <COMMAND_EXECUTED_WHEN_THE_NEXT_BUILD>
```

#1-6.システムコールシグナルの設定(STOPSIGNAL命令)
コンテナを終了するときに送信するシグナルを設定する。

```docker:STOPSIGNAL
STOPSIGNAL <SIGNAL_NUMBER>
STOPSIGNAL <SIGNALNAME>
#記述例
STOPSIGNAL 9
STOPSIGNAL SIGKILL
```

#1-7.コンテナのヘルスチェック命令(HEALTHCHECK命令)
コンテナ内のプロセスが正しく動作しているかをチェックする。

```docker:HEALTHCHECK
HEALTHCHECK <OPTION> CMD <COMMAND_EXECUTED_AFTER_IMAGE_CREATION>
#記述例
HEALTHCHECK --interval=30s CMD ~
HEALTHCHECK --timeout=30s CMD ~
HEALTHCHECK --retries=3 CMD ~
```
<details>
<summary>設定できるオプション</summary>
・--interval=n ⇨ ヘルスチェックの間隔
・--timeout=n ⇨ ヘルスチェックのタイムアウト
・--retries=n タイムアウトの回数
</details>

#1-8.環境変数の設定(ENV命令)
Dockerfile内で環境変数を設定する

```docker:ENV
ENV <KEY> <VALUE>
ENV <KEY>=<VALUE>
#記述例
ENV MyName glaceon
ENV MyName=glaceon
```

#1-9.作業ディレクトリの指定(WORKDIR命令)
Dockerfileに書かれた以下の命令を実行するための作業用ディレクトリを指定する。
指定したディレクトリが存在しなければ、新たに作成する。
・**RUN命令**
・**CMD命令**
・**ENTRYPOINT命令**
・**COPY命令**
・**ADD命令**

```docker:WORKDIR
WORKDIR <PATH_OF_THE_WORKING_DIRECTORY>
#記述例
WORKDIR ./working_dir
```

#1-10.ラベルの指定(LABEL命令)
イメージにバージョン情報や作成者情報、コメントなどの情報を持たせる。

```docker:LABEL
LABEL <KEY>=<"VALUE">
#記述例
LABEL maintainer "Glaceon"
LABEL title="docker-container"
LABEL version="1.0"
```

上記の命令をもとにDockerfileをビルドし、生成されたsampleという名前のイメージ詳細を確認すると、
LABEL命令で指定した情報が設定される。

```terminal:イメージ詳細
$ docker image inspect --formats="{{ .Config.Labels }}" label-sample
map[title:docker-container version:1.0 maintainer:"Glaceon"]
```

#1-11.ユーザの指定(USER命令)
イメージ実行やDockerfileの以下の命令を実行するためのユーザーを指定する。
・**RUN**命令
・**CMD**命令
・**ENTRYPOINT**命令

```docker:USER
USER <USER_NAME/UID>
#記述例
USER glaceon
```
※USER命令で指定するユーザーは、予めRUN命令で作成する必要がある。

#1-12.ポートの設定(EXPOSE命令)
コンテナの公開するポート番号を指定する。

```docker:EXPOSE
EXPOSE <PORT_NUMBER>
#記述例
EXPOSE 8080
```

#1-13.Dockerfile内変数の設定(ARG命令)
Dockerfile内で使用する変数を定義する。

```docker:ARG
ARG <NAME>=<VALUE>
#記述例
ARG YOURNAME="glaceon"
```

#1-14.デフォルトシェルの設定(SHELL命令)
シェル形式でコマンド実行する際のデフォルトのシェル設定を行う。

```docker:SHELL
SHELL ["<PATH OF SHELL>", "<PARAMETER>"]
#記述例
SHELL ["/bin/bash", "-c"]
```

#1-15.ファイル/ディレクトリの追加(ADD命令)
イメージにホスト上のファイルやディレクトリを追加する。

```docker:ADD
ADD <HOST_FILE_PATH> <DOCKER_IMAGE_FILE_PATH>
ADD ["<HOST_FILE_PATH>", "<DOCKER_IAMGE_FILE_PATH>"]
#記述例
ADD host.html /docker_dir/
ADD ["host.html", "/docker_dir/"]
```

#1-16.ファイルのコピー(COPY命令)
イメージにホスト上のファイルやディレクトリをコピーする。

```docker:COPY
COPY <HOST_FILE_PATH> <DOCKER_IMAGE_FILE_PATH>
COPY ["<HOST_FILE_PATH>", "<DOCKER_IAMGE_FILE_PATH>"]
#記述例
COPY host.html /docker_dir/
COPY ["host.html", "/docker_dir/"]
```

※ADD命令はリモートファイルのダウンロードやアーカイブの解凍などの機能を持つが、
COPY命令はホスト上のファイルをイメージ内に「コピーする」処理だけを行う。

#1-17.ボリュームのマウント(VOLUME命令)
イメージにボリューム(※)を割り当てる。

```docker:VOLUME
VOLUME ["<MOUNT_POINT>"]
#記述例
VOLUME ["/var/log/"]
```
※補足：「**ボリューム**」とは、コンテナの外部にある永続化させたいデータを保存する場所である。
具体的には、ホストのディレクトリ、Dockerのリソースとしてのvolumeがそれに当たる。


#2.docker-compose.ymlの概要
Docker Composeは、複数のコンテナをまとめて管理するためのツールであり、
「docker-compose.yml」というファイルにコンテナの構成情報を定義することで、
同一ホスト上の複数のコンテナを一括管理できる。
また、このCompose定義ファイルは、大きく分けて以下の三つを定義する

```yml:docker-compose
#コンテナのサービス
services:
#ネットワーク
networks:
#ボリューム
volumes:
```

##2-1.バージョンの指定(version)
docker-compose.ymlファイルは、バージョンによって記述できる項目が異なる。
明示的なバージョンの指定がないときは「1.0」として動作する。
※2020/12/18現在、最新ver.は「3.3」

```yml:version
version: "<VERSION_NUMBER>"
#記述例
version: "3.3"
```

##2-2.イメージの指定(image)
Dockerコンテナのもとになる、ベースイメージを指定する。
ベースイメージは、ローカル環境にあればそれを使い、なければDocker Hubから自動的に
ダウンロードされる。
イメージの指定がないときは、最新バージョン「latest」がダウンロードされる。

```yml:image
image: <IMAGE_NAME>
#記述例
image: ubuntu
image: dockersample:1.0
```

##2-3.イメージのビルド(build)
イメージの構成をDockerfileに記述して、自動でビルドしてベースイメージに指定する。
buildには、Dockerfileのファイルパスを指定する。

```yml:build
build: <FILE_PATH_WHERE_THE_DOCKERFILE_IS>
#記述例
build: .
```

※複数のDockerfileを使用して開発するときは、以下のように「context」と「dockerfile」で
docker-compose.ymlが格納されているディレクトリをカレントとして次のように記述する。

```yml:context/dockerfile
services:
  docker-anaconda:
    build:  
      context: .
      dockerfile: ./working-directory/Dockerfile
```

##2-4.コンテナ内で動かすコマンドの指定(command/entrypoint)
コンテナで動かすコマンドは、commandで指定する。
また、entrypointの上書きも可能。

```yml:command/entrypoint
command: <COMMAND_EXECUTED_AFTER_IMAGE_CREATION>
entrypoint: <COMMAND_EXECUTED_WHEN_THE_CONTAINER_RUNS>
#記述例
command: /bin/bash
entrypoint:
    - php
    - -d
    - memory_limit=-1
```

##2-5.コンテナ間の連携(links)
別のコンテナへリンク機能を使って連携したいときに、連携先のコンテナ名を設定する。
また、コンテナ名とは別にエイリアス名を付けたい場合は「**サービス名：エイリアス名**」を設定する。

```yml:links
links: <SERVICE_NAME>
links: <SERVICE_NAME>:<ALIAS_NAME>
#記述例
links:
  - docker-anaconda
  - docker-anaconda:py01
```

##2-6.コンテナ間の通信(ports/expose)
コンテナが公開するポートは、portsで指定する。
「**ホストマシンのポート番号:コンテナのポート番号**」かもしくは
「**コンテナのポート番号のみ**」を指定する
※コンテナのポート番号のみ指定したときは、ホストマシンのポートは
ランダムな値が設定される。
ホストマシンへポートを公開せず、リンク機能を使って連携するコンテナにのみ
ポートを公開するときは、exposeを指定する。

```yml:ports/expose
ports: "<HOST_MACHINE_PORT_NUMBER>:<CONTAINER_PORT_NUMBER>"
ports: "<CONTAINER_PORT_NUMBER>"
expose: "<CONTAINER_PORT_NUMBER>"
#記述例
ports:
  -  "3000"
  -  "8000:8000"
  -  "49100:22"
  -  "127.0.0.1:8001:8001"
expose:
  - "3000"
  - "8000"
```

##2-7.サービスの依存関係の定義(depends_on)
複数のコンテナの依存関係を定義するとき、depends_onを指定する。
以下の記述例は、docker-anacondaを開始する際にpy01コンテナとpy02コンテナを
開始するようにするための記述である。

```yml:depends_on
depends_on: <CONTAINER_DEPENDED_ON>
#記述例
services:
  docker-anaconda:
    build: .
    depends_on:
      - py01
      - py02
  py01:
    image: py01
  py02:
    image: py02
```

##2-8.コンテナの環境変数の指定(environment/env_file)
コンテナ内の環境変数を指定するには、environmentを指定する。
YAML配列形式、もしくはハッシュ形式のどちらかで変数を指定する。
指定したい環境変数の数が多いときは、別ファイルで環境変数を定義して、
そのファイルをenv_fileで指定して読み込む。

```yml:environment
environment: 
  - <KEY1>=<VALUE1>
  - <KEY2>
environment:
  KEY1: VALUE2
  KEY
env_file: <ENVFILE>
#記述例
environment:
  - HOGE=fuga
  - FOO
environment:
  HOGE: fuga
  FOO
env_file:
  - ./envfile1
  - ./app/envfile2
  - /tmp/envfile3
```

##2-9.コンテナの情報設定(container_name/labels)
Docker Composeで生成されるコンテナには、container_nameで名前をつける。
コンテナにラベルをつける場合は、labelsを指定する。

```yml:container_name/labels
container_name: <CONTAINER_NAME>
labels: 
  - "<KEY>=<VALUE>"
labels:　
　<KEY>: "<VALUE>"
#記述例
container_name: docker-anaconda
labels:
  - "com.example.department=Finance"
labels:
  com.example.department: "Finance"
```

##2-10.コンテナのデータ管理(volumes/volumes_from)
コンテナにボリュームをマウントするときは「volumes」を指定する。
ホスト側でマウントするパスを指定するには、
「ホストのディレクトリパス：コンテナのディレクトリパス」
を指定する。
ボリュームの指定の後ろに「**ro:**」をつけることで、
ボリュームを読み取り専用としてマウントすることができる。
また、別のコンテナから全てのボリュームをマウントするときは、
volumes_fromにコンテナを指定する。

```yml:volumes/volumes_from
volumes: <MOUNT_POINT>
volumes: <HOST_DIRECTORY_PATH>:<CONTAINER_DIRECTORY_PATH>
volumes_from: <CONTAINER_NAME>
#記述例
volumes:
 - /var/lib/mysql
 - cache/:/tmp/cache
volumes:
 - ~/configs:/etc/configs/:ro
volumes_from:
 - docker_anaconda