いまさらだけどDockerに入門したので分かりやすくまとめてみた

# はじめに
今更ながらDockerに入門したのでまとめます。
全てのコマンドの細かいオプションとかまではやりません。
Dockerコマンド体系はv1.13以降の新系です。
ここではクラスタ管理(KubernetesやSwarm)については対象外です。別記事でそのうちまとめます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/f4b9f5f0-3ab8-56f2-839f-aa3861630397.png)

※本記事は投稿された2018年08月08日時点の情報が主になります。

# 勉強背景
[この記事](https://qiita.com/poly_soft/items/fb649573c19b7a5c0227#docker)から強い危機感を覚えました。
Dockerは世の中では当たり前の技術。せめて、少し触ってみて基本的な知識くらいは身につけなければ。。。。

# TL;DR(5行)
- Dockerは既存のLinuxカーネル機能から成り立っている
- イメージを共有していろんな人がいろんなところで簡単にイメージからコンテナを起動できる
- Dockerコマンドでコンテナを1つ1つ命令する
- Dockerコマンドめちゃ叩くのはだるいからDockerfileで楽しちゃおう
- 1つ1つコンテナを管理するのはだるいからdocker-composeで同一ホストOS上の複数コンテナをまとめて管理しちゃおう

# 仮想化概要
そもそもの仮想化から。

## ホスト型仮想化
ホストOS上で動作する仮想化ソフトウェアを利用してVMを管理する方式。
オーバーヘッドが大きい。
代表例はVirtualBox、VMWare Player。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/8e77ad87-b140-173d-554d-0db84161bda2.png)

## ハイパーバイザ型仮想化
ハードウェア上のハイパーバイザを利用してVMを管理する方式。
ホストOSなしでハードウェアを直接制御する。
オーバーヘッド大きい。
代表例はKVM、Heper-V、ESXi、Xen。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/f011b839-94bb-86aa-0309-3a2759a6749b.png)

## コンテナ型仮想化
ホストOS上でコンテナと呼ばれるVMと似たようなふるまいをする仮想的な区画を用意して管理する方式。
コンテナはホストOSのカーネルを利用する。
通常、1コンテナ1プロセスで使用するためWebサーバコンテナとかDBサーバコンテナとかログ管理コンテナとか複数のコンテナを立てる構成となる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/2b62e1e8-8e7b-7959-6b39-d91c37373cbc.png)


### 他の仮想化と比べたコンテナ型仮想化(Docker)のメリット
- 処理が速い
  - VM毎にCPUやメモリやストレージなどを割り当てるような処理が必要がなくオーバヘッドが少ないから
  - ゲストOSが無いため消費するリソースが少ないから
  - ゲストOSが無いためアプリケーションまでのパケット転送処理(コンテキストスイッチなど)が少ないから
- 起動が速い
  - ゲストOSを立ち上げるわけではないから
- 可搬性が高い
  - Dockerエンジンさえあれば基本どこでも動く。他の仮想化は足回りとかもうちょっと苦労する。
  - Dockerfileやdocker-compose.ymlによるインフラのコード化 
- イメージが軽い
  - Dockerイメージはレイヤで管理しているから
- Dockerイメージを簡単に共有できる仕組みが整っている
  - 特に、公式Dockerイメージが用意されている場合(JenkinsやWordPressなど)はデプロイがめちゃ楽
  - ECRなどプロジェクトに閉じているかつフルマネージドな環境が整っている

### コンテナ型仮想化(Docker)のデメリット
- ホストOSのカーネルと異なるOSは動かせない
- 学習コスト(この記事で解決しよう!!!)

# Docker概要
## Dockerとは
Dockerはオープンソースのコンテナ管理ソフトウェアである。

## コンポーネント
DockerではDocker Engineを中心に複数のコンポーネント単位で機能が開発されている。
必要に応じて複数のコンポーネントを組み合わせて使用する。

### Docker Engine
Dockerイメージ作成やコンテナ起動などを行うDockerのコアコンポーネント。
Linuxカーネルの機能を使ってメインの処理を行い、Dockerデーモンとして動作する。

### Docker Compose
複数コンテナを一元管理するコンポーネント。

### Docker Registry
Dockerイメージを公開・共有するコンポーネント。

### Docker Machine
非Linux環境用にDockerの実行環境をコマンドで自動生成するコンポーネント。
本記事では触れません。

### Docker Swarm
コンテナをクラスタ化して管理するコンポーネント。
正直なところ、Kubernetesの台頭により存在感を失いつつある。
本記事では触れません。

### Docker Kitematic
DockerのGUIツールコンポーネント。
まぁ、私含め皆さんはCUI叩ければいいでしょ。
本記事では触れません。

## Docker内部の仕組み
### namespace
DockerはLinuxカーネルのnamespaceの機能を使ってコンテナ毎の区画化を実現している。
namespace毎に下記を管理している。

- PID：プロセスに関して
- Network：IPアドレス、ポート番号、ルーティング、フィルタリングなどのネットワークに関して
- UID/GID：ユーザIDとグループIDに関して
- MOUNT：マウントに関して
- UTS：ホスト名やドメイン名に関して
- IPC：メッセージキューなどのプロセス間通信に関して

### cgroup(control group)
DockerはLinuxカーネルのcgroupの機能を使ってコンテナが利用する物理マシンリソース(CPUやメモリなど)の割り当ての管理を実現している。
プロセスをグループ化して、グループごとにリソース使用量制限をかけている。

### ネットワーク
#### リンク機能
コンテナにはそれぞれ仮想NIC(eth0)が割り当てられ、172.17.0.0/16のセグメントのIPがDHCPで割り当てられる。
コンテナの仮想NICはホストOS上の1つのブリッジ(docker0)に接続されているためコンテナ同士で通信することが可能。（リンク機能）
ただし、複数物理サーバが存在するマルチホスト環境において、異なる物理サーバへのリンク機能を使った通信は不可。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/9d4604b1-2d84-89ad-9dae-33cc2816e8fe.png)

#### インターフェース
コンテナ内で確認したインターフェース情報は以下。
コンテナ側から見るとまるで物理NIC(eth0)のように見える。

```console
# ip a
(省略)
34: eth0@if35: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
```

しかし、ホストOS側から見ると実体はvethであることが以下から分かる。
vethは、L2の仮想NICであり、コンテナのNIC(eth0)とホストOSのブリッジ(docker0)間でトンネリングをしている。

```console
# ip a
(省略)
35: vethd48920c@if34: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether 9e:bd:4d:63:ed:38 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::9cbd:4dff:fe63:ed38/64 scope link
       valid_lft forever preferred_lft forever
```

また、ホストOS上で以下の通り、docker0ブリッジを確認できる。

```console
# ip a
(省略)
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:bd:f7:d8:19 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
```


#### 外部通信
DockerはLinuxカーネルのiptables機能を利用して、ホストOSの外部通信を行う。
docker0とホストOSの物理NIC間でNAPTが行われている。

