Sane Stackの動作を理解するために、前回はEmber CLIだけのDocker Composeを作成しました。今度はSails.jsだけ使ったDocker Composeを用意して簡単なアプリを作成してみます。
プロジェクト
最初に適当なディレクトリを作成します。server
ディレクトリはsails new
コマンドを使い、空のカレントディレクトリにプロジェクトを作成するために用意しておきます。
$ cd ~/node_apps/sails-spike
$ mkdir -p server pm2/log
最終的に次のようなディレクトリ構成になります。
$ cd ~/node_apps/sails-spike
$ tree -L 2
.
├── Dockerfile
├── docker-compose.yml
├── package.json
├── pm2
│ ├── config
│ └── log
└── server
├── Gruntfile.js
├── README.md
├── api
├── app.js
├── assets
├── config
├── node_modules
├── package.json
├── tasks
└── views
DockerとDocker Compose
Dockerfileは0.12/onbuildをベースイメージに使います。コンテナ内でsailsコマンドを実行するため、作業ユーザーと同じUIDでユーザーを作成します。マウントしたDockerホストのディレクトリ内でファイルを編集できるようにします。
ENTRYPOINTにsailsコマンドを指定して、CMDはhelpにしています。コンテナをrunしたとき引数を渡さないとsails help
が実行されます。docker-compose
コマンドの引数にはsails
サービスに続けてsails
サブコマンドを指定します。
FROM node:0.12-onbuild
MAINTAINER Masato Shimizu <ma6ato@gmail.com>
RUN npm install -g sails grunt bower pm2 npm-check-updates
RUN adduser --disabled-password --gecos '' --uid 1000 docker && \
adduser docker sudo && \
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \
mkdir -p /app && \
chown docker:docker /app
USER docker
WORKDIR /app
EXPOSE 1337
ENTRYPOINT ["/usr/local/bin/sails"]
CMD ["help"]
docker-compose.ymlはYAMLのマージを利用しています。&defaults
にしているsails
サービスのイメージは事前にローカルにビルドしておきます。
$ cd ~/node_apps/sails-spike/
$ docker build -t sails .
server
サービスではPM2を使ってSailsアプリを起動します。Dockerなので--no-daemon
フラグを付けてフォアグラウンドで実行します。
sails: &defaults
image: sails
volumes:
- $PWD/server:/app
- $PWD/pm2:/opt/pm2
server:
<<: *defaults
entrypoint: ["pm2","--no-daemon","start","/opt/pm2/config/development.json"]
ports:
- 1337:1337
npm:
<<: *defaults
entrypoint: ['/usr/local/bin/npm']
bower:
<<: *defaults
entrypoint: ['/usr/local/bin/bower', '--allow-root']
ベースイメージのONBUILDで実行されるpackage.json
です。sailsをインストールします。
{
"name": "sails-spike",
"description": "sails spike project.",
"version": "0.0.1",
"dependencies": {
"sails": "0.11.0"
},
"scripts": {"start": "node app.js"}
}
PM2
Sailsプロセスの管理はPM2を使います。JSONの設定ファイルを用意します。watch
に監視したいディレクトリを指定するとファイルの更新時に自動的にアプリを再起動してくれます。
{
"apps": [{
"name" : "sails-app",
"cwd" : "/app",
"script" : "app.js",
"watch" : ["api", "config"],
"out_file" : "/opt/pm2/log/sails-app.stdout.log",
"error_file": "/opt/pm2/log/sails-app.stderr.log",
"env": {
"NODE_ENV": "development",
"PORT" : 1337
}
}]
}
sailsコマンド
sailsコマンドをDockerコンテナ内で実行します。最初にSailsのバージョンを確認します。--rm
フラグを付けてコマンド実行後にコンテナが破棄されるようにします。
$ docker-compose run --rm sails --version
0.11.0
Removing sailsspike_sails_run_1...
同様にdocker-composeに定義したnpm
サービスを使ってnpmコマンドのバージョンを確認します。
$ docker-compose run --rm npm --version
2.8.4
Removing sailsspike_npm_run_1...
ちょっとわかりづらいですが、--entrypoint
フラグを上書きして任意のコマンドも実行できます。結果的にはYAMLでマージしたnpm
サービスと同じ動作になります。
$ docker-compose run --rm --entrypoint="/usr/local/bin/node" sails --version
v0.12.2
Removing sailsspike_sails_run_4...
server
ディレクトリはコンテナの/app
ディレクトリにマウントしています。ここにsails new
コマンドでアプリを作成します。
$ docker-compose run --rm sails new
info: Created a new Sails app `app`!
Removing sailsspike_sails_run_1...
server
サービスをupします。
$ docker-compose up server
ブラウザから確認します。
APIの作成
sails generate api
コマンドからコントローラーとモデルを生成します。
$ docker-compose run --rm sails generate api user
info: Created a new api!
Removing sailsspike_sails_run_1...
genarate api
ではモデルのattributesを渡せません。生成されたUser.jsモデルを編集してattributesを追加します。
module.exports = {
attributes: {
name: 'string',
age: 'integer'
}
};
初回起動時にExcuse my interruption
とデータベースのマイグレーションをどうするかダイアログが表示されます。sails lift
している場合はconfig/models.js
の設定が入りますが、foreverやpm2で起動していると編集されません。
Q&A: Sails.js won’t run through forever.js
手動でアンコメントします。
module.exports.models = {
connection: 'localDiskDb',
migrate: 'alter'
};
pm2がファイルの編集を検知してアプリを再起動してくれます。
Change detected for app name: sails-app - restarting
REST API
curlコマンドからJSON形式でPOSTしてレコードを作成します。HTTPヘッダにcontent-typeを指定します。
$ curl -X POST \
http://10.3.0.165:1337/user \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name":"pochi","age": 3 }'
{
"name": "pochi",
"age": 3,
"createdAt": "2015-04-30T12:30:03.135Z",
"updatedAt": "2015-04-30T12:30:03.135Z",
"id": 1
}
同様にcurlから登録したレコードをGETします。
$ curl -X GET \
http://10.3.0.165:1337/user/1
{
"name": "pochi",
"age": 3,
"createdAt": "2015-04-30T12:30:03.135Z",
"updatedAt": "2015-04-30T12:30:03.135Z",
"id": 1
}