Block Rockin’ Codes

back with another one of those block rockin' codes

dotCloud で WebSocket

dotCloud が WebSocket に対応したという発表がありました。

dotCloud Announces Native Support for WebSockets | dotCloud Blog

dotCloud は多くの言語やミドルウエアに対応していて、 CLI からアプリがデプロイできる PaaS サービスといった感じです。
(Heroku なんかをイメージしてもらうとわかりやすいかも。)

早速、 Node.js + Socket.IO でどんなもんか試してみました。
アカウントは自分は結構前にとったんですが、今ならすぐ取得できるっぽいです。

CLI のインストール

専用の CLI があるのでそれをインストールするところから始めます。
http://docs.dotcloud.com/firststeps/install/ にある通り、 Python の pip で入れます。

Jxck$ sudo easy_install pip && sudo pip install dotcloud

インストールしたら、 dotcloud コマンドが使えるようになります。

最初に dotcloud コマンドを実行したら、 API key とやらを聞かれるので入力します。
API key は、メッセージの通り http://www.dotcloud.com/accounts/settings で確認できます。

Jxck$ dotcloud
Warning: .dotcloud/dotcloud.conf does not exist.
Enter your api key (You can find it at http://www.dotcloud.com/accounts/settings): xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
error: usage: dotcloud [-h]
                
                {info,status,scale,run,logs,versions,url,setup,list,stats,var,restart,alias,rollback,push,destroy,create,ssh,history}
                ...

エラってね?(汗


うーん、とりあえず -h したら、 steup がそれっぽいので、もう一度やってみる。

Jxck$ dotcloud setup
Enter your api key (You can find it at http://www.dotcloud.com/accounts/settings): xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

できたっぽい。 ~/.dotcloud/dotcloud.conf を見てみる。

Jxck$ cat .dotcloud/dotcloud.conf
{
    "url": "https://api.dotcloud.com/",
    "apikey": "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

こんなのができてる。

アプリ作成

dotCloud アプリを作成してデプロイします。
ここでは Node を使います。 Node を使ったアプリについては、

dotCloud - Node.js Service が参考になります。


まずは create コマンド。

Jxck$ dotcloud create wstest

(これは、ローカルに何かファイルを作ったりではないみたい)


好きなディレクトリを作って、 build file を作ります。名前は dotcloud.yml

Jxck$ mkdir dotcloud
Jxck$ cd dotcloud

dotcloud.yml はこんな感じ

www:
  type: nodejs
  approot: wstest

approot に実際にアプリがあるディレクトリを書きます。
ディレクトリ内には、実際のアプリと package.json, supervisord.conf などを配置します。
だからこの場合、こういう構成になります。

Jxck$ tree dotcloud
dotcloud
├── dotcloud.yml
└── wssample
    ├── package.json
    ├── server.js
    └── supervisor.conf

1 directory, 4 files


とりあえず普通の http サーバを作って動かしてみます。


サーバは server.js に実装します。しかし dotCloud ではエントリファイルは supervisor.conf で指定するため、
server.js である必要はないんですが、まあ慣習です。

また、 http サーバをデプロイする場合は、必ず 8080 ポートをリッスンする必要があるそうです。
(もちろん外からは 80 でアクセスできるので、リバース Proxy があるんでしょう)

server.js
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(8080);
supervisor.conf

ここで、実装したサーバの起動方法を指定します。
npm start に対応してないのがちょっと残念ですが、
同じ方法で別の言語も動くのでまあ、しょうがないですね。
ここで指定するから、エントリファイルは server.js でなくても実際は大丈夫です。

[program:node]
command = node server.js
directory = /home/dotcloud/current

デプロイ

dotcloud コマンドでできます。
見た感じ rsync で飛ばしてるみたいですね。

$ dotcloud push wstest dotcloud/

.....

Deployment finished. Your application is available at the following URLs
www: http://wstest-jxck.dotcloud.com/

コマンドラインに出力されたアドレスでアクセスできます。


WebSocket

ではいよいよ、 WebSocket を使って試してみます。
ここでは Socket.IO を用いて、使用する通信を WebSocket のみにするため、
transport オプションに ['websocket'] を指定します。


静的ファイルの配信は express を用いました。(この程度なら express でも十分だった。)

package.json

依存するパッケージは package.json に書いておけば、デプロイ後に入れてくれます。

最初に npm init でプロジェクトを作り始めるとはかどります。

{
  "author": "Jxck",
  "name": "wssample",
  "version": "0.0.0",
  "repository": {
    "url": ""
  },
  "engines": {
    "node": "*"
  },
  "dependencies": {
    "express": "*",
    "socket.io": "*"
  },
  "devDependencies": {}
}
サーバ

サーバはこんな感じ。
ポイントは io.set() で、 transport を指定しています。
これで socket.io は websocket の接続確立に失敗してもフォールバックをしません。

var express = require('express')
  , io = require('socket.io')
  ;

var app = module.exports = express.createServer();

app.configure(function(){
  app.use(express.static(__dirname + '/public'));
});

io = io.listen(app);
io.configure('production', function() {
  io.set('transports', ['websocket']);
});

io.sockets.on('connection', function (socket) {
  console.log('connected');
  socket.on('msg send', function (msg) {
    socket.emit('msg push', msg);
    socket.broadcast.emit('msg push', msg);
  });
  socket.on('disconnect', function() {
    console.log('disconnected');
  });
});

app.listen(8080);
クライアント

現在どの通信方法で接続を確立しているかは、

以下の場合、 socket.socket.transport の中を見るとわかります。

var socket = io.connect();

socket.on('connect', function() {
  console.log('connected');
  console.log('transport is', socket.socket.transport);
  socket.emit('msg send', 'data');
  socket.on('msg push', function (msg) {
    console.log(msg);
  });
});

まとめ

今回のサンプルは以下にデプロイしています。

http://wstest-jxck.dotcloud.com/


ソースは以下。

https://github.com/Jxck/dotcloud_ws_test


実行結果は以下。

WebSocket で接続できていることが確認できます。


ということで、公表されたとおり WebSocket が通っているようですね。
WebSocket が使えない PaaS (heroku とか) はまだまだ多いので、
これはひとつ大きなアドバンテージになるかもしれません。


気になるところは

  • 速度
    • どのくらいでるのか。これはサーバとの物理的距離も関係。
  • 何使ってるの?
    • おそらく dotCloud のサーバ群には Proxy などがフロントに立っているんだろうと予想できるが、何を使っているのか。
    • ちなみにここに Nginx を使っている場合は、デフォルトだとできない、のでパッチなどが必要。(だから heroku は ws できないとされてる)


この辺も余裕があったら調べてみたいところですね。

あ、今更だけど、これはエイプリルネタじゃないです(汗
この記事、本当は 3 月中に書きたかった。。(月 1 でブログが目標)