Docker ハンズオン - 基本コマンド編

# <i class="fa fa-cubes" style="font-size:1em;"></i> Docker ハンズオン - 基本コマンド編

Docker コマンドを実際に実行してもらうために作った資料になります。

## <i class="fa fa-cubes" style="font-size:1em;"></i> 目的
Docker? なにそれ美味しいの?
Docker? 便利そうだけどお高いんでしょ?
という方々にDocker のコマンドをひと通り実行してもらうための手順になります。

## <i class="fa fa-cubes" style="font-size:1em;"></i> 環境
|ソフトウェア|バージョン|
|:---|:---|
|OS|CentOS Linux release 7.1.1503 (Core)|
|Docker|1.8.1|

## <i class="fa fa-cubes" style="font-size:1em;"></i> ハンズオンの前にさらっとお勉強
### Docker とは？
Docker は、コンテナ技術を使い、アプリケーションの開発・実行をするためのプラットフォームです。
※くわしくは[What is Docker?](https://www.docker.com/whatisdocker) をお読みください。

* Docker プラットフォーム
 * [Docker Engine](https://www.docker.com/docker-engine)
 * [Docker Hub](https://hub.docker.com/)
 * [Docker Trusted Registry](https://www.docker.com/docker-trusted-registry)
 * [Docker Machine](https://docs.docker.com/machine/)
 * [Docker Swarm](https://docs.docker.com/swarm/)
 * [Docker Compose](https://docs.docker.com/compose/)
 * [Kinematic](https://kitematic.com/)

## <i class="fa fa-cubes" style="font-size:1em;"></i> コンテナとは？
コンテナ化とは、ホストOS 上のkernel を使い、複数のルート・ファイルシステムを実行することです。

* 各々のファイルシステムをコンテナと呼びます。
* 各々のコンテナは自身のリソースを持ちます。

※ <i class="fa fa-external-link-square" style="font-size:1em;"></i>[ココらへん](http://paiza.hatenablog.com/entry/2014/10/21/知らぬはエンジニアの恥%E3%80%82今さら聞けない【コン)を参考にしてあります。

ここで大事なのはホストOS 上のkernel を使用しているということです。つまりカーネルの違うOS でbuild されたコンテナは動かすことができません。
**Docker もまた然り**

## <i class="fa fa-files-o" style="font-size:1em;"></i> ハンズオン手順
* Docker のインストール
* Docker の起動
* イメージ取得・確認
* コンテナの起動・プロセスの確認・停止
* コンテナの詳細情報確認
* コンテナの削除
* イメージの変更・保存
* イメージの削除
* Dockerfile でコンテナ構築
* レポジトリへのイメージ登録

### <i class="fa fa-cube" style="font-size:1em;"></i> Docker のインストール
手順は<i class="fa fa-external-link-square" style="font-size:1em;"></i>[公式サイト](https://docs.docker.com/installation/)から。(Win, Mac その他のインストール手順も乗っています。)

```bash
$ wget -qO - https://get.docker.com/ | sh
$ curl -sSL https://get.docker.com/ | sh
```
上記どちらかのコマンドでシェルを実行するだけでDocker が実行できる環境が整います。

### <i class="fa fa-cube" style="font-size:1em;"></i> Docker の起動
```bash
$ systemctl start docker
```
 ※ centos7 での起動方法になります。他の環境の際には環境にあった起動をお願いします。

ここまででDocker を実行するための環境が整いました。
以降から、Docker コマンドを実際にたたいていきます。

### <i class="fa fa-cube" style="font-size:1em;"></i> イメージ取得・確認
#### <i class="fa fa-hand-o-right"></i> docker search
```bash
Usage:	docker search [OPTIONS] TERM
```
[Docker Hub](https://hub.docker.com/) 上のイメージを探すコマンド。
今回は`CentOS` のイメージを探してみます。

```bash
$ docker search centos
  # NAME                            DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
  # centos                          The official build of CentOS.                   1288      [OK]
  # ansible/centos7-ansible         Ansible on Centos7                              54                   [OK]
  # jdeathe/centos-ssh-apache-php   CentOS-6 6.6 x86_64 / Apache / PHP / PHP m...   11                   [OK]
  # blalor/centos                   Bare-bones base CentOS 6.5 image                9                    [OK]
```
`CentOS` から公式レポジトリとして`centos` が提供されていることがわかります。`CentOS7` 上で`Ansible` のレポジトリが`ansible` から提供されていることなどもわかります。
イメージにはタグが付いていることもあるのですが、ここでは確認することができません。[Docker Hub](https://hub.docker.com/) 上のレポジトリで確認するしかできない？

### <i class="fa fa-hand-o-right"></i> docker pull
```bash
Usage:	docker pull [OPTIONS] NAME[:TAG|@DIGEST]
```
[Docker Hub](https://hub.docker.com/) や他のレジストリからイメージをダウンロードするコマンド。
今回はホストと同じ`CentOS Linux release 7.1.1503` を取得してみます。

```bash
$ docker pull centos:7.1.1503
  # 7.1.1503: Pulling from library/centos
  # f1b10cd84249: Pull complete
  # c43c1996cf18: Pull complete
  # f1dade627e25: Already exists
  # library/centos:7.1.1503: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security.
  # Digest: sha256:81254d2112bb3b3850b158b3f8ff7177481bc15e984b55b73e7b218f1458b3f8
  # Status: Downloaded newer image for centos:7.1.1503
```

### <i class="fa fa-hand-o-right"></i> docker images
```bash
Usage:	docker images [OPTIONS] [REPOSITORY]
```
Docker コンテナの一覧を表示するためのコマンド。

```bash
$ docker images
  # REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
  # centos              7.1.1503            f1dade627e25        4 months ago        212.1 MB
```

先ほど`pull` してきた`centos:7.1.1503` だけあることがわかります。

イメージの取得・確認については終了になります。
ここで実行したコマンドをまとめると

```
docker search でイメージを検索して、
docker pull でイメージを取得して、
docker images でイメージが取得できていることの確認。
```
以上になります。

### <i class="fa fa-cube" style="font-size:1em;"></i> コンテナの起動・プロセスの確認・停止
#### <i class="fa fa-hand-o-right"></i> docker run
```bash
Usage:	docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
```
Docker コンテナの起動のためのコマンド。

最初に画面に「Hello Docker」と表示するコンテナを起動してみます。

```bash
$ docker run centos:7.1.1503 echo "Hello Docker"
  # Hello Docker
```
画面に「Hello Docker」が表示されました。
このコンテナは `echo "Hello Docker"` を実行して終了しています。
この時、ローカルにイメージが存在しない場合、自動的に [Docker Hub](https://hub.docker.com/) からイメージを取得した後、コンテナを起動します。

`docker run` を実行するときに`-i` と`-t` のオプションをつけるとターミナルでコンテナを実行することができます。

```bash
$ docker run -i -t centos:7.1.1503 /bin/bash
[root@6bfc1d3dce46 /]$ uname -a
  # Linux 6bfc1d3dce46 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
```
`exit` を入力すると、ターミナルを終了し、ホストターミナルに戻ります。
ただし、ターミナルを終了した場合、コンテナも停止します。
コンテナを停止せずにターミナルを抜けるには`CTRL + p + q` で抜けます。

#### <i class="fa fa-hand-o-right"></i> docker ps
```bash
Usage:	docker ps [OPTIONS]
```
Docker コンテナの一覧を表示するためのコマンド。
オプションを指定しないで`docker ps` を実行すると *稼働中* のコンテナのみ表示されます。

```bash
$ docker ps
  # CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```

今はコンテナが起動していないため、なにも表示されません。
停止したコンテナも含めて表示したい場合は`-a` オプションを使います。

```bash
$ docker ps -a
  # CONTAINER ID        IMAGE               COMMAND                 CREATED             STATUS                     PORTS               NAMES
  # 55ca9592e692        centos:7.1.1503     "/bin/bash"             19 seconds ago      Exited (127) 10 seconds ago                        hopeful_engelbart
  # ab9c04bb875c        centos:7.1.1503     "echo 'Hello Docker'"   8 minutes ago       Exited (0) 8 minutes ago                       backstabbing_yalow
```
先ほど「Hello Docker」を表示したコンテナの情報を見れることがわかります。
※ この時コンテナの名前は指定しないと<i class="fa fa-external-link-square" style="font-size:1em;"></i>[docker/pkg/namesgenerator](https://github.com/docker/docker/blob/master/pkg/namesgenerator/names-generator.go) で自動生成されています。`_` の後ろは著名な科学者、ハッカーになっています。ソースコードを見ると<i class="fa fa-external-link-square" style="font-size:1em;"></i>[wikipedia](https://en.wikipedia.org/wiki/Main_Page) へのリンクも貼ってありますので見ると面白いと思います。

ここまでは、コンテナを実行して終了するか、直接コンテナを操作してきました。
それ以外にも、バッググラウンドまたはデーモンとして実行するデタッチド・モードでの実行ができます。
デタッチド・モードでの実行は`-d` オプションを使います。

```bash
$ docker run -d centos:7.1.1503 ping 127.0.0.1 -c 50
  # 3bc4c7db392b040984bb9d4acaf201fa019a10448dce144feeffe91e98a0892e
```
デタッチド・モードで実行すると、画面にコンテナID が出力されます。
この、コンテナID は`docker ps` を実行したい際に出力されるコンテナID と同一になります。
今後、コンテナIDは色々なコマンドで使われます。

```bash
$ docker ps
  # CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
  # 3bc4c7db392b        centos:7.1.1503     "ping 127.0.0.1 -c 50"   4 seconds ago       Up 3 seconds                            angry_leakey
```

このコンテナは50回自分自身に`ping` を実行すると自動的に停止します。
デタッチドモードで起動しているコンテナにはアタッチすることができます。

#### <i class="fa fa-hand-o-right"></i> docker attach
```bash
Usage:	docker attach [OPTIONS] CONTAINER
```
起動中のコンテナにアタッチするコマンド。
コンテナにアタッチすると、バックグラウンドで実行しているコンテナをフォアグラウンドにします。
ターミナルには`PID 1` のプロセスの出力が表示されます。
ターミナルから抜ける際に`CTRL + p + q` ではなく、`CTRL + c` または`exit` で抜けてしまった際にはプロセスと一緒にコンテナも停止してしまいます。

```bash
$ docker run -d centos:7.1.1503 ping 127.0.0.1 -c 50
  # 038437cdf8c096c1d22452f81d4f156d6fd4592b1884fd1957b2acc8abb7d0ee
$ docker attach 038437cdf8c096c1d22452f81d4f156d6fd4592b1884fd1957b2acc8abb7d0ee
  # 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.040 ms
  # 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.041 ms
  # ...
  # 64 bytes from 127.0.0.1: icmp_seq=49 ttl=64 time=0.038 ms
  # 64 bytes from 127.0.0.1: icmp_seq=50 ttl=64 time=0.048 ms
  # 
  # --- 127.0.0.1 ping statistics ---
  # 50 packets transmitted, 50 received, 0% packet loss, time 48999ms
  # rtt min/avg/max/mdev = 0.017/0.031/0.059/0.012 ms
```

#### <i class="fa fa-hand-o-right"></i> docker exec
```bash
Usage:	docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
```
起動中のコンテナに追加プロセスを実行するコマンド。
典型的な使い方は、ターミナルへのアクセスになります。
`docker attach` とは違い、ターミナルを終了しても、コンテナを停止しません。

```bash
$ docker run -d nginx
  # ceee8e94971c70b53d62abde824778af79c85c6caf7f66cc1320e035fe02df03
$ docker exec -i -t ceee8e94971c70b53d62abde824778af79c85c6caf7f66cc1320e035fe02df03 /bin/bash
root@ceee8e94971c:/# ps -el
  # F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
  # 4 S     0     1     0  0  80   0 -  7874 sigsus ?        00:00:00 nginx
  # 5 S   104     6     1  0  80   0 -  7968 ep_pol ?        00:00:00 nginx
  # 4 S     0     7     0  0  80   0 -  5052 wait   ?        00:00:00 bash
  # 0 R     0    11     7  0  80   0 -  2268 -      ?        00:00:00 ps
root@ceee8e94971c:/# exit
  # exit
$ docker ps
  # CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
  # ceee8e94971c        nginx               "nginx -g 'daemon off"   2 minutes ago       Up 2 minutes        80/tcp, 443/tcp     pensive_ptolemy
```
この通り`exit` をしても、コンテナは停止しません。

#### <i class="fa fa-hand-o-right"></i> docker logs
```bash
Usage:	docker logs [OPTIONS] CONTAINER
```
コンテナの`log` を表示するコマンド。
表示される`log` はコンテナが作成されてからの`PID 1` のあらゆる標準出力が表示されます。

```bash
$ docker run -d centos:7.1.1503 ping 127.0.0.1 -c 5
  # f90abb628b712fb24592d55480785d84239ee039f1373e574ccb8a3ddab7f97a
$ docker ps
  # CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
$ docker logs f90abb628b712fb24592d55480785d84239ee039f1373e574ccb8a3ddab7f97a
  # PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
  # 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.044 ms
  # 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.035 ms
  # 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.053 ms
  # 64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.019 ms
  # 64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.039 ms
  # 
  # --- 127.0.0.1 ping statistics ---
  # 5 packets transmitted, 5 received, 0% packet loss, time 3999ms
  # rtt min/avg/max/mdev = 0.019/0.038/0.053/0.011 ms
```
よく使われるオプションとして、`-f` と`--tail` があります。
`-f`: 直近のログを表示し続ける。Linux の`tail -f` コマンドと類似。 
`--tail` : ログの末尾から「何」行目を指定して表示できる。

#### <i class="fa fa-hand-o-right"></i> docker stop / docker kill
```bash
Usage:	docker stop [OPTIONS] CONTAINER [CONTAINER...]
```
```bash
Usage:	docker kill [OPTIONS] CONTAINER [CONTAINER...]
```
両方共コンテナを停止するためのコマンド。
`docker stop` はメインのコンテナ・プロセスに `SIGTERM` を送信後、一定期間が経過したら`SIGKILL` を送信。期間の指定は`-f` を使用。(デフォルトは10秒)
`docker kill` はメインのコンテナ・プロセスに`SIGKILL` を直ちに送信。

#### <i class="fa fa-hand-o-right"></i> docker start
```bash
Usage:	docker start [OPTIONS] CONTAINER [CONTAINER...]
```
停止したコンテナを再起動するコマンド。
コンテナは以前に指定したものと同じオプションで起動。`-a` でアタッチすることが可能。

```bash
$ docker run -d centos:7.1.1503 ping 127.0.0.1 -c 100
  # b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3
$ docker logs -f b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3
  # PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
  # 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.060 ms
  # 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.038 ms
  # ...
$ docker stop b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3
  # b1faa73c4503
$ docker start -a b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3
  # PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
  # 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.028 ms
  # 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.041 ms
  # ...
```
長かったですが、これでひと通りのコンテナの起動・プロセスの確認・停止については終了になります。

ここで実行したコマンドをまとめると

```
docker run でコンテナの起動をして、
docker ps でコンテナの一覧を表示して、
docker attach でコンテナにアタッチするか、
docker exec でコンテナに追加プロセスを実行させターミナルへアクセス。
docker logs でコンテナのlog を表示し、
docker stop /kill  でコンテナの停止、
docker start で停止したコンテナの再開。
```
以上になります。
ただ、ここで実行したコマンドにはたくさんのオプションがあります。
ぜひ、自分で色々と試してみてください。

### <i class="fa fa-cube" style="font-size:1em;"></i> コンテナの詳細情報確認
#### <i class="fa fa-hand-o-right"></i> docker inspect
```bash
Usage:	docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]
```
コンテナに関する詳細全てを表示するためのコマンド。出力の詳細は`JSON` 配列。
先ほど使った、`b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3` コンテナの中身を確認。

```bash
$ docker inspect b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3
  # [
  # {
  #     "Id": "b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3",
  #     "Created": "2015-09-08T13:06:53.616052821Z",
  #     "Path": "ping",
  #     "Args": [
  #         "127.0.0.1",
  #         "-c",
  #         "100"
  #     ],
  #     "State": {
  #         "Running": false,
  #         "Paused": false,
  # ...
```
特定の項目を見つけるには、パイプでつないで`grep` をするか、`--format` でフォーマットして表示をします。
フォーマットは `Go` 言語の<i class="fa fa-external-link-square" style="font-size:1em;"></i>[text/template](http://golang.org/pkg/text/template/) を参照してください。

```bash
$ docker inspect --format='{{.Args}}' b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3
  # [127.0.0.1 -c 100]
```
`JSON` 形式で表示するには以下のように実行します。

```bash
$ docker inspect --format='{{json .Args}}' b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3
  # ["127.0.0.1","-c","100"]
```

これで、コンテナの詳細情報確認は終了となります。
ここで実行したコマンドをまとめると

```
docker inspect でコンテナの詳細情報を確認。
--format オプションで、フィルタ、フォーマットを行う。
```
以上になります。

### <i class="fa fa-cube" style="font-size:1em;"></i> コンテナの削除
#### <i class="fa fa-hand-o-right"></i> docker rm
```bash
Usage:	docker rm [OPTIONS] CONTAINER [CONTAINER...]
```
コンテナを削除するためのコマンド。
先ほど、使っていた`b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3` コンテナを削除してみます。

```bash
$ docker ps -a | grep 'b1faa73c4503'
  # b1faa73c4503        centos:7.1.1503     "ping 127.0.0.1 -c 10"   37 minutes ago      Exited (0) 36 minutes ago                       sleepy_darwin
$ docker rm b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3
  # b1faa73c450331504f217c13819029274424be422342d9f8bb3c54d999a124c3
$ docker ps -a | grep 'b1faa73c4503'
```
削除されました。
ここで、いつもならまとめに入りますが今回は違います。
`docker rm` を実行する際には、コンテナID を指定もしますが、停止しているコンテナ全てを削除、コンテナのstatus がexited のもののみ削除、最後に実行したコンテナの削除などを指定したい場合があります。
そこで、`docker ps` のオプションをもう少しだけ勉強したいと思います。

```bash
docker ps -q
```
コンテナIDのみ表示。
`-aq` にすることですべてのコンテナID の表示が可能。

```bash
docker ps --filter='status=exited'
```
`--filter` オプションを使うことでフィルタリングすることもできます。
この例ですと、status がexited のコンテナのみ表示されます。

```bash
docker ps -l
```
最後に実行したコンテナの表示。

ここで紹介したような`docker ps` コマンドのオプションを使うことによって、1つ1つコンテナを指定するのではなく、いっぺんにコンテナの削除をすることが可能になります。
例として、status がexited のコンテナ(停止したコンテナ) のみ削除します。

```bash
$ docker run -d centos:7.1.1503 ping 127.0.0.1 -c 200
  # 3b557c8a26e369f40e8435656a473398e624db39ba502930469d983da3dff6e0
$ docker ps
  # CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
  # 3b557c8a26e3        centos:7.1.1503     "ping 127.0.0.1 -c 20"   4 seconds ago       Up 3 seconds                            happy_nobel
$ docker ps -a
  # CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                       PORTS               NAMES
  # 3b557c8a26e3        centos:7.1.1503     "ping 127.0.0.1 -c 20"   9 seconds ago       Up 8 seconds                                     happy_nobel
  # 671d9e6acb16        centos:7.1.1503     "ping 127.0.0.1 -c 5"    2 minutes ago       Exited (0) 2 minutes ago                         tender_kilby
  # bcde82a7bf21        nginx               "nginx -g 'daemon off"   4 minutes ago       Exited (137) 2 minutes ago                       jolly_raman
  # 2f646270433c        centos:7.1.1503     "ping 127.0.0.1 -c 50"   5 minutes ago       Exited (0) 5 minutes ago                         furious_brattain
  # 8cc5871bc318        centos:7.1.1503     "ping 127.0.0.1 -c 50"   6 minutes ago       Exited (0) 5 minutes ago                         prickly_khorana
  # d1a3d3f4d980        centos:7.1.1503     "/bin/bash"              6 minutes ago       Exited (0) 6 minutes ago                         kickass_wilson
  # aa94e9595dd5        centos:7.1.1503     "echo 'Hello Docker'"    6 minutes ago       Exited (0) 6 minutes ago                         sleepy_poincare
$ docker rm $(docker ps -aq --filter='status=exited')
  # 671d9e6acb16
  # bcde82a7bf21
  # 2f646270433c
  # 8cc5871bc318
  # d1a3d3f4d980
  # aa94e9595dd5
$ docker ps -a
  # CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
  # 3b557c8a26e3        centos:7.1.1503     "ping 127.0.0.1 -c 20"   51 seconds ago      Up 50 seconds                           happy_nobel
```
起動中のコンテナを削除しようとするとエラーになります。

```bash
$ docker run -d centos:7.1.1503 ping 127.0.0.1 -c 120
  # a8d789407cfbe31f9c5ff37f3107687ad14470b5260267c8bbd258ee1252e714
$ docker ps
  # CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
  # a8d789407cfb        centos:7.1.1503     "ping 127.0.0.1 -c 12"   4 seconds ago       Up 3 seconds                            ecstatic_elion
$ docker rm $(docker ps -q)
  # Error response from daemon: Cannot destroy container a8d789407cfb: Conflict, You cannot remove a running container. Stop the container before attempting removal or use -f
  # Error: failed to remove containers: [a8d789407cfb]
```
メッセージに書いてあるように、`docker rm` に`-f` オプションを付ければ削除できますが起動中のコンテナは`docker stop` した後に`docker rm` をした方が良いと思います。

これで、コンテナの削除は終了となります。
ここで実行したコマンドをまとめると

```bash
docker rm でコンテナの削除。
docker ps コマンドを使ってフィルタリングしたコンテナID の削除ができる。
```
以上になります。

### <i class="fa fa-cube" style="font-size:1em;"></i> イメージの変更・保存
コンテナを起動しなおすとコンテナの中身が初期化されることを確認します。
まず、`centos:7.1.1503` のコンテナを立ち上げ、`/root/` に`hoge.txt` を`touch` します。
その後、`exit` でコンテナを終了します。

```bash
$ docker run -i -t centos:7.1.1503 /bin/bash
[root@729cd1f0315a /]$ touch /root/hoge.txt
[root@729cd1f0315a /]$ ls -l /root/hoge.txt
  # -rw-r--r-- 1 root root 0 Sep  9 10:50 /root/hoge.txt
[root@729cd1f0315a /]$ exit
  # exit
```
再び、`centos:7.1.1503` のコンテナを立ち上げ、`/root/hoge.txt` があるか確認します。

```bash
$ docker run -i -t centos:7.1.1503 /bin/bash
[root@78d5ee90a874 /]$ ls -l /root/hoge.txt
  # ls: cannot access /root/hoge.txt: No such file or directory
[root@78d5ee90a874 /]$ exit
```
ファイルが無いことがわかります。
もう１度 `/root/hoge.txt` を`touch` します。

```bash
$ docker run -i -t centos:7.1.1503 /bin/bash
[root@5023f3c8bedc /]$ touch /root/hoge.txt
[root@5023f3c8bedc /]$ ls -l /root/hoge.txt
  # -rw-r--r-- 1 root root 0 Sep  9 10:54 /root/hoge.txt
[root@5023f3c8bedc /]$ exit
  # exit
```
#### <i class="fa fa-hand-o-right"></i> docker diff

```bash
Usage:	docker diff [OPTIONS] CONTAINER
```
コンテナへの変更内容を確認するためのコマンド。

`docker ps -lq` でさきほど実行した、コンテナID を取得し、変更内容を確認します。

```bash
$ docker diff $(docker ps -lq)
  # C /root
  # A /root/hoge.txt
  # A /root/.bash_history
```
`/root` が変更され、`/root/hoge.txt`、`/root/.bash_history` が追加されたことが分かります。
※ 先頭の`C` が変更、`A` が追加、`D` が削除を表します。

#### <i class="fa fa-hand-o-right"></i> docker commit
```bash
Usage:	docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
```
コンテナを変更し新しいイメージを作成するためのコマンドになります。
※`REPOSITORY` を`Docker Hub ユーザ名/アプリ名` にすると後々[Docker Hub](https://hub.docker.com/) へのコミットが楽になります。

先ほどの、`/root/hoge.txt` を作成したイメージをコミットしてみます。

```bash
$ docker commit 5023f3c8bedc hihihiroro/hoge:1.0
8321174ef33803c9423e5c4f4fd5b2cb6da1811208d355f453276ab37132ef49
```

`docker images` コマンドでコミットしたイメージができていることが確認できます。

```bash
$ docker images
  # REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
  # hihihiroro/hoge     1.0                 8321174ef338        3 minutes ago       212.1 MB
  # nginx               latest              cd3cf76a61ee        2 weeks ago         132.8 MB
  # centos              7.1.1503            f1dade627e25        4 months ago        212.1 MB
```

このイメージを使えば、先ほど`centos:7.1.1503` を実行した時とは違い、コンテナを起動すると`/root/hoge.txt` が置かれているイメージになっていることが分かります。

```bash
$ docker run -i -t centos:7.1.1503 ls -l /root/hoge.txt
  # ls: cannot access /root/hoge.txt: No such file or directory
$ docker run -i -t hihihiroro/hoge:1.0 ls -l /root/hoge.txt
  # -rw-r--r-- 1 root root 0 Sep  9 10:54 /root/hoge.txt
```

#### <i class="fa fa-hand-o-right"></i> docker history
```bash
Usage:	docker history [OPTIONS] IMAGE
```
イメージの更新内容を確認するためのコマンド。
`nginx` の更新内容を見てみます。

```bash
$ docker history cd3cf76a61ee
  # IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
  # cd3cf76a61ee        2 weeks ago         /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon o   0 B
  # 491aec45eaf8        2 weeks ago         /bin/sh -c #(nop) EXPOSE 443/tcp 80/tcp         0 B
  # 3ac9cfbdf572        2 weeks ago         /bin/sh -c #(nop) VOLUME [/var/cache/nginx]     0 B
  # f9bff7d0d06e        2 weeks ago         /bin/sh -c ln -sf /dev/stderr /var/log/nginx/   0 B
  # 8c7e9b6e3131        2 weeks ago         /bin/sh -c ln -sf /dev/stdout /var/log/nginx/   0 B
  # a53219dc4d2f        2 weeks ago         /bin/sh -c apt-get update &&     apt-get inst   7.671 MB
  # 5dde53921c3f        2 weeks ago         /bin/sh -c #(nop) ENV NGINX_VERSION=1.9.4-1~j   0 B
  # 12a77b8bf89a        2 weeks ago         /bin/sh -c echo "deb http://nginx.org/package   221 B
  # ff0618bc0767        2 weeks ago         /bin/sh -c apt-key adv --keyserver hkp://pgp.   1.997 kB
  # 08ecf065655b        2 weeks ago         /bin/sh -c #(nop) MAINTAINER NGINX Docker Mai   0 B
  # 4a5e6db8c069        2 weeks ago         /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B
  # 2c49f83e0b13        2 weeks ago         /bin/sh -c #(nop) ADD file:b770303e11edaa0ad0   125.1 MB
```
これで、イメージの変更・保存は終了となります。
ここで実行したコマンドをまとめると

```
docker diff で元のイメージとの変更の箇所を確認し、
docker commit で新しいイメージの作成をする。
docker history で更新内容の確認をする。
```
以上になります。

### <i class="fa fa-cube" style="font-size:1em;"></i> イメージの削除
#### <i class="fa fa-hand-o-right"></i> docker rmi

```bash
Usage:	docker rmi [OPTIONS] IMAGE [IMAGE...]
```
イメージを削除するためのコマンド。

Docker ではコンテナやイメージを削除しないと、ディスクの消費が増えていきエラーになってしまうことがあります。使わなくなったイメージなどは定期的に削除しておくと良いと思います。

以下の例では、`nginx` のイメージを削除する流れになります。

```bash
$ docker images
  # REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
  # hihihiroro/hoge     1.0                 8321174ef338        19 hours ago        212.1 MB
  # nginx               latest              cd3cf76a61ee        2 weeks ago         132.8 MB
  # centos              7.1.1503            f1dade627e25        4 months ago        212.1 MB
$ docker rmi cd3cf76a61ee
  # Untagged: nginx:latest
  # Deleted: cd3cf76a61eed2094db241cc47185d04320671b2e5db360baf5956aebdbdf82c
  # Deleted: 491aec45eaf837a2f08212075b17c7b869861dcc26ca99d8827e132657177c49
  # Deleted: 3ac9cfbdf572dd789cac65bfce6141f36564de1bd4266f6b51ae6eb19080a6dc
  # Deleted: f9bff7d0d06e65f89dce91e43caefc3fe090818bae24d67c9732bd4a7ada19dc
  # Deleted: 8c7e9b6e31310dacde0b5a97fd4478a75942ef12bd3753f3ed294a14a0f1c6bb
  # Deleted: a53219dc4d2f5503158eddbec871430dc3f29146fdf9b7b99ce1678484f16902
  # Deleted: 5dde53921c3f1adbee72d4bdf4a67b9a2b361a89304c6f841722b4fa87492ac9
  # Deleted: 12a77b8bf89a61d8bfc52c0ceee37e3e627187330d20bff5b091915a90959a61
  # Deleted: ff0618bc0767411abb6b6f28200a67614fea418483f3faa5d649d92b53627e43
  # Deleted: 08ecf065655b44634e66f45201a7d379d30ba877791b1765322dabf57e993f11
  # Deleted: 4a5e6db8c0693a16de88b7559ded7c1cb804018571b137e13abb1713ce6a71cf
  # Deleted: 2c49f83e0b13f73bf3d276c9fe26ba9aa94d2a1614e866642b95cb0245d0cdab
$ docker images
  # REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
  # hihihiroro/hoge     1.0                 8321174ef338        19 hours ago        212.1 MB
  # centos              7.1.1503            f1dade627e25        4 months ago        212.1 MB
```
`docker rmi` も`docker rm` と同様に起動中のコンテナで使われているイメージは削除することができません。

```bash
$ docker run -d centos:7.1.1503 ping 127.0.0.1 -c 120
  # c8a801a7ffe05cb36fe338445fff2dc9ca7a046f22c91e7d868f78ba68d50fe9
$ docker ps
  # CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
  # c8a801a7ffe0        centos:7.1.1503     "ping 127.0.0.1 -c 12"   2 seconds ago       Up 2 seconds                            drunk_khorana
$ docker images
  # REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
  # hihihiroro/hoge     1.0                 8321174ef338        19 hours ago        212.1 MB
  # centos              7.1.1503            f1dade627e25        4 months ago        212.1 MB
$ docker rmi f1dade627e25
  # Error response from daemon: Conflict, cannot delete f1dade627e25 because the running container c8a801a7ffe0 is using it, stop it and use -f to force
  # Error: failed to remove images: [f1dade627e25]
```
こちらも、`-f` オプションを付ければ削除することはできますが、起動中のイメージを消すのはやめた方が良いと思います。

これで、イメージの削除は終了となります。
ここで実行したコマンドをまとめると

```
docker rmi でイメージの削除をする。
```

以上になります。

### <i class="fa fa-cube" style="font-size:1em;"></i> Dockerfile でコンテナ構築
`Dockerfile` とはDocker イメージ構築時の命令を記述した設定ファイルになります。
`Dockerfile` で使えるコマンドには以下のものがあります。
くわしくは[コチラ](https://docs.docker.com/reference/builder/)

|コマンド名|説明|
|:---|:---|
|FROM|ベースイメージの指定|
|MAINTAINER|イメージの作成者|
|RUN|コマンドの実行|
|CMD|docker run 時に起動するコマンド|
|LABEL|コンテナとイメージにユーザ定義の付与できるラベル|
|EXPOSE|コンテナ内のプロセスがListen するポート|
|ENV|環境変数|
|ADD|HostOS からコンテナへファイルを配置|
|COPY|HostOS からコンテナへファイルを配置|
|ENTRYPOINT|docker run 時に起動するコマンド|
|VOLUME|外部からマウント可能なボリューム|
|USER|RUN, CMD, ENTRYPOINT を実行するユーザ|
|WORKDIR|作業ディレクトリ|
|ONBUILD|次のビルドで実行させるコマンド|

今回は、`Dockerfile` を用いて`apache` を動かし、動作確認をするまでを試します。

<i class="fa fa-file-text-o"></i> Dockerfile の作成

```bash
$ mkdir httpd-work; cd httpd-work
$ cat << EOS > Dockerfile
  FROM centos:7.1.1503
  MAINTAINER hihihiroro@gmail.com
  
  RUN yum update && yum -y install httpd && yum clean all
  
  EXPOSE 80
  
  COPY index.html /var/www/html/index.html
  COPY run-httpd.sh /run-httpd.sh
  RUN chmod -v +x /run-httpd.sh
  
  CMD ["/run-httpd.sh"]
  EOS
$ echo "docker test apache server." > index.html
$ cat << EOS > run-httpd.sh
  #!/bin/bash
  
  rm -rf /run/httpd/* /tmp/httpd*
  
  exec /usr/sbin/apachectl -D FOREGROUND
  EOS
```
`Dockerfile` と`COPY` するファイル、実行するコマンドを作成しました。
実際に実行してみます。

#### <i class="fa fa-hand-o-right"></i> docker build
```bash
Usage:	docker build [OPTIONS] PATH | URL | -
```

新しいイメージを作成するためのコマンド。
'hihihiroro/httpd-test' という名前で`1.0` のタグが付いたイメージを作成してみます。

```bash
$ docker build -t hihihiroro/httpd-test:1.0 .
  # Sending build context to Docker daemon 4.096 kB
  # Step 0 : FROM centos:7.1.1503
  # 7.1.1503: Pulling from library/centos
  # f1b10cd84249: Pull complete
  # c43c1996cf18: Pull complete
  # f1dade627e25: Pull complete
  # library/centos:7.1.1503: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security.
  # Digest: sha256:4c02104e053f98cb9f9f18871eaa34e65e2dbd78afe5e22500b334b770da7b7c
  # Status: Downloaded newer image for centos:7.1.1503
  #  ---> f1dade627e25
  # Step 1 : MAINTAINER hihihiroro@gmail.com
  #  ---> Running in ea0c121431c3
  #  ...
  # Step 6 : RUN chmod -v +x /run-httpd.sh
  #  ---> Running in 849be47f1acc
  # mode of '/run-httpd.sh' changed from 0644 (rw-r--r--) to 0755 (rwxr-xr-x)
  #  ---> 8bb7346e9632
  # Removing intermediate container 849be47f1acc
  # Step 7 : CMD /run-httpd.sh
  #  ---> Running in 752b4a3c4bdf
  #  ---> 9cd960f26b80
  # Removing intermediate container 752b4a3c4bdf
  # Successfully built 9cd960f26b80
```
無事にイメージができあがりました。

```bash
$ docker images
  # REPOSITORY              TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
  # hihihiroro/httpd-test   1.0                 9cd960f26b80        About a minute ago   330.1 MB
  # centos                  7.1.1503            f1dade627e25        4 months ago         212.1 MB
```
`FROM` で`centos:7.1.1503` を指定しているので、`centos:7.1.1503` のイメージも取得されていることが分かります。

では、作ったイメージを`docker run` で動かしてみようと思います。

```bash
docker run -d -p 80:80 hihihiroro/httpd-test:1.0
  # 5e918f6f9afbc26582dfd11af88d9cbae4c60dff570af2472c5efca9f168150c
```
ここで使っている`-p` オプションはホスト側とコンテナ側のポートをマッピングするためのオプションになります。
使い方は、`-p ホスト側IP:コンテナ側IP` になります。

#### <i class="fa fa-hand-o-right"></i> docker port
```bash
Usage:	docker port [OPTIONS] CONTAINER [PRIVATE_PORT[/PROTO]]
```
コンテナ側のポートがホスト側のどのポートにマッピングされているか調べるコマンドになります。

```bash
$ docker port $(docker ps -q) 80
  # 0.0.0.0:80
```
`-p` オプションで指定した通りに、コンテナ側の80番ポートがホスト側の80番ポートにマッピングされていることが分かります。

コンテナが指定した、`index.html` で動いていることを確認します。

```bash
$ curl http://xxx.xxx.xxx.xxx
  # docker test apache server.
```
指定した通りの`index.html` が表示されています。
これで、`Dockerfile` でコンテナ構築は終了となります。
ここで実行したことをまとめると

```
Dockerfile を作成し、
docker build でイメージを作成。
docker run で作成したイメージを実行。
```
以上になります。

### <i class="fa fa-cube" style="font-size:1em;"></i> レポジトリへのイメージ登録
いよいよ最後になります。

#### <i class="fa fa-hand-o-right"></i> docker login
```bash
Usage: docker login [OPTIONS] [SERVER]
```
レポジトリサーバへログインするためのコマンドになります。
`[SERVER]` を指定していない時は[Docker Hub](https://hub.docker.com/) に接続します。

```bash
$ docker login
$ Username: hihihiroro
$ Password:
$ Email: hihihiroro@gmail.com
  # Login Succeeded
```

#### <i class="fa fa-hand-o-right"></i> docker push
```bash
Usage:	docker push [OPTIONS] NAME[:TAG]
```
イメージやレポジトリをレジストリに登録するためのコマンドになります。
実際に、作った`apache` のイメージを[Docker Hub](https://hub.docker.com/) に登録してみます。

```bash
docker push hihihiroro/httpd-test:1.0
  # The push refers to a repository [docker.io/hihihiroro/httpd-test] (len: 1)
  # 9cd960f26b80: Image successfully pushed
  # 8bb7346e9632: Image successfully pushed
  # 489686ede596: Image successfully pushed
  # d22e71b95cfc: Image successfully pushed
  # f33c519ac00e: Image successfully pushed
  # b097e847ed78: Image successfully pushed
  # 14fc6e4ee97a: Image successfully pushed
  # 9747ba9c2882: Image successfully pushed
  # f1dade627e25: Image already exists
  # c43c1996cf18: Image successfully pushed
  # f1b10cd84249: Image already exists
  # 1.0: digest: sha256:a8b08735924a454417358fa33002ee901f49f41ec6cdac4d2e5310d15dd5a6a6 size: 19761
```
これで、レポジトリへのイメージ登録は終了となります。
ここで実行したコマンドをまとめると

```bash
docekr login でレポジトリにログインし、
docker push でイメージをレポジトリに登録する。
```

今回は、`apache` を自分でインストールしましたが、[Docker Hub](https://hub.docker.com/) 上には[Apache](http://www.apache.org) が提供している[オフィシャルのイメージ](https://hub.docker.com/_/httpd/)が登録されています。
他にも様々な、ミドルウェアやデータベースなど幅広いイメージが登録されています。

ハンズオン手順は以上で終了となります。
使ってないオプションがいっぱいあります。是非自分でどんどん試してみてください。
おつかれさまでした。

# <i class="fa fa-cubes" style="font-size:1em;"></i> 参考
* [Docker](https://www.docker.com)
* [Docker Hub](https://hub.docker.com)
* [docker source](https://github.com/docker)
* [知らぬはエンジニアの恥。今さら聞けない【コンテナ/仮想化技術】11選](http://paiza.hatenablog.com/entry/2014/10/21/知らぬはエンジニアの恥%E3%80%82今さら聞けない【コン)
* [Qiita の記事の見出しに Font-Awesome を利用して見栄えを良くする #qiita](http://qiita.com/tbpgr/items/361d8aaa38fb57d75216)