Dockerハンズオン基礎編：コンテナとイメージのライフサイクルを理解

## 概要
コマンドラインで手を動かしながら、コンテナやイメージの作成や実行、移動、削除について理解を深めます。

 - Docker CE(Community Edition) v17.03以降の内容に対応しています。

## 達成できること

- Docker イメージとコンテナの基本操作を理解
- Docker イメージの自動構築
- Docker Hub でイメージ送受信

## 0. はじめに（用語の確認）

「Docker」とは、アプリケーションなどのソフトウェアを簡単にどこでも「コンテナ」として実行するためのプラットフォームです。このハンズオンおよび一般的な操作における Docker とは、プログラム全体を司る、サーバ上でデーモンとして常駐している Docker Engine（エンジン）を指します。

「コンテナ」（container）とは、ソフトウェアの実行に必要なすべてをパッケージ化したものです。しかし、仮想マシンとは異なり、オペレーティングシステム部分は含みません。

Docker Engine は、ソフトウエアの実行に必要なファイルと設定情報がパッケージ化された「Docker イメージ」を操作します。また、Docker Engine は「Docker イメージ」に含まれるソフトウェアを「コンテナ」（プロセスなどが 「分離」(isolate)された状態）として操作します。

## 1. 初めての "hello-wolrd" コンテナの実行とイメージの確認

コンテナを実行

$ docker run hello-world

このコマンドを実行すると、 `hello-world` という名称の「Docker イメージ」（以下、イメージと省略）を使い、コンテナを実行します。初回実行時は、ローカルにイメージが存在しないため、自動的に Docker Hub（ハブ）からイメージをダウンロードします。ダウンロードが終われば、そのまま実行します。

```実行結果
$ docker container run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
78445dd45222: Pull complete
Digest: sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://cloud.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/
```

ローカルにあるイメージ一覧を確認するには、 `docker images` コマンドを実行します。

```
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              48b5124b2768        4 months ago        1.84kB
```
## 2. whalesay イメージのダウンロードと実行

鯨に何かメッセージを表示するプログラム、 `docker/whalesay` イメージをダウンロードします。イメージをダウンロードするコマンドは `docker pull` です。

```
$ docker pull docker/whalesay
```

それから、 `docker images` コマンドを実行し、ローカルに `docker/whalesay` イメージがあることを確認します。

```
$ docker images
hello-world         latest              48b5124b2768        4 months ago        1.84kB
docker/whalesay     latest              6b362a9f73eb        2 years ago         247MB
```

次に `docker/whalesay` イメージを実行します。実行時の引数として

- イメージ内にある `cowsay` プログラムの実行
- `cowsay` プログラムの引数 `Hello world`

を、指定します。

````
$ docker run docker/whalesay cowsay Hello world
 _____________
< Hello world >
 -------------
    \
     \
      \
                    ##        .
              ## ## ##       ==
           ## ## ## ##      ===
       /""""""""""""""""___/ ===
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
       \______ o          __/
        \    \        __/
          \____\______/
```

文字を置き換えて、何度か実行します。

## 3. カスタマイズした Docker イメージを自分で作成

既存の whalesay イメージを元に、新しいイメージを作成します。

まずは、作業用ディレクトリを作成し、移動します。

```
$ mkdir mybuild
$ cd mybuild
```

イメージを構築する方法は２つあります。

- `docker commit` コマンドで手動作成する方法
- `docker build` コマンドと `Dockerfile` ファイルで自動作成する方法

ここでは後者の `Dockerfile` を使った自動構築方法を学びます。

`vi` などのエディタで `Dockerfile` を作成します。

```
$ vi Dockerfile
```

ファイルの内容は、次のようにして保存します。

```
FROM docker/whalesay:latest
RUN apt-get -y update && apt-get install -y fortunes
CMD /usr/games/fortune -a | cowsay
```

イメージを構築するには `docker build` コマンドを実行します。ここでは `mywhale` という名前のイメージを作成します。

```
$ docker build -t mywhale .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM docker/whalesay:latest
 ---> 6b362a9f73eb
Step 2/3 : RUN apt-get -y update && apt-get install -y fortunes
（省略）
Successfully built 8b4d2d7a8c4f
Successfully tagged mywhale:latest
```

イメージが作成されたかどうか、 `docker images` コマンドで確認します。

```
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
mywhale             latest              8b4d2d7a8c4f        About a minute ago   257MB
（省略）
```

このイメージを使って、コンテナを `docker run`コマンドで 実行します。

```
$ docker run mywhale

 ____________________________
< Disposable, use only once. >
 ----------------------------
    \
     \
      \
                    ##        .
              ## ## ##       ==
           ## ## ## ##      ===
       /""""""""""""""""___/ ===
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
       \______ o          __/
        \    \        __/
          \____\______/
