Docker1.3版 boot2docker+fig入門

Docker1.3がリリースされましたね！
それに合わせて、周辺ツールがアップデートされていて
とても便利になったと感じたので紹介してみます。

# Docker/boot2docker

- [Docker 1.3: signed images, process injection, security options, Mac shared directories](http://blog.docker.com/2014/10/docker-1-3-signed-images-process-injection-security-options-mac-shared-directories/)
- [boot2dockerでのVolume問題が解決しそう](http://deeeet.com/writing/2014/10/08/boot2docker-guest-additions/)

Virtual Box Guest Additionsをサポートしたことにより、
MacOS上のファイルとコンテナ内の同期が簡単になりました。
またDockerがexecコマンドをサポートしたことにより
sshインストールなしでコンテナ内でコマンド実行することが出来ます。
でかい。


# fig

[fig](http://www.fig.sh/)は複数のDockerコンテナをお手軽に管理するためのツールです。
シンプルなyamlファイルを用意するだけでコンテナ操作を行うことが出来ます。

- [Fig 1.0: boot2docker compatibility and more](http://blog.docker.com/2014/10/fig-1-0-boot2docker-compatibility-and-more/)

figもDockerのリリースと合わせてアップデートされているようです。

<br>

# 以前と何が変わったのか？

Docker1.2以前ではboot2docker+figを利用しようとすると一手間必要になってしまっていましたが、
1.3からはローカルにfig設定を置くだけで利用することが可能になりました。
つまりローカルMac上からシームレスにコンテナ操作や同期を行うことが出来ます。

実はその辺りを工夫するため、Vagrant+DockerProviderを利用して
ローカル環境とコンテナを同期するための構成を考えていたりしたのですが
（[このエントリ](http://qiita.com/toritori0318/items/b95f15ba06e7a157abf7) 参照）
こんな面倒なことをしなくてもとても簡単に同じことを実現できるということです。

※というか、figチュートリアルがほぼこの要件を満たしてた。。今までの苦労は一体。。。

<br>

# 事前準備

## boot2dockerを1.3にupdate

既にインストール済みの場合は以下の手順でバージョンアップ＋VM更新しておきましょう

```
boot2docker upgrade
boot2docker delete
boot2docker download
boot2docker init
# 確認
boot2docker version
```

<br>

# figのチュートリアルを実行してみる

補足を入れつつ、[公式サイト](http://www.fig.sh/) とほぼ同じ手順を踏んでみます。
適当にディレクトリを掘って、以下のファイルを置いてみてください。
（他にも[Rails](http://www.fig.sh/rails.html)/[Django](http://www.fig.sh/django.html)/[Wordpress](http://www.fig.sh/wordpress.html)のサンプルもあるようです）

### pythonアプリ作成

アクセスするとRedisにカウントアップして表示するだけのスクリプトです。

```python:app.py

# -*- coding: utf-8 -*-
from flask import Flask
from redis import Redis
import os
app = Flask(__name__)

# ホスト＝redisというのは、figが設定している/etc/hostsを参照しています。後ほど補足
# もちろん、Docker標準の環境変数を利用してもOKです
redis = Redis(host='redis', port=6379)  

@app.route('/')
def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')

if __name__ == "__main__":
    # これはflaskの設定Tipsですが、他のコンテナから見えるようにhost="0.0.0.0"を設定する必要があります
    app.run(host="0.0.0.0", debug=True)
```

```:requirements.txt
flask
redis
```

### Dockerfile作成

python:2.7イメージをダウンロードし、
Mac上のカレントディレクトリ以下をコンテナの/codeに追加し、
pipで必要なpythonモジュールをインストールしています。

```:Dockerfile
FROM python:2.7
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
```

### figファイル作成

```yaml:fig.yml
web:            # サービス名です。この名前でコンテナにアクセスできます
  build: .                  # ./Dockerfileを用いビルドする
  command: python app.py    # ビルド後のコンテナで実行するコマンド
  ports:
   - "5000:5000"            # ポートフォワード設定。フォーマットは <ホスト側ポート>:<コンテナ側ポート>
  volumes:
   - .:/code                # ボリューム設定。ローカル「.」を コンテナ「/code」に同期
  links:
   - redis:redis            # リンク設定。フォーマットは <サービス名>:<エイリアス名>
redis:
  image: redis              # DockerRegistry上のredisイメージを用いコンテナ生成
```

<br>

# 実行してみる

まずはboot2dockerを起動し、
次にfigでコンテナを起動して
アプリケーションが実行されているか確認してみます。

## boot2docker

### boot2docker:VM起動

ホストとなるboot2dockerを起動します。これは今までと変わらず。

```pl
# VM起動
boot2docker up
# Docker関連の環境変数設定
#   コンソールに表示された環境変数をコピペでも良いですが、
#   以下のコマンドでも良いらしい
$(boot2docker shellinit)
```

## fig

figコマンドを実行します。
ほとんどコマンドは「サービス名」を引数に取ることが出来ます。
サービス名を省略した場合は「全サービス」を対象にコマンド実行します。

### fig:コンテナ起動

figのカレントディレクトリでfigコマンドを実行します。
（デーモン起動する時は -d オプションを追記）
（既にイメージ作成済みの場合は fig start でOK）

```
fig up
```

本当の初回だけはイメージのダウンロードなどが発生しますが、
２回目以後は一瞬でコンテナ起動するようになります。

### fig:サンプルアプリケーションにアクセスしてみる

ホストVMのipを確認後、curlでアクセスしてみましょう。

```pl

# IP確認。/etc/hostsなどに登録しておくと良いですね
boot2docker ip
# アプリにアクセス
curl 192.168.59.103:5000
(Hello World! I have been seen blah 1 times.)

```

### fig:コンテナ(サービス)の確認

psコマンドで確認できます。サービス名などが付いているので非常に見やすいですね。
-q オプションを指定するとコンテナIDが表示されます。

``` 
fig ps 
```
![スクリーンショット 2014-10-19 1.53.05.png](https://qiita-image-store.s3.amazonaws.com/0/9099/312ce2f7-355e-8fd8-e868-da708f6b4038.png)



### fig:停止

コンテナを停止します。

```
fig stop
```

### fig:ログ表示

コンテナ内のログもfigから取得できます。
以下はwebサービスのlogを取得します。

```pl

# フォーマット
fig logs サービス名
# redisサービスのログ表示
fig logs redis
```


### fig:その他にも

いくつかコマンドがありますので、fig コマンドを叩いて確認してみてください。

<br>

## figについての補足情報

### サービス名を/etc/hostsに反映してくれる

そのままなのですが、サービス名を設定すると/etc/hostsに反映してくれるようです。
軽く確認してみたところ、以下のような感じで反映するようです。

```yaml
web:
  links:
    - redis:redis6379
redis:
  ...
```

```:web_etc_hosts
...
x.x.x.x	figtest_web_1
x.x.x.x	redis6379
x.x.x.x	redis_1
x.x.x.x	web
x.x.x.x	web_1
x.x.x.x	figtest_redis_1
...
```

```:redis_etc_hosts
...
x.x.x.x	figtest_redis_1
x.x.x.x	redis
x.x.x.x	redis_1
...
```

「自分のホスト情報」＋「linksで設定したホスト情報」が設定されるようですね。
fig run <サービス名> cat /etc/hosts で確認してみましょう。

<br>

# まとめ

Docker1.3に対応したboot2dockerと、figの機能を紹介してみました。 
figを使うとシンプルにコンテナ管理が出来ますし、
なによりコンテナIDではなくサービス名で使えるのがとても便利です。
さらに、ローカル環境の構築でいままで悩んでいたことがだいぶ解消されていて
ライフチェンジングになりそうな感じです。  
まだまだ「触ってみた」程度なので、自分の環境でもどしどし使ってみて
開発フローに組み込んで行きたいと思います！！

## おまけその１
Macをリスタートした後のDocker起動時間の肌感、
ローカルファイルとコンテナ内ファイルが同期される様子、
などをキャプチャしてみました。
figの起動が一瞬で終わっててコンテナ最高〜♪
![record.gif](https://qiita-image-store.s3.amazonaws.com/0/9099/efcb398a-6468-93bf-12fe-295decf7df68.gif)

## おまけその２
fig.yml一枚書くだけ（！）でconsulクラスタ構築するデモです。
figコンフィグはこちら。
Mac上から一台のサーバに向けてAPIを実行したかったので
consulserverのみ別ポート(+10000)でポートフォワードしています。

```yaml:fig.yml
consulserver:
  image: progrium/consul
  command: -server -bootstrap
  ports:
   - "18300:8300"
   - "18400:8400"
   - "18500:8500"
consulclientA:
  image: progrium/consul
  command: -join consulserver
  links:
   - consulserver
consulclientB:
  image: progrium/consul
  command: -join consulserver
  links:
   - consulserver
consulclientC:
  image: progrium/consul
  command: -join consulserver
  links:
   - consulserver
```

デモはこちら。
![record_demo_consul.gif](https://qiita-image-store.s3.amazonaws.com/0/9099/920a89ad-1ca2-a0df-3ede-00ff8ad00ebd.gif)
やばい。