Docker でフロントエンド開発も楽できるか?(後編)
引き続きよろしくね Docker さん
前編では、
- Mac に Docker をインストールする
- Docker の VM をインストール、起動
- イメージの取得、コンテナ起動、管理
までをざっくりやってみた。 今日は、 nodejs が動く環境のイメージを作成して使ってみる。 また、コンテナ管理ツールの fig をインストールし、触ってみる。
アジェンダ
- イメージの作成
- イメージの作成
- 作成したイメージを元にコンテナを作成、起動
- fig を使ってコンテナを管理する
- fig をインストールする
- まずはチュートリアル
- フロントエンド開発環境を fig で管理する
- 設定ファイルを追加
- 環境構築し、fig を起動する
- おまけ: DockerHub に登録
- Docker を使った私見
イメージの作成
前回は Dockerhub に公開されているイメージを取得して使ったが、今回はイメージを作って触ってみる。
Dockerfile
イメージのレシピ(環境構築の手順書的なもの)は Dockerfile というファイルに書いて管理するらしい。 最初なので、試しに公式のをみながら nodejs と ruby 環境を構築するための Dockerfile を書いてみた。 nodejs は version 0.10.32、ruby は 1.9 系にしている。それから、bower、grunt、gulp、compass などよく使うモジュールもインストールしておく。
### Dockerfile
# Pull base image.
FROM dockerfile/python
# Timezone Setting
RUN echo "Asia/Tokyo" > /etc/timezone
# Install Ruby.
RUN \
apt-get update && \
apt-get install -y ruby ruby-dev ruby-bundler && \
rm -rf /var/lib/apt/lists/*
# Install Gems
RUN \
gem install compass
# Install Node.js
RUN \
cd /tmp && \
wget http://nodejs.org/dist/v0.10.32/node-v0.10.32.tar.gz && \
tar xvzf node-v0.10.32.tar.gz && \
rm -f node-v0.10.32.tar.gz && \
cd node-v* && \
./configure && \
CXX="g++ -Wno-unused-local-typedefs" make && \
CXX="g++ -Wno-unused-local-typedefs" make install && \
cd /tmp && \
rm -rf /tmp/node-v* && \
npm install -g npm && \
echo -e '\n# Node.js\nexport PATH="node_modules/.bin:$PATH"' >> /root/.bashrc
# Install Node modules
RUN \
npm install -g grunt-cli gulp webpack bower
# Define working directory.
WORKDIR /data
# Define default command.
CMD ["bash"]
このファイルのあるディレクトリで、以下のコマンドを実行してイメージを作成する。
$ docker build -t sample-nodejs:v0.10.32 ./
Sending build context to Docker daemon 75.78 kB
Sending build context to Docker daemon
Step 0 : FROM dockerfile/python
...(略)
Step 1 : RUN echo "Asia/Tokyo" > /etc/timezone
---> Running in f19240aa9215
---> 26fd3dc22d0b
...(略)
Step 2 : RUN apt-get update && apt-get install -y ruby ruby-dev ruby-bundler && rm -rf /var/lib/apt/lists/*
---> Running in 3886c51ac19f
...(略)
Step 3 : RUN gem install compass
---> Running in 8c1264fc6d17
...(略)
Step 4 : RUN cd /tmp && wget http://nodejs.org/dist/v0.10.32/node-v0.10.32.tar.gz && tar xvzf node-v0.10.32.tar.gz && rm -f node-v0.10.32.tar.gz && cd node-v* && ./configure && CXX="g++ -Wno-unused-local-typedefs" make && CXX="g++ -Wno-unused-local-typedefs" make install && cd /tmp && rm -rf /tmp/node-v* && npm install -g npm && echo -e '\n# Node.js\nexport PATH="node_modules/.bin:$PATH"' >> /root/.bashrc
---> Running in ed22415781ad
...(略)
Step 5 : RUN npm install -g grunt-cli gulp webpack bower
---> Running in 1d1e3d14a1f2
...(略)
Step 6 : WORKDIR /data
---> Running in ab2ba49fafac
...(略)
Removing intermediate container ab2ba49fafac
Step 7 : CMD bash
---> Running in dc1afeb6fbba
...(略)
Successfully built 5d1d9e32b456
## イメージが作成されたか確認
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
sample-nodejs v0.10.32 5d1d9e32b456 2 minutes ago 610.7 MB
この操作による副作用
- 作成した Dockerfile をもとに新規にイメージが作られる
作成したイメージを元にコンテナを作成、起動
作成したイメージを元にコンテナを作ってみる。 –name というオプションを付けて、sample-container という名前のコンテナを作る。
$ docker run -itd --name sample-container sample-nodejs:v0.10.32 /bin/bash
d2974da42b0c8686130d35355ca712e8817dc64181a26be27fc62daae37bef82
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d2974da42b0c sample-nodejs:v0.10.32 "/bin/bash" 4 minutes ago Up 4 minutes sample-container
Dockerfile には nodejs と ruby のインストール、そしてフロントエンド開発でよく使う、gulp、grunt、webpack、bower、compass などのモジュールをインストールしたので、コンテナにログインして確認してみる。
$ docker attach sample-container
[ root@d2974da42b0c:/data ]$ node -v
v0.10.32
[ root@d2974da42b0c:/data ]$ npm -v
2.1.18
[ root@d2974da42b0c:/data ]$ gulp -v
[17:14:55] CLI version 3.8.10
[ root@d2974da42b0c:/data ]$ grunt -v
grunt-cli: The grunt command line interface. (v0.1.13)
[ root@d2974da42b0c:/data ]$ bower -v
1.3.12
[ root@d2974da42b0c:/data ]$ webpack -v
webpack 1.4.15
[ root@d2974da42b0c:/data ]$ ruby -v
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux]
[ root@d2974da42b0c:/data ]$ compass -v
Compass 1.0.1 (Polaris)
この操作による副作用
- 作成したイメージをもとに新規にコンテナが作られる
今回はイメージを作ってみたけど、実際に開発するときは Dockerhub においてある dockerfile/nodejs や dockerfile/nodejs-bower-gulp なんかを pull して使うと良さそう。
fig を使ってコンテナを管理する
イメージの作成ができ、コンテナの作成も慣れてきたところでお次は fig を使ってみる。 fig は複数のコンテナの構成を管理する目的で使うみたい。
fig をインストールする
$ brew install fig
$ fig --version
fig 1.0.1
この操作による副作用
- fig コマンドが使えるようになる
まずはチュートリアル
まずは公式チュートリアルを試してみる。Radis を使った超簡易な Flask アプリのデモがあるのでそのまま写経。 フォルダ構成は以下。
└── figtest
├── Dockerfile
├── fig.yml
├── app.py
└── requirements.txt
Dockerfile
python 環境のコンテナを用意し、必要な pip をインストールする。
FROM orchardup/python:2.7
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
fig.yml
web と redis の 2 つのコンテナを起動させる。 web では 5000 番ポートを開け、redis コンテナとリンクさせるみたい。
web:
build: .
command: python app.py
ports:
- "5000:5000"
volumes:
- .:/code
links:
- redis
redis:
image: orchardup/redis
app.py
/ の URL に GET メソッドでアクセスすると redis に 1 ずつインクリされ、現在のカウントを含む文字列を body に返す web API。
from flask import Flask
from redis import Redis
import os
app = Flask(__name__)
redis = Redis(host="redis_1", port=6379)
@app.route('/')
def hello():
redis.incr('hits')
return 'Hello World! I have been seen %s times.' % redis.get('hits')
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
requirements.txt
この Flask アプリに必要な pip モジュール。
flask
redis
これらのファイルのあるディレクトリで、コンテナを起動させ、Flask アプリと Redis を起動させる。 コマンドは $ fig up のみ。オプションに -d をつけることでデーモン化する。
$ fig up -d
Recreating figtest_redis_1...
Recreating figtest_web_1...
イメージが作成されているか確認。
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
figtest_web latest ba03d2cfe7e1 13 minutes ago 519.7 MB
orchardup/redis latest adf31ad75e8a 5 months ago 180.1 MB
orchardup/python 2.7 cdc18ed4ed6f 7 months ago 514.3 MB
コンテナが起動したか確認。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
76d813354959 figtest_web:latest "python app.py" About a minute ago Exited (0) 59 seconds ago figtest_web_1
7fdd74decd6f orchardup/redis:latest "/usr/local/bin/run" About a minute ago Exited (0) 59 seconds ago figtest_redis_1
1cb36b68a34d orchardup/redis:latest "/bin/echo" About an hour ago Exited (0) About an hour ago elated_darwin
アプリが起動しているか確認。
$ fig ps
Name Command State Ports
---------------------------------------------------------------------
figtest_redis_1 /usr/local/bin/run Up 6379/tcp
figtest_web_1 python app.py Up 0.0.0.0:5000->5000/tcp
コンテナ内の 5000 番ポートで Flask アプリを起動させ、これがローカルの 5000 番ポートに対応しているようだ。 このコンテナの IP を調べて Curl して動作確認する。
$ boot2docker ip
192.168.59.103
IP まわりの詳しい設定やしくみはよくわかっていない。 ひとまず Curl で GET する。
$ curl http://192.168.59.103:5000 -D -
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 38
Server: Werkzeug/0.9.6 Python/2.7.6
Date: Tue, 06 Jan 2015 08:11:40 GMT
Hello World! I have been seen 1 times.%
ここまでで、fig を使って flask アプリ用のコンテナと redis コンテナを起動させアプリが動作することを確認した。
この操作による副作用
- 新たにイメージ、コンテナが作成される。
- コンテナの IP と指定のポート番号を使って、コンテナに HTTP 通信でアクセスできる。
フロントエンド開発環境を fig で管理する
設定ファイルを追加
やっとでここまで来た。手持ちのフロントエンド開発用リポジトリを fig で管理してみる。 作業は既存のリポジトリに、Dockerfile と fig.yml を加えて設定を書くだけで済むみたい。
ディレクトリ構成 (後ろに * がついたものはフォルダ)
$ tree -L 3 .
.
├── Dockerfile
├── Gemfile
├── README.md
├── bower.json
├── fig.yml
├── gulpfile.coffee
├── media
│ └── img*
├── package.json
├── src
│ ├── coffee
│ │ └── index.coffee
│ ├── jade
│ │ ├── index.jade
└── │ └── layout**
└── sass
├── config.rb
├── index.sass
└── lib**
依存モジュール
- gulp: 全タスク管理
- browserify: bower と JS モジュール管理
- coffee-script: AltJS
- jade: AltHTML
- compass + sass: AltCSS
- $ npm start でサーバ起動 + ファイル監視コンパイルタスクが始まる
ずっと昔に作った my-gulp-template を使って試すことにした。
Dockerfile
Dockerfile には環境構築のタスクを書いていく。イメージは公式にあった dockerfile/nodejs-bower-gulp を使う。
# Pull base image.
FROM dockerfile/nodejs-bower-gulp
# Install Ruby
RUN \
apt-get update && \
apt-get install -y ruby ruby-dev ruby-bundler && \
rm -rf /var/lib/apt/lists/*
# Create source dir
RUN mkdir /home/project
# Install
RUN gem install bundler compass
RUN npm install -g coffee-script
# Define working directory.
WORKDIR /home/project
# set up
ADD package.json /home/project/package.json
RUN npm install
ADD bower.json /home/project/bower.json
RUN bower install --config.interactive=false --allow-root
ADD Gemfile /home/project/Gemfile
RUN bundle install
ADD . /home/project
# Expose ports.
EXPOSE 8765
EXPOSE 35729
fig.yml
web:
build: .
command: npm start
volumes:
- "./src:/home/project/src"
ports:
- "8765:8765"
- "35729:35729"
この操作による副作用
- 無し
環境構築し、fig を起動する
コンテナを作成し環境構築する
以下のコマンドで Dockerfile の RUN タスクまでを完了させる。
$ fig build
Building web...
---> 38e49058fd98
Step 1 : RUN apt-get update && apt-get install -y ruby ruby-dev ruby-bundler && rm -rf /var/lib/apt/lists/*
---> Using cache
---> 2c927ade5af7
Step 2 : RUN mkdir /home/project
---> Using cache
---> f5bb325d867c
Step 3 : RUN gem install bundler compass
---> Using cache
---> ec10c5c101a7
Step 4 : RUN npm install -g coffee-script
---> Using cache
---> 5ac28713296e
Step 5 : WORKDIR /home/project
---> Using cache
---> a81a6754a622
Step 6 : ADD package.json /home/project/package.json
---> Using cache
---> cca41d3614d1
Step 7 : RUN npm install
---> Using cache
---> 415eb854198c
Step 8 : ADD bower.json /home/project/bower.json
---> Using cache
---> ee5bf7c1c077
Step 9 : RUN bower install --config.interactive=false --allow-root
---> Using cache
---> 7a01cf07e813
Step 10 : ADD Gemfile /home/project/Gemfile
---> Using cache
---> db438a312fd6
Step 11 : RUN bundle install # --path vendor/bundle --no-root
---> Using cache
---> 40299e5d1c7c
Step 12 : ADD . /home/project
---> 133f0a7e1f4f
Removing intermediate container 10fbde86e007
Step 13 : EXPOSE 8765
---> Running in 9b8b9b29ed67
---> b7ff885c89ef
Removing intermediate container 9b8b9b29ed67
Step 14 : EXPOSE 35729
---> Running in 9aa22049aef9
---> 50f7c8b3fcaa
Removing intermediate container 9aa22049aef9
Successfully built 50f7c8b3fcaa
タスクランナー開始
以下のコマンドで Dockerfile の環境構築が完了していたら fig.yml の command オプションを走らせる。
$ fig up
Recreating mygulptemplate_web_1...
Attaching to mygulptemplate_web_1
web_1 |
web_1 | > my-gulp-template@0.0.0 start /home/project
web_1 | > gulp --gulpfile gulpfile.coffee --require coffee-script
web_1 |
web_1 | [01:33:18] Requiring external module coffee-script
web_1 | [01:33:18] Requiring external module coffee-script/register
web_1 | [01:33:22] Using gulpfile /home/project/gulpfile.coffee
web_1 | [01:33:22] Starting 'default'...
web_1 | [01:33:22] Starting 'preBuild'...
web_1 | [01:33:22] Starting 'clean'...
web_1 | [01:33:22] Finished 'clean' after 23 ms
web_1 | [01:33:22] Starting 'copyMedia'...
web_1 | [01:33:22] Finished 'copyMedia' after 3.99 ms
web_1 | [01:33:22] Starting 'compass'...
web_1 | [01:33:22] Individual stylesheets must be in the sass directory.
web_1 |
web_1 | [01:33:22] Compass Error: { [Error: Compass failed]
web_1 | plugin: 'gulp-compass',
web_1 | showStack: false,
web_1 | message: 'Compass failed' }
web_1 | [01:33:22] Finished 'compass' after 526 ms
web_1 | [01:33:22] Starting 'jade'...
web_1 | [01:33:22] Starting 'browserify'...
web_1 | [01:33:22] Finished 'browserify' after 12 ms
web_1 | [01:33:22] Finished 'jade' after 167 ms
web_1 | [01:33:22] Finished 'preBuild' after 724 ms
web_1 | [01:33:22] Starting 'watchify'...
web_1 | [01:33:22] 'index.coffee' has changed.
web_1 | [01:33:22] Finished 'watchify' after 7.72 ms
web_1 | [01:33:22] Starting 'watch'...
web_1 | [01:33:22] Finished 'watch' after 56 ms
web_1 | [01:33:22] Starting 'connect'...
web_1 | [01:33:22] Server started http://localhost:8765
web_1 | [01:33:22] LiveReload started on port 35729
web_1 | [01:33:22] Finished 'connect' after 70 ms
web_1 | [01:33:22] Finished 'default' after 862 ms
- TODO:
- Compass のタスクが失敗しているのであとで直そう。半年以上前に書いた化石 Gulpfile なので、後でリファクタもする。
ひとまず $ boot2docker ip で IP を取得し、ブラウザで http://<CONTAINER_IP>:8765/ を開くと、、、サーバが起動してコンパイルされたファイルが取得できる(^^) (Compass 調子悪いが) Jade ファイルと Coffee ファイルを更新すると、コンパイルできている(^^)
しかも、ローカルのディレクトリにはインストールしたはずの node_modules や bower_components フォルダは存在しない。 これらはコンテナ上でインストールされる。ソースファイルは、yml にマウントするパスを書いておくことでコンテナと共有(同期)することができるっぽい。
この操作による副作用
- 新たにイメージを作成し、コンテナを起動する
- コンテナは Dockerfile や fig.yml によって構成が管理されている
おまけ: DockerHub に登録
ついでなので、自分で作ったイメージを DockerHub に登録してみた。
webpack のイメージ。流行っているのかイマイチ分からないけど、プライベートで最近触り始めた:P
Docker を使った私見
あくまでフロントエンド開発目線。
- Docker + fig が便利そうなのは掴めた。
- Docker クライアントと fig さえ入っていたら、$ fig up だけでローカルの環境を一切汚さずに、専用の環境構築を全てやってくれるのは魅力。
- フロントエンド開発環境が Docker で楽ちんになるかは微妙。
- ローカルで問題なく環境構築できるなら Docker を無理に使うことはなさそう。
- Docker の学習コストをかけてまで導入するコストをかけるより、フロントエンドの技術を習得したほうがよさそう(← わたしのことです)。
- ものすごい特殊な環境(レガシーすぎるバージョンの環境)や大人数での開発で環境構築の設定にコストがかかりすぎると判断したときは、考えても良いかもしれない。
- ここまで書いておいてなんだけど、やっぱり Docker の真の力はサーバアプリケーション含め複数のアプリケーションやクラスタ環境を管理するときだろうなぁ。
- Vagrand + Chef よく分かっていなかったり、競合ツールとのは比較できない。
- Mac の容量を食うので、イメージの容量を気にし始めたほうがよさそう。そしてこまめに使わないコンテナやイメージは削除する。
目的と用途によっては選択肢のひとつになりえそう。なーんて、月並みな感想で閉めることになってしまったけど、個人的には結構気に入った。とっかかりはフロントエンド開発で使えるかなって思いつきから触りだした Docker だったけど、フロントエンドに縛られずプライベートでは使っていこうかなと思う(・・)