開発におけるDocker導入のメリット

DockerのPros/Consとか今更感ある。他の仮想化技術との比較記事はよく目にするが、開発にどのようなメリット・デメリットがあるのかあまり周知されていないようなので自分なりの感想を書いておく。

## Pros

- 同一性
  - 複数人で開発する際に、環境の差が生まれない。
- カプセル化
  - アプリケーション込みの環境をコンテナというカプセルに隠蔽することができる。
  - コンテナという単位に対するテストが可能に。
  - コンテナを捨てる・再生成するのが容易。
- ポータビリティ（一貫性とも）
  - 開発に使ったコンテナをCIでテストできる。
  - CIでテストしたコンテナをサーバーにデプロイできる。
  - デプロイしたコンテナをスケールできる。

### Prosで防げる消耗

<dl>

<dt><p>おれの環境では動いた。</p></dt>
<dd>はい。</dd>
<dd>複数の開発者で同一の環境で開発できるので防げる。</dd>

<dt><p>ローカルで通ったテストがCIでコケる。</p></dt>
<dd>開発と同一の環境でテストできるので防げる。</dd>

<dt><p><code>bundle install</code>, <code>npm install</code> に失敗してテストがコケる。</p></dt>
<dd>依存ライブラリのフェッチに成功したイメージでテストすることで防げる。</dd>

<dt><p>コードを変更していないのにアプリケーションの挙動が変わった。<code>go get</code>してるライブラリの挙動がいつの間にか変わってたぽい。</p></dt>
<dd>依存ライブラリをフェッチしたイメージを共有することで、バージョンを固定できる。</dd>

<dt><p>nginxの設定を変更したい。サーバにログインするためのSSHキーどれだっけ。</p></dt>
<dd>手元で設定して動作を確認しDockerイメージをデプロイすることができるので、設定変更のためにサーバーにログインする必要がなくなる。</dd>
<dd>さらに、正しく設定できているかブラックボックステストすることも可能に。</dd>

</dl>

これらは一例だが、このような開発の本質ではない・解決のために時間を取られたくない問題が解消し、開発が捗る。

## Cons

- 学習コスト
  - コンテナを立ち上げるあたりまではコスト低めだが、実際に開発環境としてDockerを使うあたりから「これどうやってやるんだろう」「どちらの方法で設定するのが良いのだろう」のノウハウが出てくる感じになる。
  - 開発者全員に深い知識が必要かというとそうではないが、問題解決できる知識を持った人間が開発陣に最低一人は必要。
- ローカルでの開発とほぼ遜色ない環境でコードを書くことができるということを周知するためのコスト

### Consで発生するコスト

<dl>

<dt><p>質の良いイメージの作り方を学ぶ</p></dt>
<dd><a href="http://jonathan.bergknoff.com/journal/building-good-docker-images">Jonathan Bergknoff: Building Good Docker Images</a></dd>
<dd><a href="https://www.qoosky.net/techs/207">Dockerfile ベストプラクティス (仮) - Qoosky</a></dd>

<dt><p>「コンテナにログインしてコード書かなきゃいけないんでしょ」</p></dt>
<dd>「ホストとコンテナのボリュームを共有できるので好きなエディタでコードを書けるよ」</dd>

<dt><p>「コンテナ同士のネットワーキングとかめんどくさそう」</p></dt>
<dd>「(<a href="https://docs.docker.com/compose/">Docker Compose</a>|<a href="https://www.tutum.co/">Tutum</a>|<a href="http://kubernetes.io/">Kubernetes</a>)が面倒みてくれるよ」<br>
　　　　　＿人人人人人人人人＿<br>
　　　　　＞ 新たな学習コスト ＜<br>
　　　　　￣^Y^Y^Y^Y^Y^Y^Y￣</dd>

<dt><p><code>docker build --build-arg FOO=bar</code>+<code>ARG</code>+<code>ENV</code> or <code>docker run --env FOO=bar</code> どっちがよい？</p></dt>
<dd>ケースバイケース。カプセル化を優先するなら前者だし、一貫性を優先するなら後者。</dd>

<dt><p><code>docker run --volume /host/dir:/container/dir</code> or <code>docker run --volume /container/dir</code> どっちがよい？</p></dt>
<dd>ケースバイケース。開発時にホストのディレクトリとボリュームを共有するとかデータの永続化目的なら前者だし、他のコンテナとボリュームを共有するなら後者。</dd>