```


## 4. Docker Hub にアップロード

作成したイメージはローカル環境上で実行できますが、そのまま他のサーバで実行できません。他の場所でイメージを実行するには Dockerfile を再構築する方法や、イメージをファイルとして入出力する方法もあります。ここでは一番簡単で時間のかからない Docker Hub を使う方法を試します。

Docker Hub はイメージをダウンロードするだけでなく、自分で作成したイメージのアップロードもできます。アップロードをするためには、Docker Hub 上にアカウント作成が必要です。アカウント作成は無料です。

Docker Hub https://hub.docker.com/ を開き、ユーザ名、メールアドレス、パスワードを入力し、 `Signup` （サインアップ）をおします。暫くすると、登録したメールアドレス宛に確認用のメールが届きます。届いたら、メール本文にある確認用のリンクをクリックします。

イメージを Docker Hub に送信する前に、 `docker login` コマンドを実行します。

```
$ 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: <ユーザ名を入力>
Password:
```

認証が通れば、認証情報がファイル `~/.docker/config.json` に記録されます（アカウント情報を共有している場合、誰でも Docker Hub の操作ができますので、ご注意下さい。 `docker logout` コマンドで認証情報を削除できます）。

イメージを送信する前に `docker tag` コマンドで、イメージの名称を Docker Hub アカウント名がついたものへとタグ付けする必要があります。

```
$ docker tag mywhale <ユーザ名>/mywhale
```

実行後は `docker images`  コマンドで同一イメージに対して別のタグが付いたのを確認します。

```実行例：
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mywhale             latest              8b4d2d7a8c4f        21 minutes ago      257MB
zembutsu/mywhale    latest              8b4d2d7a8c4f        21 minutes ago      257MB
```

次に Docker Hub にイメージを送信するには `docker push` コマンドを使います。


```
$ docker push <ユーザ名>/mywhale
```

暫くすると、送信が完了します。

```実行例：
$ docker push zembutsu/mywhale
The push refers to a repository [docker.io/zembutsu/mywhale]
92631520c105: Pushed
5f70bf18a086: Layer already exists
d061ee1340ec: Layer already exists
d511ed9e12e1: Layer already exists
091abc5148e4: Layer already exists
b26122d57afa: Layer already exists
37ee47034d9b: Layer already exists
528c8710fd95: Layer already exists
1154ba695078: Layer already exists
latest: digest: sha256:25fdc321b4629d2eb26ae418780fd254f19a0a570e48bae2d2a66bbef20aeb4a size: 2613
```

あとは、ブラウザで [Docker Hub](https://hub.docker.com/) にアクセス、ログインし、自分のリポジトリ上にアップロードされているのを確認します。

## 5. イメージの削除と再ダウンロード

アップロードしたイメージは、ローカルから削除しても再度ダウンロードできるのを確認します。

イメージを削除するには `docker rmi` コマンドを使います。

```
$ docker rmi mywhale <ユーザ名>/mywhale
```

それから `docker images` コマンドを実行しても、 `whale` や `<ユーザ名>/mywhale`  イメージの情報が表示されず、削除されたことがわかります。


再度イメージをダウンロードします。

```
$ docker pull ユーザ名/mywhale
```

あとは、 `docker run` を実行し、先ほど自分でカスタマイズしたイメージが実行されるのを確認します。

```
$  docker run zembutsu/mywhale
 _________________________________________
/ Far duller than a serpent's tooth it is \
\ to spend a quiet youth.                 /
 -----------------------------------------
    \
     \
      \
                    ##        .
              ## ## ##       ==
           ## ## ## ##      ===
       /""""""""""""""""___/ ===
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
       \______ o          __/
        \    \        __/
          \____\______/
```

## 6. 後片付け

最後に、不要になったコンテナやイメージを全て削除します。 

`docker rmi` でイメージを削除します。

また、使用中のイメージやコンテナの数と要領を確認するコマンド `docker system df` を実行します。

```実行例
$ docker system df
TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              18                  3                   2.996GB             2.987GB (99%)
Containers          6                   0                   0B                  0B
Local Volumes       23                  0                   63.91MB             63.91MB (100%)
```

次に、残った不要なコンテナ、タグ付けされていないイメージ（dangling image）、直近のコンテナで使われていないネットワークやボリュームを `docker system prune` コマンドで削除できます。

```
$ docker system prune
WARNING! This will remove:
        - all stopped containers
        - all volumes not used by at least one container
        - all networks not used by at least one container
        - all dangling images
Are you sure you want to continue? [y/N] y	←【y】を入力
```

## 次のステップ

- [応用チュートリアル１：Compose で CMS（WordPress）を動かす](http://qiita.com/zembutsu/items/26cb3a3d138d26c42bab)
- [応用チュートリアル２：Compose で 監視サーバ（Zabbix Server）を動かす](http://qiita.com/zembutsu/items/d03d79896a9e23657075)
- [応用チュートリアル３：Compose で Mastodon を動かす](http://qiita.com/zembutsu/items/f1f1ede26102ba27fce2)

## 参考

- What is Docker?
 - https://www.docker.com/what-docker
- イメージとコンテナを学ぶ — Docker-docs-ja 1.13.RC ドキュメント
 - http://docs.docker.jp/engine/getstarted/step_two.html