今更ですが、Docker を使ってみる


## Dockerについて
　Dockerサイト → https://docs.docker.com
　参考 → https://employment.en-japan.com/engineerhub/entry/2017/09/28/110000
　
2013年に Docker社が開発しオープンソース化した仮想化環境の一つ。
コンテナと呼ばれる技術を使って軽量で容易に仮想化環境を構築できます。

## インストール
開発環境に合わせてパッケージがあるのでインストールします。
　→ https://store.docker.com/search?type=edition&offering=community

うちの開発環境は MacOSX なので Mac用をダウンロードしてインストールしました。
＃Docker Hub にアクセスするために？ログインを聞いてくるので初めての場合はアカウント作成してログインします。
インストールが完了したら Terminal を開いて確認します。

```
$ docker --version
Docker version 17.09.0-ce, build afdb6d4

$ docker-compose --version
docker-compose version 1.16.1, build 6d1ac21

$ docker-machine --version
docker-machine version 0.12.2, build 9371605
```

## 動作確認
試しに次のコマンドを実行します。

```
$ docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
5b0f327be733: Pull complete 
Digest: sha256:175735360662078abd70dacb73c5518d5b3ae7c1ed069d22def5da57c3e917d6
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イメージ
Docker は イメージと呼ばれる動作の塊みたいなものを Docker hub から取ってくるか或いは自分で作るかして、それをコンテナ上で実行する、というイメージです。

`docker run <image>` は image をコンテナ上で走らす、というコマンドで、前項の `docker run hello-world` は 'Hello from Docker!' と説明文を表示する動作の塊（hello-worldイメージ）を（手元になければ取ってきて）コンテナを作成して実行する、というコマンドでした。

で、イメージですが、自分で一から作ってもいいみたいですが、多くの方が既にたくさんのイメージを作って公開されているので、それを利用させてもらいます。
自分のやろうとしていることに近いイメージを取得して、それを改造して利用するといういやりかたが一番スマートなのかもしれません。

## nginx が走る Dockerイメージ を作ってみる

その前に、まずは Docker ではなくて普通に仮想マシンで nginx が走るようにする場合を考えます。
1. 仮想マシンの作成（OSインストール、ネットワーク設定）
2. nginx のパッケージをインストールするかソースコードを取得してコンパイル
3. nginx の設定
4. 実行
以上だと思いますが、OSインストールからとなると、少し面倒ですw

Docker を使った場合も流れは同じですが、仮想マシンを作成する必要がないため、比較的すぐに nginx のインストールから始めることができます。

### debian のイメージを pull する
ここでは OS は debian を利用します。もちろん ubuntu とか centos でも大丈夫。

```
$ docker pull debian
```
docker hub に登録されている debian の最新版を取得します。
バージョン（タグ）指定とかもできるみたいです。例えば 8.7 を取得したい場合は
`docker pull debian:8.7`
どんなタグがあるのかはAPIで確認できるみたいです。

```
$ curl -s https://registry.hub.docker.com/v1/repositories/debian/tags
[{"layer": "", "name": "latest"}, {"layer": "", "name": "6"}, {"layer": "", "name": "6.0"}, {"layer": "", "name": "6.0.10"}, {"layer": "", "name": "6.0.8"}, {"layer": "", "name": "6.0.9"}, {"layer": "", "name": "7"}, {"layer": "", "name": "7.10"}, {"layer": "", "name": "7.11"}, {"layer": "", "name": "7.3"}, {"layer": "", "name": "7.4"}, {"layer": "", "name": "7.5"}, {"layer": "", "name": "7.6"}, {"layer": "", "name": "7.7"}, {"layer": "", "name": "7.8"}, {"layer": "", "name": "7.9"}, {"layer": "", "name": "8"}, {"layer": "", "name": "8.0"}, {"layer": "", "name": "8.1"}, {"layer": "", "name": "8.2"}, {"layer": "", "name": "8.3"}, {"layer": "", "name": "8.4"}, {"layer": "", "name": "8.5"}, {"layer": "", "name": "8.6"}, {"layer": "", "name": "8.7"}, ...
```

### ダウンロードしたイメージを走らせる
```
$ docker run -it --name docker_nginx debian /bin/bash
root@37aa52782342:/#
```
んでコンテナ上で走っている debian 最新版にログインできました。
`-it` は interactive + tty でコンソールにログインしてごにょごにょできるオプションです。
あと、イメージ名だけだとすぐに終了するのでシェルを走らせるコマンドをつけておきます。→ `/bin/bash`
それから、`--name` でイメージに名前を付けることができます。これを付けておくとあとでいろいろと便利なので、付けておきましょう。

これで OS のインストール？は完了です。
次に nginx をインストールします。

### nginx のインストール
普通にインストールして実行してみます。

```
# apt-get update
# apt-get install nginx
# /etc/init.d/nginx start
```
で、確認したいのですが、取得した debian イメージは最低限のものしかないので、確認するものをインストールします。
curl をインストールしてみます。

```
# apt-get install curl
# curl http://localhost
```
HTMLが表示されたら成功です。
終了は

```
# exit
```
です。

### コンテナの終了
前項で、インストールと実行が確認できたのですが、docker は基本的にイメージは上書き禁止になっています。
ではどうやってインストールしていたのかというと、レイヤーという方法で実現しているみたいです。
ベースとなるイメージとの差分を重ねていくことで実現しているみたいです。

なので終了して破棄すると先ほどの nginx のインストール はなかったことになってしまいます。
終了しているかどうかは `docker ps -a` で調べることができます。

```
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                  NAMES
2d93a23033af        debian              "/bin/bash"              7 hours ago         Exited (0) 3 seconds ago                          docker_nginx
```

STATUS が Exited (0) 3 seconds ago になってます。3秒前に終了した、という状態ですね。
この状態ではまだイメージは残っています。
再度アクセスしたい場合は `docker start -i docker_nginx` と入力します。

イメージは明示的に破棄しなければ残ります。
ちなみに明示的な破棄の方法は二つあって、一つは docker run 時に `--rm` オプションを付けるか、もう一つは `docker rm` で削除するかです。

### 新しいイメージの作成
せっかく変更を加えたイメージなので、このイメージを新しい名前で保存します。＃ベースイメージに変更を加えたものをコミットします。

```
$ docker commit -m 'add nginx' docker_nginx ysomei/nginx
sha256:d6168451070dc61a8173f6dde790c0fe7b532dd3e5c9618f1009355f5d25d988
```

-m はコメント記入で docker_nginx は run するときに --name で付けた名前。
ysomei/nginx は新しいイメージの名前になります。＃ユーザー名/イメージ名 みたいです。
試しに `docker images` を実行すると

```
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ysomei/nginx        latest              d6168451070d        6 minutes ago       193MB
```
となって、新しくイメージが作成されているのがわかります。
続きを作業したい場合は、

```
$ docker run -it --name ysomei_nginx ysomei/nginx /bin/bash
```
とするとコンソールでごにょごにょできます。

## コンテナとホストをつなぐ
前項までで nginx のコンテナを起動するところまでできました。しかしながらこのままでは外部からアクセスすることができませんので繋げてあげる必要があります。
基本的には docker run の `-p` オプションでホスト上のポートにコンテナ上のポートをフォワードすれば良いです。

```
$ docker run -p 8086:80 ysomei/nginx /etc/init.d/nginx start
```
ですが、docker run は一通り処理をしたら自動的に終了するようになっているので、少し細工が必要になります。

### 終わらない細工を入れる
コンテナに入って以下をします。

```
$ docker run -it --name ysomei_nginx ysomei/nginx /bin/bash
# cd /usr/local/sbin
# vi run.sh
```

vi が入ってなければ `apt-get install vim` をします。
＃エディターは自分の使いやすいのでいいですよ。

```bash:run.sh
#!/bin/bash
/etc/init.d/nginx start
tail -f /dev/null
```
で、`chmod +x run.sh` で実行権限を追加しておきます。

ポイントは最後の `tail -f /dev/null` です。
無限に空デバイスを表示させることで終了しないコンテナが出来上がります :)

そしたら、一旦終了してイメージを更新します。

```
$ docker commit -m 'add run.sh' ysomei_nginx ysomei/nginx
sha256:d099d6d777549a20a1a26b47c5b8adf38d2c40e48b0d04e085e81bf75510b759
```

### nginxコンテナ起動！
終わらない細工をしたのでコンテナを起動させます。

```
$ docker run -d -p 8086:80 --name ysomei_nginx ysomei/nginx /usr/local/sbin/run.sh
f2814017ed405393c5d79968c958e3c061466652b0bb3396e834cb606be28d5d
```
オプションの `-d` はデーモンとして起動です。
`-p 8086:80` で、コンテナ上の 80ポートをホストの 8086ポートにフォワードします。

では確認してみましょう。まずはプロセス確認。

```
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
f2814017ed40        ysomei/nginx        "/usr/local/sbin/r..."   2 minutes ago       Up 2 minutes        0.0.0.0:8086->80/tcp   ysomei_nginx
```
STATUS が Exited じゃなくて Up 2 minutes になってますね。起動して 2分ということです。
では 8086ポートにアクセスしてみましょう。

```
$ curl http://localhost:8086/
```
HTMLが流れたら成功です。ブラウザでも確認してみてください。

## まとめ
とまあこんな感じです。
仮想環境へのインストールになるので、実環境が汚れなくていいかなぁなんて思います。
また、イメージができたらこれを持ち運ぶことで Docker の動く他の環境でもコンテナを起動して実行できるようになります。

```
$ docker save -o ysomei_nginx.tar ysomei/nginx
```
でイメージがファイルに出力されました。
読み込みは

```
$ docker load -i ysomei_nginx.tar 
fba06a98a658: Loading layer   94.5MB/94.5MB
65b3667d0d44: Loading layer  33.02MB/33.02MB
Loaded image: ysomei/nginx:latest
```
です。

とりあえず今回はここまで。