</dl>

これらは一例だが、このような学習コストや周知コストが発生し、場合によっては開発が中断する。

## Prosを支える周辺サービス

### イメージ共有サービス

複数環境での開発において同一性を保持するためのイメージ共有サービス達。

- [Docker Hub](https://hub.docker.com/): イメージのビルドとホストをするサービス。
  - [Pricing | Docker](https://www.docker.com/pricing)
- [Google Container Registry](https://cloud.google.com/container-registry/): イメージのホストをするサービス。
  - Google Cloud Storage にタグやイメージを保存してくれる。
  - 料金は Google Cloud Storage の利用料と転送量のみ。
  - イメージはCIでビルドするのでホストだけしたいといったケースだと割安感ある。

他にも色々ある模様: [本番運用を見据えたDocker Registry選定 - Qiita](http://qiita.com/Vexus2/items/e84f5869c01e08438538)

### CIサービス

開発に使ったコンテナと同一の環境を、ポータビリティを活かしてテストするサービス達。

- [CircleCI](https://circleci.com/): Dockerサポート[^circleci-docker]
  - キャッシュ機構[^circleci-cache]があるので、ビルドしたイメージをキャッシュし差分ビルドできる。
  - 最新のバージョンもフォローアップ[^circleci-docker-version]

[^circleci-docker]: [Continuous Integration and Delivery with Docker - CircleCI](https://circleci.com/docs/docker)
[^circleci-cache]: [CircleCIのキャッシュ(cache_directories)の挙動を解説するよ - tehepero note(・ω<)](http://stormcat.hatenablog.com/entry/2015/12/03/110000)
[^circleci-docker-version]: [CircleCIでDocker v1.9.0を使う方法 - Qiita](http://qiita.com/minodisk/items/de62b206cc38925322ee)

### 複数コンテナのサーバー運用サービス

ポータビリティを活かしてサーバーにイメージをデプロイ、起動してれるサービス達。

- [Tutum](https://www.tutum.co/): 各種IaaSと連携し、複数コンテナをビルド・デプロイ・管理できるサービス。[^tutum-docker]
  - 連携していないIaaSでも、SSHのログイン情報を設定することでセットアップしてくれる。
  - 料金は各IaaSに依存。本サービス自体は2016/1/14現在、βで無料。[^tutum-pricing]
  - セットアップが簡単で学習コストが低い。
- [Google Container Engine](https://cloud.google.com/container-engine/): [Kubernetes](http://kubernetes.io/)をGoogle Compute Engine上にセットアップしてくれるサービス。
  - 複数ノードをクラスタリングして1つのプラットフォームとする。
  - 複数コンテナをポッドという単位で扱い、レプリケーション・死活管理・オートスケーリング・ローリングアップデートするアプリケーション。
  - 構築したクラスタ内に複数のサービスをデプロイできるので、マイクロサービスを複数立ち上げるケースなど場合によってはコストが抑えられる。
  - その他Google Cloud Platformの恩恵がある。[^gcp]
  - 料金はGoogle Compute Engineの価格に依存。6ノード以上でクラスタリングすると別途課金が発生する。
  - 実運用においては学習コストが高い。

[^tutum-docker]: Docker社に買収されたのでDockerとの親和性が担保されそう。
[^tutum-pricing]: [Pricing - Tutum](https://www.tutum.co/pricing/)
[^gcp]: [GoogleContainerEngine - GKEを便利にするGCPのサービス - Qiita](http://qiita.com/minodisk/items/085f97472fd727c2adc6)

## Dockerの導入について

開発の本質ではない部分での消耗がなくなるというのは驚くほどキレイな心を保つことができて精神衛生上よいし、本番環境での運用まで一貫性が保てるとテストを通した環境をそのまま運用しているという安心感が生まれる。一方の学習コストについては、一度学習してしまえば次回からは同じハマり方はしないので、一度このコストを払ってしまえばよいという考え方もある。とはいえ、導入するか否かは開発体制やプロダクトによるので、各個のケースに応じ`Pros > Cons`ならば導入したらよいのではないだろうか。

**導入は計画的に。**