プログラマのためのDocker超入門 05.Dockerのよさ（中編）

　
![docker.png](https://qiita-image-store.s3.amazonaws.com/0/66457/da2303a9-e25a-8035-3e5f-e5692ef96383.png)

# 前提

`インフラ？やっといたほうがいいの？`な方への記事です。
正確な説明や比喩よりも、わかりやすさを優先します。

# 過去記事であがった未解決な課題

前回 [04.Dockerのよさ（前編）](/pottava/items/50b90403b895742467dc)で解決しなかった残課題。

第2回の[構成管理](/pottava/items/5b386a952bf1d26ea387)では

* OSによっては構成管理が期待通りに動かない
* 同じ定義書を利用しても、隣の人とまったく同じ環境になる保証がない
* そもそもプロジェクトごとに定義書作るのは（煩雑さが緩和されず）やっぱり大変

第3回の[クラウド](/pottava/items/3d75477b467d93de8784)では

* スナップショットからは作業履歴を追いにくい
* サーバスペックは複数種類からの選択で、それでは過剰もしくは不足
* ポータビリティが下がるベンダーロックインの心配
* サーバ単位でDisposable Componentsするのは時間的金銭的に非効率

# Dockerとはなにか

[前回](/pottava/items/50b90403b895742467dc#docker%E3%81%A8%E3%81%AF%E3%81%AA%E3%81%AB%E3%81%8B)に引き続き、4以降の詳細をみていきましょう！

## 4.1 gitのように commit, push, pullを使った履歴管理ができる

Dockerは、サーバのいまの状態を Dockerイメージとして保存したり
簡易的ながらその変更履歴をみることができます。

また、そのイメージを`レジストリ`と呼ばれる管理サーバに
アップロードしたり、そこからダウンロードすることで
他の人と Dockerイメージを共有することができます。
（レジストリは、gitや svnのリポジトリみたいなものです）

こんな感じで作業します。

1. レジストリから、テンプレートである Dockerイメージを取得します  
`$ docker pull`
2. サーバに入って編集してそれを保存するか、`ビルド`[^1]します  
`$ docker run -it image bash`  
`$ docker commit`  
　　　or  
`$ docker build`
3. レジストリへ共有します  
`$ docker push`

`push`したイメージは、`pull`で持ってくれば、pullしてきたところでも
pushしたものと`まったく同じコンテナを起動する`ことができます。

## 4.2 push, pullで共有した Dockerイメージを使う

残った課題に、

> ・同じ定義書を利用しても、隣の人とまったく同じ環境になる保証がない

というものがありましたが、Jenkinsのような [CIサーバ](http://www.sophia-it.com/content/CI%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC)上で
構成管理ツールを使って Dockerイメージを作り、レジストリを介して
それをみんなで使う形にすればこれが解決です！！便利ですね！

また、サーバに対して編集した内容は、以下のコマンドで後から確認できます[^2]。
`$ docker history`

つまりこれも解決です。

> ・スナップショットからは作業履歴を追いにくい

## 5.1 Dockerイメージは、クラスのように継承できる

4.1の見方を変えると、実は、Dockerイメージは`継承`できることがわかります。

例えば、`ubuntu:14.04` のイメージを pullしてきて
Nginx1.9.3 をインストールした `mine/nginx:1.9.3` というイメージと
そこに HTMLコンテンツを追加した`mine/app:latest` というイメージ、
一方で ubuntuに MySQL5.6 をインストールした `mine/mysql:5.6`
というイメージを作った場合、その関係はこうなります。

![docker-hierarchy.png](https://qiita-image-store.s3.amazonaws.com/0/66457/f3d2edba-8cc2-5980-b3aa-e91e74eed200.png)


これらをコンテナとして利用するときは

```bash
$ docker run -d --name mysql mine/mysql:5.6
$ docker run -d --name web -p 80:80 -link mysql:db mine/app
```

という形で、Nginxを継承した appコンテナを立ち上げて使います。

## 5.2 共通（親）イメージの利用

Dockerイメージはレジストリを使って他の人とも共有できますが
`他のプロジェクト`で使う上でも、これはとても便利な状況です。

5.1の例で言えば、nginxは他のプロジェクトでも使えるわけです。
各プロジェクトでは appイメージだけ[^3]を管理すればよくなります！

例えば、私の[勤務先](http://www.supinf.co.jp/)では

* プロジェクト共通イメージは `library/nginx:1.9.3` など library以下で作成
* 共通イメージを作るための構成管理定義書は専用の gitリポジトリで管理
* 社員だけがアクセスできる Dockerレジストリを介して
* 各プロジェクトは共通イメージを pull
* `a-project/app:latest`といった名前で、構成管理ツールを使いビルド

しており、
各プロジェクトではそのプロジェクト固有のサーバ要件のみ[^4]を
git管理すればいいので、構成管理上最小限の定義書で済みます。


> ・プロジェクトごとに定義書作るのはやっぱり大変

これが解決です。

Dockerイメージのおかげで定義書のコピペはほとんどなく、
プロジェクト共通のイメージの更新は CIツールなどでの
ビルドを通して各プロジェクトにすぐに反映されます :blush: 

# 今回のまとめ

2回で書き切りたかったのですが長くなってしまったので、次回続きを。。

Dockerのよさ、ちょっとイメージできてきたでしょうか？
記事では伝えきれませんが、Dockerは、ほんとうに簡単に
`保存`したり`起動`したり`共有`したりできます。
とにかく速い。

開発環境を作る手間やトラブルを防ぐためにも
Dockerの利用を検討する価値はありますよ〜

[06. Dockerのよさ（後編）](/pottava/items/5cba799ff54ce5af79e5)へ
　
[^1]: 具体的な Dockerの扱い方は次回以降に記載します・・
[^2]: 実際には、ちゃんとヒストリをみるなら buildを使ってビルドしないとですね
[^3]: コンテンツをコンテナにマウントするだけなら`docker run -v`でもOK
[^4]: 例えばデータベース名がbarだとか、nginxの設定差分とか。