Docker1.3がリリースされましたね!
それに合わせて、周辺ツールがアップデートされていて
とても便利になったと感じたので紹介してみます。
Docker/boot2docker
- Docker 1.3: signed images, process injection, security options, Mac shared directories
- boot2dockerでのVolume問題が解決しそう
Virtual Box Guest Additionsをサポートしたことにより、
MacOS上のファイルとコンテナ内の同期が簡単になりました。
またDockerがexecコマンドをサポートしたことにより
sshインストールなしでコンテナ内でコマンド実行することが出来ます。
でかい。
fig
figは複数のDockerコンテナをお手軽に管理するためのツールです。
シンプルなyamlファイルを用意するだけでコンテナ操作を行うことが出来ます。
figもDockerのリリースと合わせてアップデートされているようです。
以前と何が変わったのか?
Docker1.2以前ではboot2docker+figを利用しようとすると一手間必要になってしまっていましたが、
1.3からはローカルにfig設定を置くだけで利用することが可能になりました。
つまりローカルMac上からシームレスにコンテナ操作や同期を行うことが出来ます。
実はその辺りを工夫するため、Vagrant+DockerProviderを利用して
ローカル環境とコンテナを同期するための構成を考えていたりしたのですが
(このエントリ 参照)
こんな面倒なことをしなくてもとても簡単に同じことを実現できるということです。
※というか、figチュートリアルがほぼこの要件を満たしてた。。今までの苦労は一体。。。
事前準備
boot2dockerを1.3にupdate
既にインストール済みの場合は以下の手順でバージョンアップ+VM更新しておきましょう
boot2docker upgrade
boot2docker delete
boot2docker download
boot2docker init
# 確認
boot2docker version
figのチュートリアルを実行してみる
補足を入れつつ、公式サイト とほぼ同じ手順を踏んでみます。
適当にディレクトリを掘って、以下のファイルを置いてみてください。
(他にもRails/Django/Wordpressのサンプルもあるようです)
pythonアプリ作成
アクセスするとRedisにカウントアップして表示するだけのスクリプトです。
# -*- 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)
flask
redis
Dockerfile作成
python:2.7イメージをダウンロードし、
Mac上のカレントディレクトリ以下をコンテナの/codeに追加し、
pipで必要なpythonモジュールをインストールしています。
FROM python:2.7
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
figファイル作成
web: # サービス名です。この名前でコンテナにアクセスできます
build: . # ./Dockerfileを用いビルドする
command: python app.py # ビルド後のコンテナで実行するコマンド
ports:
- "5000:5000" # ポートフォワード設定。フォーマットは <ホスト側ポート>:<コンテナ側ポート>
volumes:
- .:/code # ボリューム設定。ローカル「.」を コンテナ「/code」に同期
links:
- redis:redis # リンク設定。フォーマットは <サービス名>:<エイリアス名>
redis:
image: redis # DockerRegistry上のredisイメージを用いコンテナ生成
実行してみる
まずはboot2dockerを起動し、
次にfigでコンテナを起動して
アプリケーションが実行されているか確認してみます。
boot2docker
boot2docker:VM起動
ホストとなるboot2dockerを起動します。これは今までと変わらず。
# VM起動
boot2docker up
# Docker関連の環境変数設定
# コンソールに表示された環境変数をコピペでも良いですが、
# 以下のコマンドでも良いらしい
$(boot2docker shellinit)
fig
figコマンドを実行します。
ほとんどコマンドは「サービス名」を引数に取ることが出来ます。
サービス名を省略した場合は「全サービス」を対象にコマンド実行します。
fig:コンテナ起動
figのカレントディレクトリでfigコマンドを実行します。
(デーモン起動する時は -d オプションを追記)
(既にイメージ作成済みの場合は fig start でOK)
fig up
本当の初回だけはイメージのダウンロードなどが発生しますが、
2回目以後は一瞬でコンテナ起動するようになります。
fig:サンプルアプリケーションにアクセスしてみる
ホストVMのipを確認後、curlでアクセスしてみましょう。
# 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
fig:停止
コンテナを停止します。
fig stop
fig:ログ表示
コンテナ内のログもfigから取得できます。
以下はwebサービスのlogを取得します。
# フォーマット
fig logs サービス名
# redisサービスのログ表示
fig logs redis
fig:その他にも
いくつかコマンドがありますので、fig コマンドを叩いて確認してみてください。
figについての補足情報
サービス名を/etc/hostsに反映してくれる
そのままなのですが、サービス名を設定すると/etc/hostsに反映してくれるようです。
軽く確認してみたところ、以下のような感じで反映するようです。
web:
links:
- redis:redis6379
redis:
...
...
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
...
...
x.x.x.x figtest_redis_1
x.x.x.x redis
x.x.x.x redis_1
...
「自分のホスト情報」+「linksで設定したホスト情報」が設定されるようですね。
fig run <サービス名> cat /etc/hosts で確認してみましょう。
まとめ
Docker1.3に対応したboot2dockerと、figの機能を紹介してみました。
figを使うとシンプルにコンテナ管理が出来ますし、
なによりコンテナIDではなくサービス名で使えるのがとても便利です。
さらに、ローカル環境の構築でいままで悩んでいたことがだいぶ解消されていて
ライフチェンジングになりそうな感じです。
まだまだ「触ってみた」程度なので、自分の環境でもどしどし使ってみて
開発フローに組み込んで行きたいと思います!!
おまけその1
Macをリスタートした後のDocker起動時間の肌感、
ローカルファイルとコンテナ内ファイルが同期される様子、
などをキャプチャしてみました。
figの起動が一瞬で終わっててコンテナ最高〜♪
おまけその2
fig.yml一枚書くだけ(!)でconsulクラスタ構築するデモです。
figコンフィグはこちら。
Mac上から一台のサーバに向けてAPIを実行したかったので
consulserverのみ別ポート(+10000)でポートフォワードしています。
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