「Cloud Foundry 百日行」第4回目は,前回と同様の spreadsheet アプリ “EtherCalc” です。
基本情報
EtherCalc は web spreadsheet で,複数人で同時編集できる点も前回の EtherSheet と同じです。ソースを見た印象としては,PaaS を含めたクラウド環境で動かすことを意識した造りになっているように感じました。
記事の概要は以下の通りです。
- ソースコードの取得
- Redis なしでデプロイ
- Redis なしで動作確認
- Redis ありでデプロイ
- Redis サービスの作成と結合
- ソースコードの修正
- アプリの push
- Redis ありで動作確認
では,始めます。
ソースコードの取得
$ git clone https://github.com/audreyt/ethercalc.git
ethercalc ディレクトリーに入ります。
$ cd ethercalc/
Redis なしでデプロイ
ではまず,このアプリをRedis なしでデプロイしてみます。
本アプリはデータを Redis に格納しますが,Redis がない場合ローカルのディスクにデータを保存するようになっているので,とりあえず試してみたいようなだけであればこちらの方が簡単です。
ただし,Cloud Foundry にデプロイした場合ファイルシステムに永続性がないので,アプリを再起動したりするとデータはすべて消えてしまいます。またアプリを複数インスタンス構成で動作させたい場合は,Redis が必須です。
【アプリのpush】
$ cf push ec
Creating app ec in org nota-ja / space 100 as nota-ja...
......
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: ec.10.244.0.34.xip.io
last uploaded: Tue Jun 9 06:24:46 +0000 2015
stack: lucid64
state since cpu memory disk details
#0 running 2015-06-09 03:25:22 PM 0.0% 133.9M of 256M 0 of 1G
拍子抜けするほど簡単に動きました。
Redis なしで動作確認
初期画面
シートを作成
Create Spreadsheet
をクリックしてシートを作ります。
入力/演算
A1 セルに 123
, A2 セルに 456
, A3 セルに =sum(A1:A2)
を入力してみます。
数字が右寄せになってるのがちょっとポイント高い感じです。
表示の変更
【列幅の拡大】
【フォントの拡大】
他にも機能はあるのですが,多すぎるのでこれくらいにしたいと思います。
ともかく,極めて簡単に動かすことができました。
Redis ありでデプロイ
今度は Redis ありでデプロイしてみます。
Redis サービスの作成と結合
本アプリ用に Redis サービスのインスタンスを作成します。
今回, Redis サービスの提供には, cf-redis-release を利用しました。
cf marketplace
でサービスの一覧を確認します。
$ cf marketplace
Getting services from marketplace in org nota-ja / space 100 as nota-ja...
OK
service plans description
PostgreSQL Basic PostgreSQL Plan* PostgreSQL on shared instance.
p-mysql 100mb-dev, 1gb-dev A MySQL service for application development and testing
p-redis shared-vm, dedicated-vm Redis service to provide a key-value store
......
サービス p-redis
, プラン shared-vm
を指定して,サービス・インスタンスを作成します。サービス・インスタンス名は redis4ec
としました。
$ cf create-service p-redis shared-vm redis4ec
Creating service instance redis4ec in org nota-ja / space 100 as nota-ja...
OK
確認:
$ cf services
Getting services in org nota-ja / space 100 as nota-ja...
OK
name service plan bound apps last operation
my4es p-mysql 100mb-dev es
pg4kandan PostgreSQL Basic PostgreSQL Plan kandan
redis4ec p-redis shared-vm
Redis のサービス・インスタンスが作成できました。
次に,これをアプリと結合します。
$ cf bind-service ec redis4ec
Binding service redis4ec to app ec in org nota-ja / space 100 as nota-ja...
OK
TIP: Use 'cf restage ec' to ensure your env variable changes take effect
確認:
$ cf services
Getting services in org nota-ja / space 100 as nota-ja...
OK
name service plan bound apps last operation
my4es p-mysql 100mb-dev es
pg4kandan PostgreSQL Basic PostgreSQL Plan kandan
redis4ec p-redis shared-vm ec
ソースコードの修正
この状態でステージングをしなおして (cf restage ec
) みたのですが,残念ながら Redis に接続した状態にはなりませんでした。
調査したところ,実はこのアプリは Cloud Foundry を意識した造りになっていた (cf. ソースコード : VCAP_SERVICES
という環境変数から Redis への接続情報を取り出すコードが実装されている) のですが,cf-redis-release の仕様とのわずかな差異によって接続に失敗していたことがわかりました。
最終的な差分は以下の通りです。
$ git diff master
1diff --git a/db.js b/db.js 2index 9a776f4..c13bae5 100644 3--- a/db.js 4+++ b/db.js 5@@ -12,8 +12,8 @@ 6 services = JSON.parse(process.env.VCAP_SERVICES || '{}'); 7 for (name in services) { 8 items = services[name]; 9- if (/^redis/.test(name) && (items != null && items.length)) { 10- ref1$ = [(ref$ = items[0].credentials)['port'], ref$['hostname'], ref$['password']], redisPort = ref1$[ 11+ if (/redis/.test(name) && (items != null && items.length)) { 12+ ref1$ = [(ref$ = items[0].credentials)['port'], ref$['host'], ref$['password']], redisPort = ref1$[0], 13 } 14 } 15 redisHost == null && (redisHost = 'localhost'); 16diff --git a/src/db.ls b/src/db.ls 17index 93aaeed..f4f7aa8 100644 18--- a/src/db.ls 19+++ b/src/db.ls 20@@ -9,8 +9,8 @@ 21 process.env.VCAP_SERVICES or '{}' 22 23 for name, items of services 24- | /^redis/.test name and items?length 25- [redisPort, redisHost, redisPass] = items.0.credentials<[ port hostname password ]> 26+ | /redis/.test name and items?length 27+ [redisPort, redisHost, redisPass] = items.0.credentials<[ port host password ]> 28 29 redisHost ?= \localhost 30 redisPort ?= 6379
修正が2ファイルにわたっているのは,元のソースコードが LiveScript で書かれていて,それをコンパイルした結果の JavaScript ファイルにも(当然)変更が入るためで,実質的に修正したのは src/db.ls
の1ファイルのみです。
アプリの push
アプリをpushして更新します。
$ cf push ec
Updating app ec in org nota-ja / space 100 as nota-ja...
......
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: ec.10.244.0.34.xip.io
last uploaded: Tue Jun 9 07:38:36 +0000 2015
stack: lucid64
state since cpu memory disk details
#0 running 2015-06-09 04:38:52 PM 0.0% 138.8M of 256M 0 of 1G
この時のログ (cf logs ec
で見ることが可能) を見ると,以下のような出力があり,Redis と接続できていることが確認できました。
2015-06-09T16:42:47.13+0900 [App/0] OUT Connected to Redis Server: 10.244.3.46:50638
Redis ありで動作確認
先ほどのシートを確認
アプリの更新時に再起動がかかったため,先ほどのシートにアクセスするとデータはすべて消えてしまっています。
シートの作成と操作
トップ画面から新しくシートを作り,いろいろ操作してみました。
アプリの再起動
ここでアプリを再起動してみます。
$ cf restart ec
再起動中,ブラウザーの画面はこのようになります。
数十秒ほどで再起動が完了しました。
Stopping app ec in org nota-ja / space 100 as nota-ja...
OK
Starting app ec in org nota-ja / space 100 as nota-ja...
0 of 1 instances running, 1 starting
1 of 1 instances running
App started
OK
App ec was started using this command `npm start`
Showing health and status for app ec in org nota-ja / space 100 as nota-ja...
OK
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: ec.10.244.0.34.xip.io
last uploaded: Tue Jun 9 07:42:27 +0000 2015
stack: lucid64
state since cpu memory disk details
#0 running 2015-06-09 04:57:53 PM 0.0% 133M of 256M 0 of 1G
ブラウザー画面はもとの状態に戻っていて,リロードしてもデータは残っています。
以上で一通りの動作確認は終わりです。
今回使用した環境
- cf-release (v194)
https://github.com/cloudfoundry/cf-release/tree/v194
( https://github.com/cloudfoundry/cf-release/tree/345a8b3e1ea0005a3e9fced13f0bf6fa6f7ad981 ) - bosh-lite
https://github.com/cloudfoundry/bosh-lite/tree/01db9da7b4122f7d02858d92e0fe938e91256649 - CF CLI (v6.11.3-cebadc9-2015-05-20T19:00:58+00:00)
https://github.com/cloudfoundry/cli/releases/tag/v6.11.3 - cf-redis-release (記事執筆時点のmaster)
https://github.com/pivotal-cf/cf-redis-release/tree/09c06f35dbdbd7e9d695195ceda0f4381b49e455 - EtherCalc
https://github.com/audreyt/ethercalc/tree/c0f0229512f7826ae93297c47eed54767e66bdc0