## Docker Hub
[Docker Hub](https://hub.docker.com/)は公式レジストリサーバです。
公式のDockerイメージ(officialと記載されているもの)の他に一般のユーザの独自イメージも公開されている。
デフォルトではpullやpushはこのリポジトリに対して実行される。
プライベートレジストリを構築してそれを利用することも可能。
GitHub連携やパブリッククラウド連携機能が用意されている。
同一イメージがpushされた場合はDocker Hub内では1つしか管理しない。(全て個別に管理していたらDocker Hubの容量がとんでもないことになる)

# Docker環境構築
## 今回の前提
- Ubuntu16.04
- インターネット通信可能

## Dockerインストール
最新版のDocker(Community Edition)をインストールする例。

```console
$ sudo apt-get remove docker docker-engine
$ sudo apt install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get install docker-ce
$ sudo docker -v
Docker version 18.06.0-ce, build 0ffa825
```

## （必要あれば）プロキシ設定
```console
$ sudo mkdir -p /etc/systemd/system/docker.service.d
$ sudo vi /etc/systemd/system/docker.service.d/http_proxy.conf
[Service]
Environment="HTTP_PROXY=http://<your_proxy_ip>:<your_proxy_port>/"
$ sudo vi /etc/systemd/system/docker.service.d/https_proxy.conf
[Service]
Environment="HTTPS_PROXY=http://<your_proxy_ip>:<your_proxy_port>/"
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
```

ちなみに↑のプロキシ設定は[stackoverflow](https://stackoverflow.com/questions/41262622/error-connecting-to-docker-hub/48201476#48201476)で私が貢献しました。（どうでもいい）


# Docker主要コマンド
新旧コマンド対応表やDockerコマンドの全体間をつかむには[こちらの記事](https://qiita.com/zembutsu/items/6e1ad18f0d548ce6c266)が分かりやすかったです。

## コマンド一覧
### イメージ管理用(image)
- pull：Dockerイメージをレジストリから取得
- ls：Dockerイメージの一覧を表示
- inspect：Dockerイメージの詳細を表示
- tag：Dockerイメージにタグをつける
- push：Dockerイメージをレジストリへアップロード
- rm：Dockerイメージの削除
- save：Dockerイメージをtarファイルに保存
- load：saveで固めたtarからDockerイメージを作成
- import：exportで固めたtarファイルからDockerイメージを作成

### コンテナ管理用(container)
- ls：コンテナの一覧を表示
- run：Dockerイメージからコンテナを生成
- stats：コンテナのリソース使用状況を表示
- logs：コンテナ内の実行ログ確認
- create：Dockerイメージからコンテナの生成
- start：コンテナの起動
- stop：コンテナの停止
- restart：コンテナの再起動
- pause：コンテナの一時停止
- unpause：一時停止中コンテナの起動
- rm：停止中コンテナの削除
- attach：稼働中コンテナに接続
- exec：稼働中コンテナに接続
- top：稼働中コンテナ内のプロセス一覧表示
- port：コンテナの公開ポート番号表示
- rename：コンテナの名前変更
- cp：コンテナとホストOS間でファイルとディレクトリのコピー
- diff：Dockerイメージが生成されてからの変更情報を表示
- commit：変更があったコンテナからイメージを作成
- export：コンテナをtarファイルに保存

### その他
- version：Dockerのバージョンを表示
- info：Dockerの実行環境情報を表示
- search：Docekrイメージの検索
- login：Docker Hubへログイン
- logout：Docker Hubからログアウト

## コマンド実行例
### イメージ管理用(image)
#### pull
Dockerイメージのダウンロードをする。
タグ(:以降)を省略すると最新版を取得する。
下記はcentosのイメージでタグが7のものをダウンロードする例。

```console
# docker image pull centos:7
7: Pulling from library/centos
7dc0dca2b151: Pull complete
Digest: sha256:b67d21dfe609ddacf404589e04631d90a342921e81c40aeaf3391f6717fa5322
Status: Downloaded newer image for centos:7
```

#### ls
Dockerイメージの一覧表示をする。

```console
# docker image ls
centos                7                   49f7960eb7e4        7 weeks ago         200MB
```

#### inspect
Dockerイメージの詳細確認をする。
イメージID、作成日、バージョン、作成者などの情報がJSON形式で取得可。

```console
# docker image inspect 49f7960eb7e4
[
    {
        "Id": "sha256:49f7960eb7e4cb46f1a02c1f8174c6fac07ebf1eb6d8deffbcb5c695f1c9edd5",
        "RepoTags": [
            "centos:7"
        ],
        "RepoDigests": [
            "centos@sha256:b67d21dfe609ddacf404589e04631d90a342921e81c40aeaf3391f6717fa5322"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2018-06-04T22:19:34.475342266Z",
        "Container": "ef04c6fb40e53318c38014531a0bb5647e2d659dbe8a5e375374d4bbac57a02d",
        "ContainerConfig": {
            "Hostname": "ef04c6fb40e5",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"/bin/bash\"]"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:40ef8420eda09fa48ca36df234cb2b68387b5e13abb352e6390da642afe0351d",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.schema-version": "= 1.0     org.label-schema.name=CentOS Base Image     org.label-schema.vendor=CentOS     org.label-schema.license=GPLv2     org.label-schema.build-date=20180531"
            }
        },
        "DockerVersion": "17.06.2-ce",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:40ef8420eda09fa48ca36df234cb2b68387b5e13abb352e6390da642afe0351d",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.schema-version": "= 1.0     org.label-schema.name=CentOS Base Image     org.label-schema.vendor=CentOS     org.label-schema.license=GPLv2     org.label-schema.build-date=20180531"
            }
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 199678471,
        "VirtualSize": 199678471,
        "GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/10b389d643af1b23fb8cb748dd6d730dd9721e6cd7365f453dca69915881378e/merged",
                "UpperDir": "/var/lib/docker/overlay2/10b389d643af1b23fb8cb748dd6d730dd9721e6cd7365f453dca69915881378e/diff",
                "WorkDir": "/var/lib/docker/overlay2/10b389d643af1b23fb8cb748dd6d730dd9721e6cd7365f453dca69915881378e/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:bcc97fbfc9e1a709f0eb78c1da59caeb65f43dc32cd5deeb12b8c1784e5b8237"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]
```

#### tag
Dockerイメージにタグをつけて別名保存する。
下記はcentosのイメージに1.0というタグを付ける例です。ついでにイメージ名をcentos_hogeに変えています。IMAGE IDは変わりません。

```console
# docker image tag 49f7960eb7e4 goldkou/centos_hoge:1.0

# docker image ls
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
goldkou/centos_hoge   1.0                 49f7960eb7e4        7 weeks ago         200MB　★
centos                7                   49f7960eb7e4        7 weeks ago         200MB
```

#### push
レジストリ(デフォルトではDocker Hub)へDockerイメージをアップロードする。
Docker Hubへpushするにはloginが必要。

```console
# docker image ls
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
goldkou/centos_hoge   1.0                 49f7960eb7e4        7 weeks ago         200MB
centos                7                   49f7960eb7e4        7 weeks ago         200MB

# docker image push goldkou/centos_hoge:1.0
The push refers to repository [docker.io/goldkou/centos_hoge]
bcc97fbfc9e1: Mounted from library/centos
1.0: digest: sha256:eed5b251b615d1e70b10bcec578d64e8aa839d2785c2ffd5424e472818c42755 size: 529
```

#### rm
ローカルのDockerイメージ削除をする。

```console
# docker image ls
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
goldkou/centos_hoge   1.0                 49f7960eb7e4        7 weeks ago         200MB
centos                7                   49f7960eb7e4        7 weeks ago         200MB

# docker image rm goldkou/centos_hoge:1.0
Untagged: goldkou/centos_hoge:1.0

# docker image ls
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
centos              7                   49f7960eb7e4        7 weeks ago         200MB
```

### save
Dockerイメージをtarファイルに保存する。

```console
# docker image ls
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
node                  latest              52fe93b8eea7        3 days ago          674MB

# docker image save -o node.tar 52fe93b8eea7

# ls |grep node.tar
node.tar
```

### load
saveで固めたtarからDockerイメージを作成する。

```console
# docker image load -i node.tar
Loaded image ID: sha256:52fe93b8eea726594f3b8efefedc2e3a1db02828ab57632b217b953f00192950
```

#### import
exportで固めたtarファイルからDockerイメージを作成する。

```console
# docker image import tmp.tar
sha256:39243504993c62780816c916461a4383e8751b8f90367888b6c8d4ce51727f15

# docker image ls
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
<none>                <none>              39243504993c        3 seconds ago       668MB
```

### コンテナ管理用(container)
#### ls
コンテナの一覧表示をする。
-aオプションで起動中と停止中も含めて全て表示する。
STATUSはUP/Up(Paused)/Exitedのいずれか。

```console
# docker container ls -a
CONTAINER ID        IMAGE               COMMAND                 CREATED             STATUS                           PORTS                  NAMES
```

#### run
Dockerイメージからコンテナの生成と起動を行う。

##### 通常起動（オプションなし）
以下はcentosのイメージからコンテナの生成と起動をする例。例にはないが、コンテナ名を指定したい場合は--nameオプションを利用する。

```console
# docker container run centos
# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS                NAMES
5586349638c8        centos              "/bin/bash"         6 seconds ago       Exited (0) 5 seconds ago                         tender_panini
```

##### 起動して擬似的なSSHをする
以下はcentosのイメージからコンテナの生成と起動をして、そのままコンテナにSSHする（厳密にはSSHではないですが）例。
/bin/bashでコンテナ内でbash起動する。
-itオプションでコンソールに結果を出力する。
--nameオプションで任意のコンテナ名を指定する。
Ctrl+C(あるいはexitコマンド)で抜けるとコンテナが停止してしまう(STATUSがExitedになる)ため、Exitedにしたくない場合は、Ctrl+Q+Pでプロセスだけ停止して抜ける。

```console
# docker container run -it --name "test1" centos /bin/bash
[root@1b758d38b739 /]# (Ctrl+Q+Pで抜ける)
# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS                NAMES
1b758d38b739        centos              "/bin/bash"         14 seconds ago      Up 22 seconds                        test1
```

##### バックグラウンド実行
以下はcentosのイメージからバックグラウンドでコンテナの生成と起動をして、自分自身にpingを実行し続ける例。
-dオプションでバックグラウンドで実行する。
-itオプションを有効にしていないためコンソールでは出力結果を確認できない。

```console
# docker container run -d centos /bin/ping localhost
5c617037cee01f183b0a67489334cacb90fd1015be2352119980810c81944fc4
```

##### ネットワーク設定
以下はホストOSの8080番にアクセスするとコンテナの80番で動いているhttpサービスにアクセスするポート転送とAA:AA:AA:AA:AA:AAというMACアドレスを指定してコンテナを生成して実行する例。
-pオプションでポート転送設定する。
--mac-addressでMACアドレス指定する。
他にもDNSサーバIPアドレス、ホスト名、IPアドレスなどの指定が可能。

```console
# docker container run -it -p 8080:80 --mac-address="AA:AA:AA:AA:AA:AA" httpd /bin/bash
root@d983b5e75160:/usr/local/apache2# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
54: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff　★MACアドレスが指定したものになっているｓ
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
```

##### 環境変数の設定
-eオプションで環境変数を設定する。

```console
# docker container run -it -e hoge=hoge centos /bin/bash
[root@897dd18ebe7e /]# set |grep hoge
hoge=hogehoge
```

また、環境変数ファイルを別途用意してそれを読み込むことも可能。
--env-fileオプションでファイル指定する。

```console
# cat env_list
hoge=hogehoge
fuga=fugafuga

# docker container run -it --env-file=env_list centos /bin/bash
[root@97c69057c511 /]# set
hoge=hogehoge
fuga=fugafuga
```

##### ボリューム割り当て
-vオプションで<ホストOSディレクトリ>:<コンテナ側ディレクトリ>形式でコンテナにボリュームを割り当てる。

```console
#ホストOSのマウント元情報確認
# pwd
/root/sample
# ls
sample.txt

#マウントポイント指定してコンテナ起動
# docker container run -it -v /root/sample/:/opt ubuntu
root@77851efa9a86:/# cd /opt/
root@77851efa9a86:/opt# ls
sample.txt　★マウントによりホストOS上のsample.txtが見えていることを確認
```

#### stats
稼働中コンテナの状態を確認する。
topコマンドのようにCPU使用率やメモリ使用率などを確認ができる。

```console
# docker container stats test1
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT   MEM %               NET I/O             BLOCK I/O           PIDS
5734bad7afbb        test1               0.00%               380KiB / 15.55GiB   0.00%               2.11kB / 0B         0B / 0B             1
```

#### logs
作成済みコンテナ内での実行ログを確認する。

```console
# docker container logs -t 5c617037cee0
2018-07-23T08:32:58.463727463Z PING localhost (127.0.0.1) 56(84) bytes of data.
2018-07-23T08:32:58.463781213Z 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.048 ms
2018-07-23T08:32:59.462708207Z 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.034 ms
2018-07-23T08:33:00.461835156Z 64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.044 ms
(省略)
```

#### create
Dockerイメージからコンテナの作成をする。
createだけではSTATUSはCreatedのままで起動(UP)はしない。
--nameオプションでnameを指定しない場合は適当な名前が振られる。

```console
# docker image ls
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
centos              latest              49f7960eb7e4        7 weeks ago         200MB

# docker container create centos
e86597be9bbf20e5c5345a103cb1e6302f8a034d803b9cd2d92a27e6a65a259f

# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                NAMES
e86597be9bbf        centos              "/bin/bash"         11 seconds ago      Created                                  stoic_noyce
```

#### start
コンテナの起動をする。
STATUSがUPになる。

```console
# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS                NAMES
af3e7da4f96a        ubuntu              "/bin/bash"         15 minutes ago      Exited (0) 1 second ago                          angry_tereshkova

# docker container start af3e7da4f96a
af3e7da4f96a

# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS                NAMES
af3e7da4f96a        ubuntu              "/bin/bash"         15 minutes ago      Up 1 second                                      angry_tereshkova
```

#### stop
コンテナの停止をする。
STATUSがExitedになる。

```console
# docker container stop af3e7da4f96a
af3e7da4f96a

# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS                NAMES
af3e7da4f96a        ubuntu              "/bin/bash"         20 minutes ago      Exited (0) 1 second ago                          angry_tereshkova
```

#### restart
コンテナの再起動をする。
STATUSがUPになる。

```console
# docker container restart af3e7da4f96a
af3e7da4f96a

# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS                NAMES
af3e7da4f96a        ubuntu              "/bin/bash"         20 minutes ago      Up 2 seconds                                     angry_tereshkova
```

#### pause
コンテナの一時停止をする。
STATUSがUp(Paused)になる。

```console
# docker container pause af3e7da4f96a
af3e7da4f96a

# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS                NAMES
af3e7da4f96a        ubuntu              "/bin/bash"         23 minutes ago      Up 14 seconds (Paused)                           angry_tereshkova
```

#### unpause
STATUSがPausedになっているものを再開する。
STATUSがUPになる。

```console
# docker container unpause af3e7da4f96a
af3e7da4f96a

# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS                NAMES
af3e7da4f96a        ubuntu              "/bin/bash"         37 minutes ago      Up 13 minutes                                    angry_tereshkova
```

#### rm
停止中コンテナの削除をする。

```console
# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                   PORTS                NAMES
af3e7da4f96a        ubuntu              "/bin/bash"         40 minutes ago      Up 17 minutes                                 angry_tereshkova

# docker container stop af3e7da4f96a
af3e7da4f96a

# docker container rm af3e7da4f96a
af3e7da4f96a

# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                   PORTS                NAMES
```

#### attach
稼働中コンテナへ接続する。
attachの場合はコンテナ内でシェルが動作していなければ接続することができない。
Ctrl+C(あるいはexitコマンド)で抜けるとコンテナが停止してしまう(STATUSがExitedになる)ため、Exitedにしたくない場合は、Ctrl+Q+Pで抜ける。

```console
#接続
# docker container attach 34da816d9447

#コンテナ内でプロセス一覧確認。/bin/bashプロセスはもともと動いていた1つだけ。
[root@34da816d9447 /]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 05:32 pts/0    00:00:00 /bin/bash
root        16     1  0 05:37 pts/0    00:00:00 ps -ef

#exitで抜ける
[root@34da816d9447 /# exit
exit

#STATUSがExitedになった
# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS                NAMES
34da816d9447        49f7960eb7e4        "/bin/bash"         5 minutes ago       Exited (0) 5 seconds ago                        test1
```

#### exec
稼働中コンテナへ接続する。
接続する際に稼働コンテナでPID=1のプロセスを実行するため、コンテナ内でシェルが動作している必要がない。
Ctrl+C(あるいはexitコマンド)で抜けた後もSTATUSはUpのままで、接続時に起動したプロセスが停止するだけ。
-itオプションはコンソール出力のお決まりのオプション。

```console
#コンテナ接続
# docker container exec -it 34da816d9447 /bin/bash

#コンテナ内でプロセス一覧確認。今回はもともとあがっていた/bin/bashプロセス(PID=16)と接続する際に起動した/bin/bashプロセス(PID=1)の2つ。
[root@34da816d9447 /]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 06:02 pts/0    00:00:00 /bin/bash　★接続時に起動したプロセス
root        16     0  0 06:02 pts/1    00:00:00 /bin/bash
root        31    16  0 06:02 pts/1    00:00:00 ps -ef

#exitで抜ける
[root@34da816d9447 /]# exit
exit

#STATUSがUpのままであることを確認。
# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                   PORTS                NAMES
34da816d9447        49f7960eb7e4        "/bin/bash"         30 minutes ago      Up 20 seconds                                 test1
```

ちなみに、alpine(軽量イメージ)を使っている場合は `/bin/bash` は入っていないので、 `/bin/ash` とするとのこと。
少しハマりました。

#### top
稼働コンテナ内のプロセス一覧を表示する。

```console
# docker container top 34da816d9447
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                20384               20365               0                   15:02               pts/0               00:00:00            /bin/bash
```

#### port
コンテナの公開ポート番号表示をする。

```console
# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                NAMES
46574bb37e1e        node                "/bin/bash"         27 minutes ago      Up 13 minutes       0.0.0.0:80->80/tcp   nodejs001

# docker container port nodejs001
80/tcp -> 0.0.0.0:80
```

#### rename
コンテナの名前変更を行う。

```console
# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                NAMES
46574bb37e1e        node                "/bin/bash"         30 minutes ago      Up 15 minutes       0.0.0.0:80->80/tcp   nodejs001

# docker container rename nodejs001 nodejs001_hoge

# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                NAMES
46574bb37e1e        node                "/bin/bash"         30 minutes ago      Up 16 minutes       0.0.0.0:80->80/tcp   nodejs001_hoge　★名前が変更されている
```

#### cp
コンテナとホストOS間でファイルとディレクトリのコピーをする。

```console
#コンテナ46574bb37e1e上の/etc/passwdファイルをホストの/tmpディレクトリに移動
# docker container cp 46574bb37e1e:/etc/passwd /tmp

#ファイルの確認
# ll /tmp |grep passwd
-rw-r--r--  1 root root  1236  7月 17 14:35 passwd
```

#### diff
Dockerイメージが生成されてからの差分を表示する。

- A：ファイル追加(ADD)
- C：ファイル更新(CHANGE)
- D：ファイル削除(DELETE)

```console
# docker container diff 46574bb37e1e
C /etc
C /etc/subgid
C /etc/subuid-
C /etc/passwd-
C /etc/shadow
C /etc/shadow-
C /etc/group
C /etc/passwd
C /etc/gshadow
C /etc/gshadow-
C /etc/group-
C /etc/subuid
C /etc/subgid-
C /root
A /root/.bash_history
C /var
C /var/log
C /var/log/faillog
C /var/log/lastlog
```

#### commit
コンテナからイメージを作成する。

```console
# docker container commit 28bd5bc4292e ubuntu_img
sha256:ab6ea87d1613643bf1be1c7826e6a8aa0712675c232ea294d2b5bb48f54739b1

# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu_img          latest              ab6ea87d1613        7 seconds ago       82.4MB
```

#### export
コンテナからtarファイルを作成する。

```console
# docker container export 46574bb37e1e > tmp.tar
```

### その他
#### version
Dockerのバージョンを表示する。

```console
# docker version
Client:
 Version:           18.06.0-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        0ffa825
 Built:             Wed Jul 18 19:11:02 2018
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.0-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       0ffa825
  Built:            Wed Jul 18 19:09:05 2018
  OS/Arch:          linux/amd64
  Experimental:     false
```

#### info
Dockerの実行環境情報を表示する。

```console
# docker info
Containers: 1
 Running: 1
 Paused: 0
 Stopped: 0
Images: 4
Server Version: 18.06.0-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: d64c661f1d51c48782c9cec8fda7604785f93587
runc version: 69663f0bd4b60df09991c08812a60108003fa340
init version: fec3683
Security Options:
 apparmor
 seccomp
  Profile: default
Kernel Version: 4.4.0-21-generic
Operating System: Ubuntu 16.04 LTS
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 15.55GiB
Name: XXXXX
ID: GTKQ:OBBP:FIX2:4VBK:HQJU:F2GF:IQOZ:5ICS:OFCT:KPI2:MN5R:R7RF
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
HTTP Proxy: http://XXXXX
HTTPS Proxy: http://XXXXX
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

WARNING: No swap limit support
```

#### search
Docker Hubに公開されているイメージの検索する。
WEB-UIで表示されるものとほぼ同じ情報を取得する。

```console
# docker search centos
NAME                               DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
centos                             The official build of CentOS.                   4419                [OK]
ansible/centos7-ansible            Ansible on Centos7                              114                                     [OK]
(省略)
```

#### login
Docker Hubへログイン。
Docker Hubへpushするためにはログインしておく必要がある。

```console
# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: goldkou
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
```

#### logout
Docker Hubからログアウト。

```console
# docker logout
Removing login credentials for https://index.docker.io/v1/
```

#### 便利ワンライナー
ホストOSからコンテナのIP確認

```console
# docker image inspect --format '{{ .NetworkSettings.IPAddress }}' <コンテナIDまたはコンテナ名>
```

# Dockerfile
## Dockerfile概要
Dockerfileはコンテナの構成情報を定義したファイルである。
Dockerfileを用意すれば何回もDockerコマンドを叩く必要なく、1コマンドでDockerイメージを生成できるため、構築の手間を省力化したりミスをなくしたりDockerfileそのものを手順書の一部として扱える。逆にDockerfileが無いとコンテナ操作に関する手順書やパラメータシートなどを別途管理する必要が出てきてしまう。
新イメージを作るのにベースイメージからいったんコンテナを起動して、命令実行している。

## build
### buildコマンド
buildコマンドでDockerfileからDockerイメージを作成する。
-tオプションで出来上がる任意のDockerイメージ名とタグ名を指定する。
-fオプションでDockerfileのパスを指定する。

```console
# docker image build -t <イメージ名:tag名> -f <Dockerfile>
```

### Automated Build
GitHubまたはBitbucketで公開されているDockerfileからDockerイメージをビルドしてDocker Hubに登録する機能。
GitHub(Bitbucket)のアカウントとDocker Hubのアカウント間の連携設定が必要。
ファイル名が"Dockerfile"である必要がある。
例えば、[こちらの記事](https://qiita.com/FoxBoxsnet/items/a31fc46681d9b67c8cc6)のようにWebhookを利用してGitHubでタグが付いたらその時点でBuildしてDocker Hubにイメージを登録しておくとかできる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/73aec3c9-79a2-ec60-1d6a-4f607517c06e.png)

### レイヤー
build実行時は内部では命令毎にイメージを作成する動きをしているが、実際には効率的にイメージを管理するためにそれぞれイメージの全体でなくイメージ間の差分(tar)であるレイヤーの積み重ねを管理している。
このレイヤー数にはストレージドライバ起因で上限があるため、できるだけ命令は以下のように1つにまとめた方がよい。

```bash:NG例
RUN yum -y install httpd
RUN yum -y install git
```
```bash:OK例
RUN yum -y install \
            httpd\
            git
```

## 命令
### 命令一覧
- FROM：ベースイメージの指定
- MAINTAINER：作成者情報を設定
- ENV：環境変数を設定
- WORKDIR：場所(ディレクトリ)を移動
- USER：ユーザ変更設定
- LABEL：メタ情報(バージョンやコメントなど)設定
- EXPOSE：公開ポート番号設定
- ADD：ファイルやディレクトリを取得（リモート可）
- COPY：ファイルやディレクトリを取得（ローカルのみ）
- VOLUME：ボリューム設定
- ONBUILD：次のbuild時に実行されるコマンドを設定
- RUN：ベースイメージから起動したコンテナ内で実行するコマンドを設定
- CMD：作成したイメージが起動されたら実行するコマンドを設定。ENTRYPOINT使用時はENTRYPOINTの引数として利用することも可能。
- ENTRYPOINT：作成したイメージが起動されたら実行するコマンドを設定

### 命令詳細
#### FROM
ベースイメージの指定をする命令。

```dockerfile
FROM centos
```

#### MAINTAINER
Dockerfileの作成者情報を設定する命令。
ただし、MAINTAINERは1.13から非推奨であり、代わりにLABEL命令を使います。

```dockerfile
MAINTAINER goldkou
```

#### ENV
コンテナ内の環境変数を設定する命令。
runコマンドのenvオプションと同様のことができるが、envオプションの内容が優先となる。

```dockerfile
ENV hoge=hogehoge\
    fuga=fugafuga
```

#### WORKDIR
場所(ディレクトリ)を移動する命令。
次以降の命令は移動した先の場所が起点となる。

```dockerfile
WORKDIR /tmp
RUN ["pwd"]
```

#### USER
ユーザ変更する命令。
次以降の命令者は変更した後のユーザになる。

```dockerfile
USER admin
RUN ["whoami"]
```

#### LABEL
イメージにメタ情報(バージョンやコメントなど)を設定する命令。
inspectコマンドで内容を確認できる。

```dockerfile
LABEL title="sampleImage"\
      version="1.0"\
      description="This is a sample."
```
```console
# docker image inspect 1a5099f89ade |grep title
                "title": "sampleImage",

# docker image inspect 1a5099f89ade |grep version
                "org.label-schema.schema-version": "= 1.0     org.label-schema.name=CentOS Base Image     org.label-schema.vendor=CentOS     org.label-schema.license=GPLv2     org.label-schema.build-date=20180531",
                "version": "1.0"

# docker image inspect 1a5099f89ade |grep description
                "description": "This is a sample.",
```

#### EXPOSE
コンテナの公開ポート番号を設定する命令。
外部からアクセスする場合にはrunコマンドの-pオプションによるポート転送が必要。

```dockerfile
EXPOSE 80
```

#### ADD
ファイルやディレクトリを取得する命令。
ホストOS上のローカルファイルでもリモートファイルでも可。
リモートファイルの場合はパーミッションが600になる点に注意。

```dockerfile
ADD https://github.com/docker/cli/blob/master/README.md /tmp
```

#### COPY
ファイルやディレクトリを取得する命令。
ホストOS上のローカルファイルのみ可。ローカルファイルのコピーを行う場合はCOPYを使うことが推奨されている。
下の例では、ローカルに存在するtmp.txtをコンテナ上の/tmpにコピーしている。

```dockerfile
COPY tmp.txt /tmp
```

#### VOLUME
ボリュームを割りあてる命令。
コンテナ内のマウントポイントを指定する。
ホストOSなどからボリュームがマウントされる。具体的にどこにマウントされるかなどの詳細は[こちらの記事](https://qiita.com/namutaka/items/f6a574f75f0997a1bb1d#dockerfile%E3%81%A7%E3%81%AEvolume%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89)が勉強になりました。
コンテナ内のファイルはコンテナを削除すると消えてしまうので、重要なデータはコンテナでなく外部ボリュームで管理すべし。

```dockerfile
VOLUME /myvol
```

#### ONBUILD
次のbuildで実行するコマンドをイメージに仕込む命令。
自身のDockerfileから生成したDockerイメージをベースイメージとして別のDockerfileでビルドされるときに実行されるコマンドを設定する。
（正直なところ、ONBUIDならではの効果的な使い道がまだ分からない。ADDやCMDとかでそれできるよねって感じ。ベースイメージを軽くできるとか？）
以下は、ADD命令を利用してホストOS上のtmp.tarファイルをコンテナの/var/www/html配下に格納する例。

```dockerfile
ONBUILD ADD tmp.tar /var/www/html/
```

#### RUN
Dockerイメージを作成する際にコンテナ内でコマンドを実行する命令。
実行形式はExec形式とShell形式の2種類がある。
Exec形式はシェルを介さずに実行する。公式的にはこちらが推奨とされている。
Shell形式は/bin/sh -cのシェルを介して実行する。

```bash:Exec形式例
RUN ["yum", "-y", "install", "httpd"]
```
```bash:Shell形式例
RUN yum -y install httpd
```

CMDやENTRYPOINTとの違いは、RUNは「Dockerイメージを作成するためのコマンド」を定義するのに対し、CMDやENTRYPOINTは「Dockerイメージが起動してから実行されるコマンド」を定義する点である。

#### CMDとENTRYPOINT
##### CMD
Dockerfileで作成したDockeイメージから稼働したコンテナ内で指定コマンドを実行する命令。
runコマンドの引数に指定したコマンドでCMDの内容をオーバーライドできる。
1つのDockerfileにCMDは1つのみ。
Exec形式はシェルを介さずに実行する。公式的にはこちらが推奨とされている。
Shell形式は/bin/shを介して実行する。

```dockerfile:Exec形式例
CMD ["ping","127.0.0.1","-c","5"]
```
```dockerfile:Shell形式例
CMD ping 127.0.0.1 -c 5
```

##### 複数のCMDを実行したい場合
複数CMD書いても最後の行のものしか有効になりません。
複数のコマンドを実行したい場合は、コマンド群をシュルスクリプトに定義し、CMDでそのシェルを実行するようにしましょう。

##### ENTRYPOINT
Dockerfileで作成したDockeイメージから稼働したコンテナ内で指定コマンドを実行する命令。
runコマンドの引数に指定したコマンドでCMDの内容をオーバーライドできるが、--entrypointオプションが必要。
1つのDockerfileにENTRYPOINTは1つのみ。
Exec形式はシェルを介さずに実行する。公式的にはこちらが推奨とされている。
Shell形式は/bin/shを介して実行する。

```dockerfile:Exec形式例
ENTRYPOINT ["ping","127.0.0.1","-c","5"]
```
```dockerfile:Shell形式例
ENTRYPOINT ping 127.0.0.1 -c 5
```

##### CMDとENTRYPOINTの併用
CMDとENTRYPOINTを1つのDockerfileに併用する場合は、CMDの値がENTRYPOINTの末尾に追加される。(CMDがENTRYPOINTのオプションとして扱われる)
以下は、localhostにpingする命令の例。

```dockerfile
ENTRYPOINT ["ping"]
CMD ["127.0.0.1", "-c", "50"]
```

##### CMDとENTRYPOINTの違い
CMDとENTRYPOINTの主な違いはrunコマンド実行時の上書きの仕方だけ。
詳細は[こちらの記事](https://qiita.com/hihihiroro/items/d7ceaadc9340a4dbeb8f)

## コメントアウト
Dockerfileは#でコメントアウトします。

```dockerfile
# This is a comment out of the dockerfile.
```

## Dockerfile動かしてみる
とりあえずそれぞれの意味はそんなに無いけど、いろいろな命令をDockerfileに書いてみる。

```dockerfile:Dockerfile
FROM centos

MAINTAINER goldkou

LABEL title="sampleImage"\
      version="1.0"\
      description="This is a sample."

RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol

ENV hoge=hogehoge

EXPOSE 80

WORKDIR /tmp
RUN ["pwd"]

ADD https://github.com/docker/cli/blob/master/README.md /tmp

COPY sample.txt /tmp
```

上記Dockerfileからビルド実行。

```console
# docker image build -f Dockerfile .
Sending build context to Docker daemon   2.56kB
Step 1/12 : FROM centos
 ---> 49f7960eb7e4
Step 2/12 : MAINTAINER goldkou
 ---> Running in b9faffa441a8
Removing intermediate container b9faffa441a8
 ---> b5697add76f7
Step 3/12 : LABEL title="sampleImage"      version="1.0"      description="This is a sample."
 ---> Running in e9fe12c0088a
Removing intermediate container e9fe12c0088a
 ---> b78833368ef8
Step 4/12 : RUN mkdir /myvol
 ---> Running in a6dbd3e448f0
Removing intermediate container a6dbd3e448f0
 ---> fe87721af021
Step 5/12 : RUN echo "hello world" > /myvol/greeting
 ---> Running in 2634122c6694
Removing intermediate container 2634122c6694
 ---> f973b12fa4a6
Step 6/12 : VOLUME /myvol
 ---> Running in ae03fe76efb3
Removing intermediate container ae03fe76efb3
 ---> 69cbebb5e50d
Step 7/12 : ENV hoge=hogehoge
 ---> Running in 25d01e7b2374
Removing intermediate container 25d01e7b2374
 ---> b490efb7db45
Step 8/12 : EXPOSE 80
 ---> Running in 224cfe63507f
Removing intermediate container 224cfe63507f
 ---> 9e34c56c1d60
Step 9/12 : WORKDIR /tmp
 ---> Running in 66ae8c28c3c0
Removing intermediate container 66ae8c28c3c0
 ---> 74d787ad9a85
Step 10/12 : RUN ["pwd"]
 ---> Running in 0e804a695f55
/tmp
Removing intermediate container 0e804a695f55
 ---> 409b71d637f0
Step 11/12 : ADD https://github.com/docker/cli/blob/master/README.md /tmp
Downloading  51.02kB
 ---> 5b6890980869
Step 12/12 : COPY sample.txt /tmp
 ---> b4dc0b57f8a8
Successfully built b4dc0b57f8a8
```

なんとなくできたぽいけど、上記のStepが本当にできたかをいくつか調べる。

```console
#イメージ一覧確認
# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              b4dc0b57f8a8        23 seconds ago      200MB

#コンテナ起動
# docker container run -it -p 8080:80 b4dc0b57f8a8

#/tmpに移動していることを確認(上記Step9)
[root@6ea955b74e97 tmp# pwd
/tmp

#OSがCentOS最新版であることを確認(上記Step1)
# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)

#マウントされていることを確認(上記Step4~6)
# cat /myvol/greeting
hello world

#環境変数確認(上記Step7)
[root@6ea955b74e97 tmp]# printenv |grep hoge
hoge=hogehoge

#/tmpにファイルが格納されていることを確認(上記Step11~12)
[root@6ea955b74e97 tmp]# ls /tmp
README.md  ks-script-3QMvMi  sample.txt  yum.log

#exitでコンテナを抜ける

#ポート番号確認(上記Step8)
# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                         PORTS                  NAMES
6ea955b74e97        b4dc0b57f8a8        "/bin/bash"         24 minutes ago      Up 24 minutes                  0.0.0.0:8080->80/tcp   dazzling_beaver

#メタ情報確認(上記Step3)
# docker image inspect 6ea955b74e97 |grep title
                "title": "sampleImage",
# docker image inspect 6ea955b74e97 |grep version
                "org.label-schema.schema-version": "= 1.0     org.label-schema.name=CentOS Base Image     org.label-schema.vendor=CentOS     org.label-schema.license=GPLv2     org.label-schema.build-date=20180531",
                "version": "1.0"
# docker image inspect 6ea955b74e97 |grep description
                "description": "This is a sample.",
```

# compose
同一ホストOS上の複数コンテナを一括管理するコンポーネント。
"docker-compose.yml"ファイルに複数コンテナの構成情報を定義し、docker-composeコマンドで起動や停止などの管理をする。
通常、複数のサーバ群(コンテナ群)で1つのサービスを構成するため、それらをまとめるcomposeの需要がある。

## docker-composeインストール
```console
#docker-composeインストール
# curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   617    0   617    0     0    427      0 --:--:--  0:00:01 --:--:--   427
100 11.2M  100 11.2M    0     0   562k      0  0:00:20  0:00:20 --:--:-- 1536k

#権限変更
# chmod +x /usr/local/bin/docker-compose

#インストール確認(バージョン確認)
# docker-compose --version
docker-compose version 1.22.0, build f46880fe
```

## docker-compose.yml
### サービス一覧
- image：ベースイメージの指定
- build：Dockerfileの指定
- command：コンテナ内で実行するコマンドの設定
- links：コンテナ間リンク設定
- ports：ホストOS外部への公開ポート設定
- expose：コンテナ間のみでの公開ポート設定
- volumes：ボリュームマウントの設定
- volumes_from：別コンテナをボリュームとしてマウントするための設定
- environment：環境変数設定
- env_file：環境変数をファイル読み込みで設定
- container_name：コンテナの名前設定

### サービス詳細
#### image
ベースイメージの指定をする。
Dockerイメージを直接指定する方法。
docker-compose.ymlにはimageかbuildのどちらかの記載が必須。(当たり前な話だけどコンテナ起動にはイメージ必須だから)

```YAML:docker-compose.yml
sampleserver:
  image: ubuntu
```

#### build
Dockerfileの指定をする。
Dockerfile内のFROM命令でイメージ指定できるため、間接的にイメージを指定できる。
docker-compose.ymlにはimageかbuildのどちらかの記載が必須。(当たり前な話だけどコンテナ起動にはイメージ必須だから)

```console:ディレクトリ構成
# ls
Dockerfile  docker-compose.yml
```
```Dockerfile:Dockerfile
FROM ubuntu
```
```YAML:docker-compose.yml
sampleserver:
  build .
```

#### command
コンテナ内で実行するコマンドの指定をする。

```YAML
command: /bin/bash
```

#### links
コンテナ間のネットワーク設定をする。
linksで指定したコンテナへ、指定元コンテナから接続可能にする。
コンテナ内の/etc/hostsに名前設定がされる。

```YAML
links:
  - dbserver
```

#### ports
コンテナの外部への公開ポート設定をする。
以下はホストOSへの5000番ポートアクセスをコンテナの5000ポートに転送する設定例。

```YAML
ports:
  - "5000:5000"
```

#### expose
コンテナ間のみでの公開ポート設定をする。

```YAML
expose:
  - "5000"
```

#### volumes
コンテナにボリュームをマウントする。
<マウント元のパス>:<マウント先（コンテナ）のパス>の形式で指定する。(コンテナ側は省略可)

```YAML
volumes:
  - /tmp:/tmp
```

#### volumes_from
別のコンテナからボリュームをマウントする。
下はstorageという名前のコンテナからマウントする例。

```YAML
volumes_from:
 - storage
```

#### environment
コンテナ内の環境変数設定をする。

```YAML
environment:
  - hoge=hogehoge
```

#### env_file
コンテナ内の環境変数をファイル読み込みで設定する。

```ini:envfile
hoge=hogehoge
fuga=fugafuga
```
```YAML
env_file: envfile
```

#### container_name
コンテナの名前設定をする。

```YAML
container_name: sample-container1
```

## docker-composeコマンド
docker-compose.ymlファイルと同一ディレクトリでコマンド実行する必要がある。
あるいは、-fオプションでファイルパスを指定して実行することも可能。

### docker-composeコマンド一覧
- ps：コンテナの一覧表示
- up：コンテナの生成と起動
- scale：生成するコンテナ数の指定
- logs：コンテナログの確認
- run：コンテナの実行
- start：コンテナの起動
- stop：コンテナの停止
- restart：コンテナの再起動
- rm：コンテナの削除

### docker-composeコマンド詳細
#### ps
コンテナの一覧表示をする。

```console
# docker-compose ps
        Name             Command    State    Ports
--------------------------------------------------
```

#### up
docker-compose.ymlからコンテナの生成と起動を行う。

```console
# cat docker-compose.yml
ubuntuServer:
   image: ubuntu

centosServer:
   image: centos

# docker-compose up
Pulling ubuntuServer (ubuntu:)...
latest: Pulling from library/ubuntu
c64513b74145: Pull complete
01b8b12bad90: Pull complete
c5d85cf7a05f: Pull complete
b6b268720157: Pull complete
e12192999ff1: Pull complete
Digest: sha256:3f119dc0737f57f704ebecac8a6d8477b0f6ca1ca0332c7ee1395ed2c6a82be7
Status: Downloaded newer image for ubuntu:latest
Creating sample_ubuntuServer_1 ... done
Creating sample_centosServer_1 ... done
Attaching to sample_ubuntuServer_1, sample_centosServer_1
sample_ubuntuServer_1 exited with code 0
sample_centosServer_1 exited with code 0

# docker-compose ps
        Name             Command    State    Ports
--------------------------------------------------
sample_centosServer_1   /bin/bash   Exit 0
sample_ubuntuServer_1   /bin/bash   Exit 0
```

#### scale
docker-compose.ymlファイルから生成するコンテナの数を指定する。

```console
# cat docker-compose.yml
ubuntuServer:
   image: ubuntu

centosServer:
   image: centos

# docker-compose scale ubuntuServer=2 centosServer=3
WARNING: The scale command is deprecated. Use the up command with the --scale flag instead.
Creating sample_ubuntuServer_1 ... done
Creating sample_ubuntuServer_2 ... done
Creating sample_centosServer_1 ... done
Creating sample_centosServer_2 ... done
Creating sample_centosServer_3 ... done

# docker-compose ps
        Name             Command    State    Ports
--------------------------------------------------
sample_centosServer_1   /bin/bash   Exit 0
sample_centosServer_2   /bin/bash   Exit 0
sample_centosServer_3   /bin/bash   Exit 0
sample_ubuntuServer_1   /bin/bash   Exit 0
sample_ubuntuServer_2   /bin/bash   Exit 0
```

#### run
起動済みコンテナで新たにコマンドを実行する。
以下は/bin/bashを実行する例。

```console
# docker-compose run ubuntuServer /bin/bash
root@552410439d29:/#
```

#### start
複数コンテナの一括起動をする。
何も指定しなければ一括となる。

```console
# docker-compose start
Starting ubuntuServer ... done
Starting centosServer ... done
```

#### stop
複数コンテナの一括停止をする。
何も指定しなければ一括となる。

```console
# docker-compose stop
```

#### restart
複数コンテナの一括再起動をする。
何も指定しなければ一括となる。

```console
# docker-compose restart
Restarting sample_ubuntuServer_1 ... done
Restarting sample_centosServer_1 ... done
```

#### rm
複数コンテナの一括削除をする。
何も指定しなければ一括となる。

```console
# docker-compose rm
Going to remove sample_ubuntuServer_1, sample_centosServer_1
Are you sure? [yN] y
Removing sample_ubuntuServer_1 ... done
Removing sample_centosServer_1 ... done
```

## docker-composeを動かしてみる
公式Dockerイメージとして用意されているWordPressを使って、webコンテナとDBコンテナとstorageコンテナの3コンテナを構築してみる。

まずは、データ保存用コンテナstorageを作成するためのDockerfileを定義する。
busyboxとは標準的なLinuxコマンドを実行できるDocker Hub上に公開されているDockerイメージです。

```Dockerfile:Dockerfile
FROM busybox
MAINTAINER goldkou
VOLUME /var/lib/mysql
```

上記Dockerfileをもとにstorageという名前でbuild実行して、コンテナ起動します。

```console
# docker image build -t storage .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM busybox
latest: Pulling from library/busybox
8c5a7da1afbc: Pull complete
Digest: sha256:cb63aa0641a885f54de20f61d152187419e8f6b159ed11a251a09d115fdff9bd
Status: Downloaded newer image for busybox:latest
 ---> e1ddd7948a1c
Step 2/3 : MAINTAINER goldkou
 ---> Running in 440983f98554
Removing intermediate container 440983f98554
 ---> def7c880ba89
Step 3/3 : VOLUME /var/lib/mysql
 ---> Running in 27cf3184bbfb
Removing intermediate container 27cf3184bbfb
 ---> 45008d31fff7
Successfully built 45008d31fff7
Successfully tagged storage:latest

# docker container run -it --name storage storage
/ # (Ctrl+PとCtrl+Qで抜ける)
```

つづいて、WEBコンテナとDBコンテナの2コンテナを起動するdocker-compose.ymlを定義します。
DBコンテナはストレージとしてさきほど作成したstorageコンテナを使用します。

```YAML:docker-compose.yml
webserver:
  image: wordpress
  ports:
    - "80:80"
  links:
    - "dbserver:mysql"

dbserver:
  image: mysql
  depends_on:
    - webserver
  volumes_from:
    - storage
  environment:
    MYSQL_ROOT_PASSWORD: password
```

バックグラウンドでdocker-composeをupします。

```console
# docker-compose up -d
(省略)
Creating wordpress_dbserver_1 ... done
Creating wordpress_webserver_1 ... done
```

ホストOSの80番ポートにブラウザでアクセスしてWordPressの画面が表示されれば成功です。


(注意点)
~~docker-compose upで起動したwordpressのwebserverがSQLコネクションエラーでExitedになってしまいました。docker container restart webserverで復旧しました。多分、webserverができあがる前にdbserverがあがっちゃったとかそんなんだと思われます。きっと、順番付けとかがあるはず。~~ `depends_on`を使えば順番づけできます。 @yuma_h さんがありがとうございます。

最後に、お片付けします。

```console
# docker-compose stop
Stopping wordpress_webserver_1 ... done
Stopping wordpress_dbserver_1  ... done


# docker-compose rm
Going to remove wordpress_webserver_1, wordpress_dbserver_1
Are you sure? [yN] y
Removing wordpress_webserver_1 ... done
Removing wordpress_dbserver_1  ... done


# docker-compose ps
Name   Command   State   Ports
------------------------------

# docker stop storage
storage

# docker rm storage
storage

# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```

# プライベートレジストリ
リモートのDocker Hubでなく、プライベートレジストリ(ローカル)を自分で構築して利用することができる。
プライベートレジストリ用にDocker Hub上で"registry"という名前でDockerイメージが用意されている。
プライベートレジストリのバックエンドとして例えばAWSのS3などを使えば高信頼性のプライベートレジストリを簡単に作ることができる。
また、有料だがAWSやAzureでプライベートレジストリサービスの提供も行われている。

```console
#registryイメージ探索
# docker search registry
NAME                                    DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
registry                                The Docker Registry 2.0 implementation for s…   2093                [OK]
(省略)

#バージョン2のレジストリイメージ取得
# docker image pull registry:2.0
2.0: Pulling from library/registry
4d2e9ae40c41: Pull complete
a3ed95caeb02: Pull complete
7c8152785df5: Pull complete
8b04aafd7cd8: Pull complete
c97c75d2d42e: Pull complete
4b3ef98bba76: Pull complete
edee0288d356: Pull complete
ea2a9399d365: Pull complete
ddf532273b60: Pull complete
e9e91aa1843e: Pull complete
6144b0ffbb4c: Pull complete
Digest: sha256:3cac1869696e4ff3435bbc30391749ac373f7471736dbb48dfa9bfde08c4efd2
Status: Downloaded newer image for registry:2.0

#プライベートレジストリコンテナ起動
# docker container run -d -p 5000:5000 registry:2.0
9b89aef7d9abf796e59a65e8ba7ae42d4c66cfa90f876f1572ae9aea04a6c7e9

#push対象イメージにタグを付与
# docker image tag 49f7960eb7e4 localhost:5000/sample_centos

#イメージ一覧確認
# docker image ls
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
localhost:5000/sample_centos   latest              49f7960eb7e4        7 weeks ago         200MB
registry                       2.0                 3bccd459597f        3 years ago         549MB

#プライベートレジストリにイメージをアップロード
# docker image push localhost:5000/sample_centos
The push refers to repository [localhost:5000/sample_centos]
bcc97fbfc9e1: Pushed
latest: digest: sha256:a0ede55508fc10f4755360ef12ed66de9355a909028c70126acdf6ab787350d3 size: 3181

#ローカルのイメージ削除
# docker image rm 49f7960eb7e4
Untagged: centos:7
Untagged: centos@sha256:b67d21dfe609ddacf404589e04631d90a342921e81c40aeaf3391f6717fa5322
Deleted: sha256:49f7960eb7e4cb46f1a02c1f8174c6fac07ebf1eb6d8deffbcb5c695f1c9edd5
Deleted: sha256:bcc97fbfc9e1a709f0eb78c1da59caeb65f43dc32cd5deeb12b8c1784e5b8237
# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
registry            2.0                 3bccd459597f        3 years ago         549MB

#プライベートレジストリからイメージダウンロード
# docker image pull localhost:5000/sample_centos
Using default tag: latest
latest: Pulling from sample_centos
7dc0dca2b151: Pull complete
Digest: sha256:a0ede55508fc10f4755360ef12ed66de9355a909028c70126acdf6ab787350d3
Status: Downloaded newer image for localhost:5000/sample_centos:latest
# docker images
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
localhost:5000/sample_centos   latest              49f7960eb7e4        7 weeks ago         200MB　★増えている
registry                       2.0                 3bccd459597f        3 years ago         549MB
```