前回のエントリーDotCloudが素晴らしいに引き続きDotCloudで遊びます。
今回はDotCloudの「プログラミング言語やミドルウェアを自由に選べる」という特徴を活かしていろんな組み合わせを試してみたいと思います。
* メニュー
PHP + MySQL
Ruby + Redis (Sinatraを利用)
Python + MongoDB (Flaskを利用)
PHP + MySQL
この組み合わせでのシステム開発はなんだかんだ言って仕事で慣れている方も多いのではと思います。もちろんDotCloudでもPHP + MySQLの環境をサポートしています。アプリケーションのデプロイまでの簡単なフローは前回のエントリーに書いたのでそちらを参照してください。
* 環境
PHP 5.3.2
MySQL 5.1.41
1 2 3 4 |
$ mkdir phpmysql $ cd phpmysql $ dotcloud create phpmysql Created application "phpmysql" |
* dotcloud.yml
1 2 3 4 |
www: type: php data: type: mysql |
ここまでで一度pushして、MySQLの各種情報を確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ dotcloud push phpmysql ## dotcloud.ymlを書いてpush $ dotcloud info phpmysql.data ## MySQLの情報を確認 cluster: wolverine config: mysql_password: {ここにパスワードが表示される} created_at: 1312032855.118799 ports: - name: ssh url: ssh://mysql@89e51352.dotcloud.com:12096 - name: mysql url: mysql://root:TCU3JM8kQripzTg9OG75@89e51352.dotcloud.com:12097 state: running type: mysql |
ウルヴァリンだって。サイクロップスとかローグって名前のクラスタもあるんでしょうか。
次にMySQLに接続します。普通にシェルから操作できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$ dotcloud run phpmysql.data -- mysql -uroot -p # mysql -uroot -p Enter password: {パスワードを入力} Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 34 Server version: 5.1.41-3ubuntu12.10-log (Ubuntu) Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | +--------------------+ 2 rows in set (0.00 sec) mysql> create database testdb; Query OK, 1 row affected (0.00 sec) |
testdb という名前でデータベースを1つ作りました。
次はPHPからアクセスしてみます。MySQLへの接続に必要なデータはホームディレクトリの environment.json というファイルに記述されているのでそこから取ってきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?php try { // environment.json ファイルから接続に必要な情報を取得 $filepath = $_SERVER['HOME'].'/environment.json'; $env = json_decode(file_get_contents($filepath), true); // "DOTCLOUD_DATA_MYSQL_xxx" というキーでMySQL関連のデータが入っている $host = $env['DOTCLOUD_DATA_MYSQL_HOST']; $port = $env['DOTCLOUD_DATA_MYSQL_PORT']; $dbname = 'testdb'; $dsn = 'mysql:host='.$host.';port='.$port.';dbname='.$dbname; $user = $env['DOTCLOUD_DATA_MYSQL_LOGIN']; $pass = $env['DOTCLOUD_DATA_MYSQL_PASSWORD']; $dbh = new PDO($dsn, $user, $pass); // ここでは PDO を利用 $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $sql = 'SELECT NOW()'; // 日付,時刻を取得 $stmt = $dbh->prepare($sql); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); echo 'NOW(): ',$row['NOW()']; $dbh = null; }catch(PDOException $e) { echo $e->getMessage(); } ?> |
1 |
$ dotcloud push phpmysql ## アプリケーションのデプロイ |
後はエントリーポイントにアクセスして日付と時刻が表示されたら成功です。PHPを書いたのは半年ぶりくらいですがここまで10分かかりませんでした。とても簡単。今回はPDOを使いましたが、もちろんmysqliも使えます。
Ruby + Redis
この組み合わせに特に意味はないです。なんとなく字面が良かったので、。Redisは最近注目され始めているNoSQLデータベースの1つで、githubやdigg、stackoverflowなど大規模サービスのバックエンドでも利用されています。Redisは文字列型の他にリストやセット、ハッシュなどの様々な型があり、それぞれの型に対するコマンドがatomicに動作するという良い特徴を持っています。また、Tokyo Cabinet/Tokyo Tyrantのようにデータの永続化やレプリケーションも可能です。Redisについては別エントリーのインメモリKVSのRedisについてで少し詳しく調べているのでもし興味があればそちらを参照してください。Ruby + Redisでの開発フローもPHP + MySQLの例とほとんど同じです。ここではWebアプリケーションフレームワークのSinatraも利用します。
* 環境
Ruby 1.9.2 (Rack 1.3.2)
Redis 2.2.2
Sinatra 1.2.6
1 2 3 4 |
$ mkdir rubyredis $ cd rubyredis $ dotcloud create rubyredis Created application "rubyredis" |
* dotcloud.yml
1 2 3 4 |
www: type: ruby data: type: redis |
ここまでで一度pushして、Redisの各種情報を確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ dotcloud push rubyredis ## dotcloud.ymlを書いてpush $ dotcloud info rubyredis.data ## Redisの情報を確認 cluster: wolverine config: redis_password: {ここにパスワードが表示される} created_at: 1312036663.3893609 ports: - name: ssh url: ssh://redis@6c235a17.dotcloud.com:11761 - name: redis url: redis://redis:i5b8tq7d4UiG1cvlyQ9j@6c235a17.dotcloud.com:12096 state: running type: redis $ dotcloud run rubyredis.data redis-cli ## シェルからRedisの接続確認 # redis-cli redis> auth {ここにパスワードを入力} OK redis> rpush message 'hello' ## 簡単な操作確認 (integer) 1 redis> rpush message 'world' (integer) 2 redis> lrange message 0 -1 1) "'hello'" 2) "'world'" redis> |
ここまでは特に問題はないかと。次にRuby(Rack)アプリケーションからRedisにアクセスしてみます。接続に必要な情報はMySQLの時と同様に environment.json ファイルから取ってきます。また、Rubyのバージョンは特に指定をしなければ1.9.2になるようなので $LOAD_PATH 等の細かい所に注意してください。
* Gemfile
1 2 3 4 5 |
source :rubygems require 'json' require 'rack' require 'redis' require 'sinatra' |
* config.ru
1 2 3 |
$:.unshift File.dirname(__FILE__) require 'redistest' run Sinatra::Application |
* redistest.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
require 'rubygems' require 'json' require 'redis' require 'sinatra' ## 汚い書き方ですが接続テストということで;; get '/' do filepath = '/home/dotcloud/environment.json' env = JSON.parse(File.open(filepath).read) host = env['DOTCLOUD_DATA_REDIS_HOST'] port = env['DOTCLOUD_DATA_REDIS_PORT'] pass = env['DOTCLOUD_DATA_REDIS_PASSWORD'] redis = Redis.new(:host => host, :port => port, :password => pass) redis.rpush(:data, 'redis') ## リストの末尾(右)からpush redis.lpush(:data, 'hello, ') ## リストの先頭(左)からpush p redis.lrange(:data, 0, -1) ## リストの先頭から末尾までの値を取得 end |
1 |
$ dotcloud push rubyredis |
エントリーポイントにアクセスして hello, redis と表示されたら成功です。やはり簡単。Rubyのバージョンに関しては、dotcloud.ymlで指定すれば1.8.x系も使えます。
1 2 3 4 |
www: type: ruby config: ruby-version: ree ## Ruby Enterprise Edition (1.8.x系) |
HerokuもアドオンでRedisは使えるようですが、FREEプランだと「容量5MB, 1データベース, 永続化なし, レプリケーションなし」になっています。DotCloudではどれくらい使えるのかがドキュメントには書いていませんが、もし容量5MBだったらつらいなぁという感じです。アプリケーションのデプロイまでのステップはDotCloudの方が若干少ないので楽だと思います。Redisはalphaではなく既にbetaコンポーネントとして提供されているのでドキュメントもこれから充実してくるはず。
Python + MongoDB
この組み合わせは最近よく見かけるようになってきました。自然言語処理(NLP)屋さんがPythonを好むのはまぁわかるのですが、MongoDBも好きな人が多いのは何か理由があるんですかね。やっぱりドキュメント(文書)としてデータを扱うからでしょうか。とにかくNLPな人達はLLにもミドルウェアにも強くなれて羨ましい限り。一方、画像処理(CV/IM)な世界はPythonを広めるのに必要な土台は十分なのに、NLPな世界と比べるとあまり流行ってない上にデータストアに詳しい人も少ない気がします。CVな人達は動画像ファイルのような巨大データの”管理”ってどうやってるんでしょう、。
すみません、愚痴で話しがそれました。NLPな人達がときどき羨ましくなります(´・ω・`)
Python + MongoDBでの開発フローもこれまでの例と同じで特筆することはありません。ここではWebアプリケーションフレームワークのFlaskも利用します。
* 環境
Python 2.6.5
MongoDB 1.8.2
Flask 0.7.2
1 2 3 4 |
$ mkdir pythonmongo $ cd pythonmongo $ dotcloud create pythonmongo Created application "pythonmongo" |
* dotcloud.yml
1 2 3 4 |
www: type: python data: type: mongodb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
$ dotcloud push pythonmongo ## dotcloud.ymlを書いてpush $ dotcloud info pythonmongo.data ## MongoDBの情報を確認 cluster: wolverine config: mongodb_password: {ここにパスワードが表示される} created_at: 1312085176.141191 ports: - name: ssh url: ssh://mongodb@8107c568.dotcloud.com:11761 - name: mongodb url: mongodb://root:EFe0oQokRCeWh6q6Cpbc@8107c568.dotcloud.com:12096 state: running type: mongodb $ dotcloud run pythonmongo.data mongo ## シェルからMongoDBの接続確認 # mongo MongoDB shell version: 1.8.2 connecting to: test > use admin switched to db admin > db.auth("root", "{パスワードを入力}"); 1 > use test switched to db test > db.messages.save({"message":"hello, "}) ## データを入れておく > db.messages.save({"message":"mongodb"}) > db.messages.find() { "_id" : ObjectId("4e350736e720613220dcc5f2"), "message" : "hello, " } { "_id" : ObjectId("4e35073de720613220dcc5f3"), "message" : "mongodb" } > quit() |
次にPython(WSGI)アプリケーションからMongoDBにアクセスします。普通の構成でファイル作ってpushするだけ。
* requirements.txt (RackアプリでいうGemfileのようなもの)
1 2 |
Flask==0.7.2 pymongo==1.11 |
* wsgi.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import json from flask import Flask, g from pymongo import Connection application = Flask(__name__) app = application @app.before_request def before_request(): filepath = '/home/dotcloud/environment.json' f = open(filepath) env = json.load(f) f.close() conn = Connection(env['DOTCLOUD_DATA_MONGODB_HOST'], int(env['DOTCLOUD_DATA_MONGODB_PORT'])) conn.admin.authenticate(env['DOTCLOUD_DATA_MONGODB_LOGIN'], env['DOTCLOUD_DATA_MONGODB_PASSWORD']) g.db = conn @app.teardown_request def teardown_request(exception): g.db.disconnect() @app.route('/') def hello(): message = '' for item in g.db.test.messages.find(): message += item['message'] + "\n" return message if __name__ == '__main__': app.run() |
1 |
$ dotcloud push pythonmongo |
エントリーポイントにアクセスして hello, mongodb と表示されたら成功です。
今回はPerlでの利用例は省略しますが、普通にPSGIアプリケーションを作って、使いたいCPANモジュールを Makefile.PL に書いてpushするだけで動きました。特に難しいところはないかと思います。
DotCloudでWebアプリケーションを開発する手順を整理すると以下のようになります。
2. dotcloud.yml を書く
4. dotcloud push をしてから dotcloud info でミドルウェアの情報を確認する
5. シェルから接続確認
6. アプリケーションから接続確認 (environment.jsonから情報を取得)
また、SSHでDotCloudのサーバに接続するのは簡単です。
1 2 3 4 5 6 |
アプリケーション名は pythonmongo とする $ dotcloud ssh pythonmongo.www # $SHELL dotcloud@pythonmongo-default-www-0:~$ ls -aF ./ .bash_history .bashrc code@ env/ .pip-cache/ revisions/ .ssh/ ../ .bash_logout .cache/ current@ environment.json .profile rsync-1312103158.72/ |
ちなみに、nginxなどのサービス監視はmonitで行っているようです。僕もさくらVPSに入れて使っていますが、設定ファイルの書式が綺麗で書きやすいので好きです。
DotCloudと似たようなPaaSでは日本人の方が作ったfluxflexがありますが、そちらはマウスでぽちぽち作業できるのでポップな感じがしますね(公式サイトの作りも)。当然ながら日本語ドキュメントが整備されているので英語が苦手な人はfluxflexの方が使いやすいかもしれません。現時点でのスペック比較はあまり参考にならない気もするので、公式のPVとか見て好きな方を選んだらいいんじゃないかと思います。僕はDotCloudの音の響きで選んだだけなので、。あと、コンポーネントのロードマップが公式サイトに載ってるので印象は良いです。
僕はインフラ寄りのエンジニアなのでアプリケーション開発には詳しくないのですが、これを機にアプリ側の勉強もしてみようと思います。