※2014/10/19追記
figを使ってもっとお手軽に同じようなことをする構成を別記事にしました!
http://qiita.com/toritori0318/items/190fd2dad2bf3ce38b88
Mac上でVagrantを起動し、その中にDockerコンテナを立ちあげ、
コンテナ内のソースとローカルのソースを同期させる開発環境を構築してみます。
そもそも何が目的なのか?
開発環境の配布です。
今までは setup.sh のようなもので
プログラム言語/関連モジュール/ミドルウェアなどをローカルにインストールして
開発環境を整えていましたが
共有ライブラリのバージョン違い/元環境とのコンフリクト/エンジニアのスキルセットなどにより
上手くいかないことも多々ありました。
そこで、すべての環境はVagrant(Docker)に置いて環境依存を無くし、
かつローカルのソースコードと同期することによって
あたかも全ての環境がローカルに存在するかのごとく振る舞うことが可能なVagrant環境を構築してみました。
つまり Vagrantだけあればすぐに開発できる環境が入手できる ということになります。
また、Vagrant直でやらないのは全部入りの環境を提供して作業させようとすると
VM起動が遅くそれがストレスになるからです。
アプリケーションだけでなくミドルウェアも含めてコンテナ化することで
軽量かつ汎用的な環境を配布できると考えました。
サンプルソースコード
こちらに置いてあります。
Vagrantは1.6以上が必要です。
https://github.com/toritori0318/flask-vagrant-docker-sample
サンプルの概要/ポートマッピング図
3つのコンテナを用意しています。
- nginx
- python-app
- redis
python-appは
アクセスする毎にカウントをインクリメントして表示
するだけの簡単なアプリです。Redisに情報を保存しています。
nginxはpython-appの5000番ポートにリバースプロキシしており、
python-appはredisの6379番ポートにアクセスしています。
各コンテナはそれぞれ
nginx(10080)/python-app(15000)/redis(16379)
にポートフォワードさせ、ローカルMacから直接アクセスできるように設定しています。
ディレクトリ同期概要図
Mac⇔Vagrant間はsynced_folder(NFS)で、
Vagrant⇔Dockerコンテナ間はvolume(正確にはdocker providerのvolumes)で
実現しています。
Mac上の./logディレクトリは nginxコンテナのログ全般と、appサーバのデバッグログが同期されます。
./appディレクトリはpython-appコンテナのアプリケーションディレクトリと同期させています。
コンテナ間の通信について
linkを使います。
python-app ⇔ redis間はこのリンクを、
nginx ⇔ python-app間はこのリンクを 設定しています。
python-app内でredisを参照しているのはここで環境変数を読み込んでいるだけです。
nginxでは、直接nginx.confで環境変数を読み込むのが上手くいかなかったので1
run.sh内でsed置換しています。
開発フロー
ローカルMac上のappディレクトリ以下のファイルを修正します。
すると、python-appコンテナ上のappにも修正が反映し
自動で適用されます(自動適用はflaskの機能)。
また、ログファイルはローカルMac上の ./logディレクトリにリアルタイムで反映されるのでデバッグも容易です。
やってみよう
-
まずは Dockerコンテナを起動します。
vagrant up --provider=docker redis python-app nginx
-
うまく動いているか確認してみます。
-
./app/server.pyを修正してみます。
-
しばらくすると自動で修正が反映された!
ローカルファイルだけでなく、
Dockerコンテナ内のファイルが修正されているのがポイントですね。
その他Tips
Dockerホストにログインするには?
vagrant sshでログインしたいところですが、
このVagrantfileで起動するとカレントホストには表示されません2
ですが、vagrant global-statusでidを探してログインすることは可能です。
vagrant ssh <id>
しかし、いちいちid指定するの面倒なので ssh-config に登録してしまいましょう。
これならvmを作りなおしたとしてもsshコマンドでそのままログインできます。
vagrant ssh-config <id>
(ホスト名が「default」になっているのでわかりやすいものに変えたほうが良いでしょう)
コンテナにログインしたい場合は?
サンプルでホストイメージとして使っている yungsang/boot2docker は
nsenter入りなので、それを使うと良いでしょう。
さらに docker-enterという便利コマンドもついているので
お手軽にログイン可能です
# docker-host上からログイン
docker-enter <コンテナID>
# Macから直接最新コンテナにログイン
ssh <ssh-configで設定したホスト名> 'docker-enter $(docker ps -l -q)'
ローカルPCからDockerコマンド実行したいんだけど
dockerコマンドインストール後にDOCKER_HOSTを指定すればOKです。
export DOCKER_HOST=tcp://localhost:2375
というかdockerコマンドはあったほうが便利なので
brewでインストールしておきましょう。
再度Docker Buildしたい場合は?
vagrant reload すると、Docker buildを再実行します。
問題点
Macの電源を落として再度Mac起動した後でDockerコンテナ起動しようとすると
volumeの適用がうまく行かずにエラーが出てしまいます。
これは、一度コンテナを削除して再度作りなおすとうまくいくのですが
このオペレーションを開発者に強制するのも酷ですし、
ここはどうにかして回避したいと考えています。
もしかしたらDocker-providerを使わずにfigなどで自前起動すれば問題ないのかな〜と思っているので
今後検証してみる予定です。
まとめ
コンテナ上のファイルと同期して、
ローカルPCに直接環境構築することなく開発できる環境を作ってみました。
この構成、まだいくつか問題があって絶賛検証中なので
もっと良い方法があればご教授頂ければと思います!