オープンソースのPaaSソフトウェア CloudFoundry の技術情報やイベント告知などを掲載します

2015-06-15

drop7 を Cloud Foundry で動かす

本日の第8回「Cloud Foundry 百日行」は、drop7です。
これも簡単な構成のWebアプリゲームです。
内容は相変わらず簡単なHTML+Javascriptですが徐々に追加の内容を盛り込んでいこうと思います。

drop7基本情報

デプロイ

手順

  • 0) 準備
  • 1) アプリの起動?
  • 2) 動作確認その1
  • 3) アプリの起動
  • 4) 動作確認その2

0.準備

まずはソースコードの取得から。

$ git clone https://github.com/pavellishin/drop7
$ cd drop7
drop7$ ls
defs.js  drop7.css  drop7.html  drop7.js  drop7.manifest  jquery-1.9.1.min.js  revision.hook  take1  take2

1.アプリの起動?

これまで通りCloud Foundry上にアプリをデプロイしてみましょう。
後々のためにmanifestファイルを作ってしまいます。

drop7$ vi manifest.yml
---
applications:
- name: drop7
  buildpack: https://github.com/cloudfoundry/staticfile-buildpack
  memory: 4M
  disk_quota: 16M

こんな所でしょうか。
デプロイをしてみます。

drop7$ cf push
Using manifest file /home/ukaji/workspace/drop7/manifest.yml

Creating app drop7 in org ukaji / space default as ukaji...
OK

Creating route drop7.10.244.0.34.xip.io...
OK

Binding drop7.10.244.0.34.xip.io to drop7...
OK

Uploading drop7...
Uploading app files from: /home/ukaji/workspace/drop7
Uploading 218.3K, 16 files
Done uploading               
OK

Starting app drop7 in org ukaji / space default as ukaji...
-----> Downloaded app package (80K)
Cloning into '/tmp/buildpacks/staticfile-buildpack'...
Submodule 'compile-extensions' (https://github.com/cloudfoundry-incubator/compile-extensions.git) registered for path 'compile-extensions'
Cloning into 'compile-extensions'...
Submodule path 'compile-extensions': checked out '0b1eb13f9a747494b0abac8c665bb556cd07c749'
grep: Staticfile: No such file or directory
-----> Using root folder
-----> Copying project files into public/
-----> Setting up nginx
grep: Staticfile: No such file or directory
-----> Uploading droplet (2.3M)

1 of 1 instances running

App started


OK

App drop7 was started using this command `sh boot.sh`

Showing health and status for app drop7 in org ukaji / space default as ukaji...
OK

requested state: started
instances: 1/1
usage: 4M x 1 instances
urls: drop7.10.244.0.34.xip.io
last uploaded: Tue Jun 9 05:12:57 +0000 2015
stack: lucid64

     state     since                    cpu    memory       disk       details   
#0   running   2015-06-09 02:13:41 PM   0.0%   2.4M of 4M   0 of 16M

無事起動したようです。

2.動作確認その1

動作確認を行います。
ブラウザでアクセスをしてみましょう。

403エラーが出てしまいました。

そこまで込み入った話でもないのでネタバレをしてしまうと、実はdrop7.10.244.0.34.xip.ioにアクセスした時に呼ばれているファイルは、アプリケーションのルートディレクトリにあるindex.htmlです。
今回のアプリケーションの中身を眺めてみると、最初に呼び出したいファイルはdrop7.htmlのようですが、デフォルトの設定ではこれを呼ぶことができなかったため、エラーが返ってきてしまったと考えられます。

drop7.htmlのファイル名をindex.htmlに書き換えてしまえば良い話ではあるのですが、もし他のファイルからdrop7.htmlが呼ばれていたりすると少々厄介です。
どうにかして最初に呼ぶファイルをdrop7.htmlに変更してしまう方が何かと便利そうです。

3.アプリの起動

ということで、今回はStaticfile-buildpackが提供する機能を使ってみます。
Staticfile-buildpackのConfigurationの項目を読んでみると、Advanced Nginx configurationという項目があります。
Staticfile-buildpackはHTMLなどのアプリのためにNginxによってHTTPサーバを立ててくれるのですが、どうやらCloud Foundry上に立てられるNginxの設定ファイルnginx.confを書きかえることができるようです。

では、Staticfile-buildpackのリポジトリ内にあるnginx.conf、
https://github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf
こちらを例にして設定ファイルを作ってみます。
・・・と言っても書き換えるのは24行目のindexの部分だけ。
ここにdrop7.htmlを追加しましょう。

drop7$ vi nginx.conf
worker_processes 1;
daemon off;

error_log <%= ENV["APP_ROOT"] %>/nginx/logs/error.log;
events { worker_connections 1024; }

http {
  log_format cloudfoundry '$http_x_forwarded_for - $http_referer - [$time_local] "$request" $status $body_bytes_sent';
  access_log <%= ENV["APP_ROOT"] %>/nginx/logs/access.log cloudfoundry;
  default_type application/octet-stream;
  include mime.types;
  sendfile on;
  gzip on;
  tcp_nopush on;
  keepalive_timeout 30;
  port_in_redirect off; # Ensure that redirects don't include the internal container PORT - <%= ENV["PORT"] %>

  server {
    listen <%= ENV["PORT"] %>;
    server_name localhost;

    location / {
      root <%= ENV["APP_ROOT"] %>/public;
      index index.html index.htm Default.htm drop7.html;
      <% if File.exists?(File.join(ENV["APP_ROOT"], "nginx/conf/.enable_directory_index")) %>
      autoindex on;
      <% end %>
      <% if File.exists?(auth_file = File.join(ENV["APP_ROOT"], "nginx/conf/.htpasswd")) %>
      auth_basic "Restricted";                                #For Basic Auth
      auth_basic_user_file <%= auth_file %>;  #For Basic Auth
      <% end %>
      <% if ENV["FORCE_HTTPS"] %>
      if ($http_x_forwarded_proto = http) {
        return 301 https://$host$request_uri;
      }
      <% end %>
    }
  }
}

※変更箇所

drop7$ diff nginx.conf_default nginx.conf 
24c24
<       index index.html index.htm Default.htm;
---
>       index index.html index.htm Default.htm drop7.html;

もちろん、nginx.confファイルをご自身で書ける方は他にも色々な設定を加えてみてもいいかもしれません。

さて、今度こそアプリケーションを動かしてみましょう。
nginx.confはアプリのルートディレクトリに置いておくだけでいいそうなのでこのままデプロイで問題なさそうです。

drop7$ cf push
(一部略)
requested state: started
instances: 1/1
usage: 4M x 1 instances
urls: drop7.10.244.0.34.xip.io
last uploaded: Tue Jun 9 05:22:47 +0000 2015
stack: lucid64

     state     since                    cpu    memory       disk       details   
#0   running   2015-06-09 02:23:41 PM   0.0%   2.3M of 4M   0 of 16M

起動はもちろん成功。

4.動作確認その2

URLにアクセスしてみましょう。

今回は無事アクセスができました。

ちなみにゲームの基本的なルールですが・・・

  • 1.縦もしくは横に並んだボールのうち、列の個数と同じ番号のボールが消える
  • 2.数字の書いていないボールは周りのボールを2回壊せば中からボールが出てくる

こんなところでしょうか。あとは大体世の中の落ち物ゲームと同じような感じだと思います。
何にせよ言葉で説明するのは少し難しいので、習うより慣れろでプレイしてみるのが一番だと思います。

おわりに

毎回HTML+Javascriptのアプリケーションを同じように解説するのは少し味気ないので、今回はBuildpackが提供する追加機能に触れてみました。
Githubのページをご覧の通り、他にも簡単なBASIC認証などの機能も実装されています。
動作検証を行ったアプリの中にはまだHTML系のアプリケーションも残っているので、いずれそちらも解説するかもしれません。

今回使用したソフトウェア

2015-06-12

Asciiflow を Cloud Foundry で動かす

本日の第7回「Cloud Foundry 百日行」は、asciiflowです。
今回のアプリもHTMLとJavascriptなのでこれまで同様の簡単な手順で動作させることが出来ます。

[asciiflow]基本情報

デプロイ

手順

  • 0) 準備
  • 1) アプリの起動
  • 2) 動作確認

0.準備

まずはソースコードの取得をしましょう。
ここではローカルの適当なWorkSpaceで作業を行っています。

$ git clone https://github.com/lewish/asciiflow2.git
$ cd asciiflow2
asciiflow2$ ls
addtohomescreen.css closure-compiler.jar  images   jquery-1.9.1.min.js  jquery.jeditable.min.js  js-lib
addtohomescreen.min.js compile.sh       index.html  jquery-1.9-externs.js  js-compiled.js    README

今回のアプリはディレクトリの中身を眺めてみると.jarファイルが入っています。
一見Javaアプリかな?とも思えるのでREADMEを読んでみると

  • 1) compile.shを使ってコンパイル
  • 2) 1)が実行できない時はclosure-compiler.jarに実行権を付与
  • 3) simple web serverを起動

となっており、1)2)の手順はclosure-compiler.jarを使ってjs-compiled.jsを作成するようです。

その後、WEBServerを起動するようですが、しかし既に作成済みのjs-compiled.jsも提供されている為、
手順1)2)は省略することができます。

結果、closure-compiler.jarと./js-libは動作には不要となりこれまでにも紹介してきたhtmlとjavascriptの組み合せのアプリになります。

1.アプリの起動

ではCloud Foundry上にアプリをデプロイしてみましょう。
まず作成するのはmanifest.ymlとStaticfile。

asciiflow2$ touch Staticfile
asciiflow2$ vi manifest.yml

---
applications:
- name: asciiflow2
  memory: 64M
  buildpack: https://github.com/cloudfoundry/staticfile-buildpack

今回はStaticfileを作成しました。このファイルが無くてもStaticfile Buildpackは動作します。しかし
Buildpackによってはアプリをデプロイした際のオプションにBuildPackを指定してもBuildpackの適用条件を満たしていない場合
起動してくれません。利用するBuildpackの動作条件は確認しましょう。

準備が整ったのでpushします。

asciiflow2$ cf push

:

OK

requested state: started
instances: 1/1
usage: 64M x 1 instances
urls: asciiflow2.10.244.0.34.xip.io
last uploaded: Thu Jun 11 07:19:50 +0000 2015
stack: lucid64

     state     since                    cpu    memory        disk      details   
#0   running   2015-06-11 04:20:07 PM   0.0%   7.3M of 64M   0 of 1G      

上記のようなログが見えればデプロイ成功です。

2.動作確認

ブラウザで動作確認を行ってみましょう。
asciiflow2.10.244.0.34.xip.ioにブラウザでアクセスをしてみると・・・

ちゃんとアプリが起動しています。
GoogleDrive(アカウントが必要)へのAutoSave以外の機能は試しましたが問題なく利用できます。

今回使用したソフトウェア

2015-06-11

-2048 を Cloud Foundry で動かす

本日の第6回「Cloud Foundry 百日行」は、-2048です。
これも第5回と同じくデプロイが簡単なHTML+JavaScriptのアプリです。

-2048基本情報

デプロイ

手順

  • 0) 準備
  • 1) アプリの起動
  • 2) 動作確認

0.準備

まずはソースコードの取得から。
ディレクトリ名にマイナス記号が入っていると少々厄介なのでnegative2048に名前を変更しながらgit cloneしておきましょう。

$ git clone https://github.com/LegoMaster616/-2048 negative2048
$ cd negative2048
negative2048$ ls
CONTRIBUTING.md  favicon.ico  index.html  js  LICENSE.txt  meta  Rakefile  README.md  style

主な中身はindex.htmlとjs/ディレクトリなので、前回と同様にstaticfile-buildpackにHTTPサーバを立ててもらえばアプリは動いてくれそうです。

1.アプリの起動

では早速Cloud Foundry上にアプリをデプロイしてみましょう。
前回と同様に $ cf push negative2048 -b https://github.com/cloudfoundry/staticfile-buildpack で方を付けてしまっても良いのですが、折角なので前にご紹介したmanifestファイルを再び使ってみます。
アプリケーションの作りがほぼ同じなので同じようなmanifestファイルでデプロイできるはずです。

negative2048$ vi manifest.yml
---
applications:
- name: negative2048
  buildpack: https://github.com/cloudfoundry/staticfile-buildpack

ここまでくれば残す作業はcf pushだけです。アプリをデプロイしましょう。

negative2048$ cf push
Using manifest file /home/ukaji/workspace/_old/negative2048/manifest.yml

Creating app negative2048 in org ukaji / space default as ukaji...
OK

Creating route negative2048.10.244.0.34.xip.io...
OK

Binding negative2048.10.244.0.34.xip.io to negative2048...
OK

Uploading negative2048...
Uploading app files from: /home/ukaji/workspace/_old/negative2048
Uploading 239K, 32 files
Done uploading               
OK

Starting app negative2048 in org ukaji / space default as ukaji...
-----> Downloaded app package (244K)
Cloning into '/tmp/buildpacks/staticfile-buildpack'...
Submodule 'compile-extensions' (https://github.com/cloudfoundry-incubator/compile-extensions.git) registered for path 'compile-extensions'
Cloning into 'compile-extensions'...
Submodule path 'compile-extensions': checked out '0b1eb13f9a747494b0abac8c665bb556cd07c749'
grep: Staticfile: No such file or directory
-----> Using root folder
-----> Copying project files into public/
-----> Setting up nginx
grep: Staticfile: No such file or directory
-----> Uploading droplet (2.7M)

1 of 1 instances running

App started


OK

App negative2048 was started using this command `sh boot.sh`

Showing health and status for app negative2048 in org ukaji / space default as ukaji...
OK

requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: negative2048.10.244.0.34.xip.io
last uploaded: Thu Jun 11 00:37:00 +0000 2015
stack: lucid64

     state     since                    cpu    memory         disk      details   
#0   running   2015-06-11 09:37:17 AM   0.0%   2.7M of 256M   0 of 1G

2.動作確認

デプロイが無事終了したら動作確認です。ブラウザでアクセスをしてみましょう。

動きました。

このゲームも前回と同じく2048ゲームのクローンです。
操作方法は基本通りなのですが、少々追加ルールがややこしいです。

  • 追加ルール1.プラスとマイナスの同じ数字が衝突すると0のタイルになる
  • 追加ルール2.0のタイルは他のタイルの数字を変更することなくマージされる

ちなみに勝利条件は2048、もしくは-2048のタイルを作ることなのですが、得点の稼ぎ方なども考えだすと相当にややこしいゲームです。

おまけ

アプリケーションが起動するときに表示されるこのステータス画面、

(一部略)
Showing health and status for app negative2048 in org ukaji / space default as ukaji...
OK

requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: negative2048.10.244.0.34.xip.io
last uploaded: Mon Jun 8 05:52:09 +0000 2015
stack: lucid64

     state     since                    cpu    memory         disk      details   
#0   running   2015-06-08 02:52:27 PM   0.0%   2.8M of 256M   0 of 1G 

これの一番下をご覧になってお気づきの方もいらっしゃるかもしれません。
「メモリ2.8Mのアプリに256M割り振っちゃうのはちょっと無駄じゃないかな?」
こんなことを考えたとしましょう。

実はこの

memory
2.8M of 256M

の部分、「このアプリは割当てられた256Mのメモリのうち、2.8Mを使用中。」という意味です。
確かに数Mのメモリで動いてくれるアプリケーションに256Mも用意してあげるのは少々もったいないので、もう少し適切な値を割り振りたいものです。

さて、メモリなどのリソースの量についても、アプリ起動コマンドのオプションで解決することができます。
今回のアプリケーションで試してみましょう。

negative2048$ cf push negative2048 -b https://github.com/cloudfoundry/staticfile-buildpack -m 4M -k 8M
(一部略)
requested state: started
instances: 1/1
usage: 4M x 1 instances
urls: negative2048.10.244.0.34.xip.io
last uploaded: Mon Jun 8 06:13:16 +0000 2015
stack: lucid64

     state     since                    cpu    memory       disk      details   
#0   running   2015-06-08 03:13:55 PM   0.0%   2.4M of 4M   0 of 8M 

ここでは-mオプションによってメモリ量を指定、ついでに−kオプションで使用ディスク量の指定を行ってみました。
最初のデプロイ時より無駄が少なくなっているのがわかります。

もちろんこれらの起動オプションもmanifestファイル内に吸収し、起動コマンドをcf pushにまとめることが可能です。
manifestファイルは下の通りです。

negative2048$ cat manifest.yml 
---
applications:
- name: negative2048
  buildpack: https://github.com/cloudfoundry/staticfile-buildpack
  memory: 4M
  disk_quota: 8M

今回使用した環境

2015-06-10

243game を Cloud Foundry で動かす

本日の第5回「Cloud Foundry 百日行」は、243 Gameです。
デプロイをして実際に動かすまでが簡単にできるアプリなので、初心者のかたも是非手を動かしてみてください。

[243 Game]基本情報

デプロイ

手順

  • 0) 準備
  • 1) アプリの起動
  • 2) 動作確認

0.準備

まずはソースコードの取得をしましょう。
ここではローカルの適当なWorkSpaceで作業を行っています。

$ git clone https://github.com/mishop/243
$ cd 243
243$ ls
CONTRIBUTING.md  favicon.ico  index.html  js  LICENSE.txt  meta  Rakefile  README.md  style

ディレクトリの中身を眺めてみるとindex.htmlやjs/などが入っています。
HTMLファイルがJavaScriptを呼び出して動作する比較的簡単な構造のアプリケーションのようです。

1.アプリの起動

では早速Cloud Foundry上にアプリをデプロイしてみましょう。
Cloud Foundryへのデプロイはpushで行います。
実はこのアプリ、次のコマンドによって一発でデプロイが完了します。

243$ cf push 243game -b https://github.com/cloudfoundry/staticfile-buildpack
Creating app 243game in org ukaji / space default as ukaji...
OK

Creating route 243game.10.244.0.34.xip.io...
OK

Binding 243game.10.244.0.34.xip.io to 243game...
OK

Uploading 243game...
Uploading app files from: /home/ntt/apps/243
Uploading 226.6K, 29 files
Done uploading               
OK

Starting app 243game in org ukaji / space default as ukaji...
-----> Downloaded app package (236K)
Cloning into '/tmp/buildpacks/staticfile-buildpack'...
Submodule 'compile-extensions' (https://github.com/cloudfoundry-incubator/compile-extensions.git) registered for path 'compile-extensions'
Cloning into 'compile-extensions'...
Submodule path 'compile-extensions': checked out '0b1eb13f9a747494b0abac8c665bb556cd07c749'
grep: Staticfile: No such file or directory
-----> Using root folder
-----> Copying project files into public/
-----> Setting up nginx
grep: Staticfile: No such file or directory
-----> Uploading droplet (2.6M)

1 of 1 instances running

App started


OK

App 243game was started using this command `sh boot.sh`

Showing health and status for app 243game in org ukaji / space default as ukaji...
OK

requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: 243game.10.244.0.34.xip.io
last uploaded: Mon Jun 8 01:02:42 +0000 2015
stack: lucid64

     state     since                    cpu    memory         disk      details   
#0   running   2015-06-08 10:02:58 AM   0.0%   3.7M of 256M   0 of 1G

上記のようなログが見えればデプロイ成功です。

今回、cf pushというコマンドで-bというオプションを指定しましたが、これは使用する”Buildpack”のURLを指定するためのオプションです。
Buildpackとは、Cloud Foundry上にデプロイしようとするアプリのために環境を構築するためのものです。
RubyのアプリであればRubyのBuildpack、GolangのアプリであればGolangのBuildpackをデプロイ時に選択する、というような利用イメージになります。
今回用いたstaticfile-buildpackは、HTMLファイルやJavaScriptファイルで作られたアプリを配信するためにHTTPサーバ(Nginx)を立てる、といった仕組みになっています。

HTTPサーバを立てたりアプリのソースコードを適切なディレクトリに配置したり・・・といった作業を全てCloud Foundryが行ってくれたため、今回のアプリは1コマンドでの起動ができてしまいました。

2.動作確認

デプロイが無事終了したら動作確認を行ってみましょう。
デプロイ完了の時にURLが発行されているはずなので、ブラウザでアクセスをしてみます。

243$ cf app 243games
Getting apps in org ukaji / space default as ukaji...
OK

name      requested state   instances   memory   disk   urls   
243game   started           1/1         256M     1G     243game.10.244.0.34.xip.io   

URLはcf app アプリ名でも確かめることができます。
243game.10.244.0.34.xip.ioにブラウザでアクセスをしてみると・・・

ちゃんとアプリが起動しています。

画面を見て既にお気づきの方も多いと思いますがこのゲーム、あの有名な2048ゲームのクローンです。
ゲームの遊び方は至ってシンプルで、
 1.矢印キーを使って画面内のタイルを4方向にスライドさせる
 2.同種のタイルを3つぶつけて3倍の数のタイルにマージする
 3.頑張って243のタイルを作る
これだけです。
243=3の5乗なので5段階のマージで243には到達しそうなものですが、思った以上の難易度です。
あくまで個人の感想ですが、2048ゲームで2048のタイルを作るより243ゲームで243のタイルを作るほうが遥かに難しいです。

おまけ

さて、Cloud Foundryにデプロイをする時のpushコマンドは引数として色々なオプションを付けることができます。
今回は-bオプションだけを使いましたが、実は他にもアプリ起動コマンドの指定や使用メモリの制限など多彩な機能が存在しています。
しかし、機能が多彩なこと自体は良いのですが、これは同時に

「色々なオプションを駆使してアプリを起動しました!」
 ↓
しばらくして・・・
 ↓
「あの時の起動コマンド何だったっけ・・・」

などという事態が発生しないとも限りません。

こんな自体を避けるためには、アプリのルートディレクトリに「manifestファイル」を作って置くのが便利です。
Cloud Foundryでは、デプロイの際に必要な設定をYML形式の設定ファイルに記載しておくことができます。
これを一度作ってしまえば、デプロイのコマンドは’cf push’だけで済んでしまいます。
manifestファイルの詳細な書き方については
http://docs.cloudfoundry.org/devguide/deploy-apps/manifest.html
をご参照下さい。

最後に、今回のアプリのデプロイに必要最低限なmanifestファイルを記しておきます。

243$ vi manifest.yml
---
applications:
- name: 243game
  buildpack: https://github.com/cloudfoundry/staticfile-buildpack

cf pushだけでデプロイができることを確かめてみてください。

今回使用した環境

2015-06-09

EtherCalc を Cloud Foundry で動かす

「Cloud Foundry 百日行」第4回目は,前回と同様の spreadsheet アプリ “EtherCalc” です。

基本情報

EtherCalc は web spreadsheet で,複数人で同時編集できる点も前回の EtherSheet と同じです。ソースを見た印象としては,PaaS を含めたクラウド環境で動かすことを意識した造りになっているように感じました。

記事の概要は以下の通りです。

  1. ソースコードの取得
  2. Redis なしでデプロイ
  3. Redis なしで動作確認
  4. Redis ありでデプロイ
    • Redis サービスの作成と結合
    • ソースコードの修正
    • アプリの push
  5. 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

ブラウザー画面はもとの状態に戻っていて,リロードしてもデータは残っています。

以上で一通りの動作確認は終わりです。

今回使用した環境

2015-06-08

EtherSheet を Cloud Foundry で動かす

「Cloud Foundry 百日行」第3回目は,Node.js ベースの spreadsheet アプリ “EtherSheet” です。

基本情報

EtherSheet は,GitHub の README によると,「リアルタイム共同作業が可能なオープンソースの spreadsheet」です。オープンソースの Google Sheets クローン,というのが分かりやすい説明かもしれません。もっとも,今回試用してみた限りでは,機能も安定性も Google Sheets には及ばないと感じましたが..。
手順の概要は以下の通りです。
  1. ソースコードの取得
  2. ソースコードの修正
    今回,Cloud Foundry 上で動作させるに当たって,2点ほど修正が必要だったので,それについて述べます
  3. サービスの作成
    本アプリは MySQL を使うので,MySQL サービスのインスタンスを作成します
  4. アプリの push
    今回は manifest.yml ファイルを使って push してみました
では,始めます。

ソースコードの取得

$ git clone https://github.com/ethersheet-collective/EtherSheet.git
EtherSheet ディレクトリーに入ります。
$ cd EtherSheet/

ソースコードの修正

本アプリを Cloud Foundry上で動作させるに当たり,実地検証の結果,ソースコードの修正が必要と判断しました。
この部分の記事の書き方としては,大きく,
  • (a) まず正しい手順を書き,その後失敗の経験に基づいた注意点を書く
  • (b) 失敗した手順を書き,原因を解明して修正したあと,成功した手順を書く
の2つの方法があると思いますが,今回は(a)で記述を進めることにしました。この辺り,「(b)の方が読みやすい」等ご意見があれば,お知らせいただけるとありがたく思います。
今回の修正のポイントは,
  1. MySQLの接続情報を環境変数から取るようにする
  2. アプリが待ち受けるホスト/ポートの情報を環境変数から取るようにする
の2点です。

MySQLの接続情報を環境変数から取る

本アプリは,データベースの接続情報を設定ファイル (config.js) から取るようになっています。しかし, Cloud FoundryやHerokuのような PaaS では,データベースを service としてカジュアルに結合(bind)/切断(unbind)することを想定し,そうした情報は環境変数として与えられる造りになっています。これに合うよう,ソースコードを修正しました。
実際の修正内容は以下の通りです。既存の動作を変えないよう,環境変数がある場合のみ上書きされ,それ以外は設定ファイルの値を使うようになっています。
$ git show 20f77d7
 1commit 20f77d78c2079966dd6624b7abdca59705017f78
 2Author: Noburou TANIGUCHI <taniguchi.noburou@lab.ntt.co.jp>
 3Date:   Mon Jun 8 12:35:16 2015 +0900
 4
 5    Get database connection credentials from DATABASE_URL env var
 6
 7    For easiness to run on Cloud Foundry / PaaS environment.
 8
 9diff --git a/lib/ethersheet_service.js b/lib/ethersheet_service.js
10index e527c0e..58aa2c4 100644
11--- a/lib/ethersheet_service.js
12+++ b/lib/ethersheet_service.js
13@@ -5,6 +5,7 @@ var uuid = require('node-uuid').v4;
14 var async = require('async');
15 var async = require('async');
16 var csv = require('csv');
17+var url = require('url');
18 var _ = require('underscore');
19 var Sheet = require('./models/sheet');
20 var SheetCollection = require('./models/sheet_collection');
21@@ -15,12 +16,26 @@ var SheetCollection = require('./models/sheet_collection');
22 var EtherSheetService = module.exports = function(config){
23   var es = this;
24   es.config = config;
25+
26+  /* for Cloud Foundry */
27+  var dbUrl = url.parse(process.env.DATABASE_URL);
28+  if (dbUrl) {
29+    es.config.db_host = dbUrl.hostname;
30+    es.config.db_port = dbUrl.port;
31+    var path = dbUrl.path.slice(1).split(/[?#]/);
32+    es.config.db_name = path[0]
33+    var auth = dbUrl.auth.split(':');
34+    es.config.db_user = auth[0];
35+    es.config.db_password = auth[1];
36+  }
37+
38   events.EventEmitter.call(this);
39   this.connectionHandler = function(){};
40   es.db = new ueberDB.database(
41     es.config.db_type, {
42     user: es.config.db_user,
43     host: es.config.db_host,
44+    port: es.config.db_port,
45     password: es.config.db_password,
46     database: es.config.db_name
47   });

アプリが待ち受けるホスト/ポートの情報を環境変数から取る

前項と同様に,本アプリでは,アプリが待ち受けるホスト/ポートの情報を設定ファイル (config.js) から取るようになっています。しかし Cloud Foundry環境では,アプリの起動・停止が簡単に行えるよう,アプリのインスタンスはコンテナー内で動作し,待ち受けポートも61001番以降から自動で採番したものを環境変数に入れるようになっており,ユーザーが指定できるようにはなっていません。
そこで,アプリの待ち受けポートも環境変数から取れるよう,ソースコードを修正しました。
実際の修正内容は以下の通りです。前項と同様,既存の動作を変えないよう,環境変数がある場合のみ上書きされ,それ以外は設定ファイルの値を使うようになっています。
$ git show bf3e351
 1commit bf3e3510bd6e8393a5d10e81427110e3f34ed493
 2Author: Noburou TANIGUCHI <taniguchi.noburou@lab.ntt.co.jp>
 3Date:   Mon Jun 8 12:40:36 2015 +0900
 4
 5    Get host / port to listen from VCAP_APP_HOST / VCAP_APP_PORT env var
 6
 7    For easiness to run on Cloud Foundry / PaaS environment.
 8
 9diff --git a/lib/ethersheet_service.js b/lib/ethersheet_service.js
10index 58aa2c4..2efb0d5 100644
11--- a/lib/ethersheet_service.js
12+++ b/lib/ethersheet_service.js
13@@ -18,6 +18,8 @@ var EtherSheetService = module.exports = function(config){
14   es.config = config;
15
16   /* for Cloud Foundry */
17+  es.config.host = process.env.VCAP_APP_HOST || es.config.host || 'localhost';
18+  es.config.port = process.env.VCAP_APP_PORT || es.config.port || 8080;
19   var dbUrl = url.parse(process.env.DATABASE_URL);
20   if (dbUrl) {
21     es.config.db_host = dbUrl.hostname;

サービスの作成

本アプリは永続化ストレージとして MySQL を使うので,MySQL サービスのインスタンスを作成します。
今回利用した MySQL サービスは, cf-mysql-release を利用して構築しました。これは postgresql-cf-service-broker とは異なり,アプリのデプロイは全く関係ないので,今回構築方法等については触れませんが,記事化のご要望等あれば何か考えたいと思います。
サービス種別の一覧:
$ 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
......
サービスの作成:
$ cf create-service p-mysql 100mb-dev my4es
Creating service instance my4es in org nota-ja / space 100 as nota-ja...
OK

アプリのpush

これで準備が整ったので,いよいよアプリをpushしていきます。
今回は Application Manifest ファイル (manifest.yml) を使って push してみました。
Cloud Foundryにアプリをpushする際には (例えば cf push コマンドのヘルプを見るとわかりますが) 非常に多くのオプションがあります。メモリ上限, ディスク上限, インスタンス数, ホスト名, ドメイン名, 起動コマンド, push時に起動するか,…, 等々。同じアプリをpushするとき,これらをpushの度に指定する面倒さを軽減するための機能が,Application Manifest ファイルです。先述したような設定をこのファイルに書いておくことで,同じ設定でpushを繰り返す場合は単に cf push とするだけで済むようになります。
今回使用した manifest.yml の内容は以下の通りです。
$ cat manifest.yml
---
applications:
  - path: .
    name: es
    random-route: true
    memory: 256M
    instances: 1
    services:
      - my4es
このファイルがあるディレクトリーで cf push を実行します。
$ cf push
Using manifest file /home/nota-ja/workspace/100/EtherSheet/manifest.yml
......
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: es-inactive-fluffer.10.244.0.34.xip.io
last uploaded: Mon Jun 8 01:01:31 +0000 2015
stack: lucid64

     state     since                    cpu    memory        disk      details
#0   running   2015-06-08 10:02:28 AM   0.0%   72M of 256M   0 of 1G
アプリが起動しました。
ちなみに,上記の manifest.yml の記述は,だいたい以下の手順と等価です。
$ cf push es -p . --random-route -m 256m -i 1 --no-start
$ cf bind-service es my4es
$ cf restage

動作確認

アプリが無事起動したので,実際にブラウザーからアクセスしてみます。

初期画面


GOTO SHEET ボタンを押すと初期状態の spreadsheet に遷移します。

spreadsheet の初期状態


セルに値を入力

A1 セルに 123 を入力してみます。

合計関数

合計を取る sum 関数を A3 セルに入力してみます。

↓

正しい計算結果 579 が表示されました。

FUNCTIONS ペインから関数を入力

左上の右側のボタンをクリックして,FUNCTIONS ペインを表示し,そこから sqrt 関数を選択してみます。

sqrt_def という文字列が入力されました。
入力された文字列を正しい関数名 sqrt に修正し,A3 セルを引数に与えてみます。

↓

A4 セルに計算結果が表示されました。

SHEETS ペイン

左上の左側のボタンをクリックして,SHEETS ペインを表示させます。

新シートの作成


newSheet ボタンをクリックし,新シートを作成しました。
新しいシートは空です。

CSVのエクスポート

exportCSV ボタンをクリックすると,生のCSVファイルがブラウザー上に表示されます。

ここでブラウザーのメニューから 保存 を実行すると,保存ダイアログが出てくるので,保存します。

CSVのインポート

Sheet2 に,先ほどエクスポートしたCSVをインポートしてみます。
importCSV ボタンをクリックすると,インポート・ダイアログが表示されます。

「ファイルを選択」をクリックすると,ファイル選択ダイアログで先ほど保存したCSVファイルを選択すると,インポートの準備が整います。

Upload ボタンをクリックすると,インポートされる…はずですが,エラーが表示されました。

この時のアプリのログは以下のようになっていました。
2015-06-08T10:36:55.40+0900 [App/0]      OUT POST /HRgZgHUlR5nvSmb74kT5/pubsub/589/5rukm6ta/xhr 0ms (unfinished)
2015-06-08T10:36:58.15+0900 [App/0]      ERR /home/vcap/app/lib/ethersheet_service.js:161
2015-06-08T10:36:58.15+0900 [App/0]      ERR   csv().from(data.toString())
2015-06-08T10:36:58.15+0900 [App/0]      ERR   ^
2015-06-08T10:36:58.15+0900 [App/0]      ERR TypeError: object is not a function
2015-06-08T10:36:58.15+0900 [App/0]      ERR     at EtherSheetService.createSheetFromCSV (/home/vcap/app/lib/ethersheet_service.js:161:3)
2015-06-08T10:36:58.15+0900 [App/0]      ERR     at /home/vcap/app/lib/server.js:86:10
2015-06-08T10:36:58.15+0900 [App/0]      ERR     at fs.js:271:14
2015-06-08T10:36:58.15+0900 [App/0]      ERR     at Object.oncomplete (fs.js:107:15)
今回全く触っていない部分のエラーなので,未完成なのかもしれません。
ブラウザーの「戻る」ボタンをクリックすると,接続エラー画面が。

指示通りリロードしてみましたが, 502 Bad Gateway の文字が。

仕方ないのでアプリを再起動してみます。
$ cf restart es
Stopping app es in org nota-ja / space 100 as nota-ja...
OK

Starting app es 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 es was started using this command `npm start`

Showing health and status for app es in org nota-ja / space 100 as nota-ja...
OK

requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: es-inactive-fluffer.10.244.0.34.xip.io
last uploaded: Mon Jun 8 01:01:31 +0000 2015
stack: lucid64

     state     since                    cpu    memory          disk      details
#0   running   2015-06-08 10:38:34 AM   0.0%   73.1M of 256M   0 of 1G
無事再起動しました。
先ほど入力したのシートの URL にアクセスしてみると…。

正常に表示され,データも残っていました。
以上で一通りの動作確認は終わりです。

今回使用した環境

2015-06-05

postgresql-cf-service-broker を Cloud Foundry で動かす

「Cloud Foundry 百日行」第2回目は,いきなり少し変化球でもうしわけありませんが,postgresql-cf-service-broker です。

基本情報

実はこのアプリは,Cloud Foundry (以下CF) の service broker として機能するアプリで,通常のアプリとは少し異なります。

にもかかわらず,なぜこれを今回紹介するかというと,前回の Kandan の記事 で,このアプリを使って PostgreSQL サービスを構築したので,このタイミングを措いて他にこれを紹介する機会はないと考えたためです。

また,独自に bosh-lite 等を使ってCF環境を構築している/しようとしている方にとっても,本記事は参考になると判断したこともあります。

全体の概要はこんな感じです (© @kenojiri さん; 青色部分は筆者)。

全体の流れは概略以下の様になっています:

  1. Docker コンテナー上の PostgreSQL を起動
  2. postgresql-cf-service-broker をCF上にアプリとしてデプロイ
    環境変数の情報に基づき postgresql-cf-service-broker が PostgreSQL に接続&管理
    postgresql-cf-service-broker をCF環境の service broker として登録&公開
  3. (前記事の例)
    Kandan をCF上にアプリとしてデプロイ
    サービス生成/結合要求に応じてpostgresql-cf-service-broker が PostgreSQL にDB,ユーザー,パスワードを作成
    その情報を含む接続情報を Kandan に渡す
    Kandan はその接続情報を使って PostgreSQL 上のDBにアクセス

では,始めます。上述したように,今回は service broker から使われる PostgreSQL のインスタンスの構築から説明します。

PostgreSQL インスタンスの準備

*既に自由に使える PostgreSQL のインスタンスをお持ちの方は,本節は スキップ していただいてOKです。

今回は検証用ということで,PostgreSQL は Docker を使って用意することにしました。

手順の概要は以下の通りです:

  • 1) Docker のインストール
  • 2) psql (PostgreSQL CLI) のインストール
  • 3) PostgreSQL Docker image の起動

Docker のインストール

CFは Ubuntu 上で動作するので,同じ Ubuntu 上で PostgreSQL Docker image を動かします。まずは Ubuntu に Docker をインストールします。

$ sudo apt-get install -y docker.io

確認:

$ docker --version
Docker version 1.0.1, build 990021a

psql (PostgreSQL CLI) のインストール

$ sudo apt-get install -y postgresql-client

確認:

$ psql --version
psql (PostgreSQL) 9.3.7

PostgreSQL Docker image の起動

Docker Image の取得

今回は,検証時点での最新版 9.4.2 を使うことにしました。

$ sudo docker pull postgres:9.4.2

Docker image の起動

ホストのポート 5432 をコンテナーのポート 5432 に転送し,初期ユーザー cf, 初期ユーザーのパスワードを xxxxxxxx に設定して,取得した Docker Image を起動します。

$ sudo docker run --name cf-postgres -e POSTGRES_PASSWORD=xxxxxxxx -e POSTGRES_USER=cf -e LC_ALL=C.UTF-8 -p 0.0.0.0:5432:5432 -d postgres:9.4.2

接続確認

$ psql -U cf -W -l -h 192.168.xxx.xxx
Password for user cf:
                              List of databases
   Name    |  Owner   | Encoding | Collate |  Ctype  |   Access privileges
-----------+----------+----------+---------+---------+-----------------------
 cf        | postgres | UTF8     | C.UTF-8 | C.UTF-8 |
 postgres  | postgres | UTF8     | C.UTF-8 | C.UTF-8 |
 template0 | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres          +
           |          |          |         |         | postgres=CTc/postgres
 template1 | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres          +
           |          |          |         |         | postgres=CTc/postgres
(4 rows)

正しく設定されている場合は,上記コマンドでデータベースの一覧が取得できます。

接続がうまくいかず,以下のようなエラーが出る場合は,

$ psql -U cf -W -l
Password for user cf:
psql: could not connect to server: No such file or directory
    Is the server running locally and accepting
    connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

以下のコマンドでポートの listen 状態を確認してみてください。

$ netstat -ltn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:10050           0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:2222          0.0.0.0:*               LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 :::5432                 :::*                    LISTEN
tcp6       0      0 :::10050                :::*                    LISTEN

ここで,ホストのポート 5432 が IPv6 側しか listen されていない場合,この issue の問題を引いている可能性があります。現状この issue は未解決のようですが,私はここでのやりとりの中に書かれている以下の方法で問題を解決することができました。

現状の確認:

$ sysctl net.ipv6.conf.all.forwarding
net.ipv6.conf.all.forwarding = 0

パラメーターの変更:

$ sudo sysctl net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.forwarding = 1

修正結果の確認:

$ sysctl net.ipv6.conf.all.forwarding
net.ipv6.conf.all.forwarding = 1

以上で,PostgreSQL インスタンスの準備は完了です。

postgresql-cf-service-broker のデプロイ

次に,postgresql-cf-service-broker をCF上にデプロイしていきます。

以下手順の概要です:

  • 0) デプロイ準備
    • 0.1) JDK, Maven のインストール
    • 0.2) ソースコードの取得&アプリのビルド
    • 0.3) Org, Space の作成
    • 0.4) Application Security Group の解放
  • 1) デプロイ
    • 1.1) アプリのアップロード
    • 1.2) 環境変数の設定
    • 1.3) アプリの起動

順次見ていきましょう。

デプロイ準備

JDK, Maven のインストール

このアプリはJavaのアプリなのですが,CFの標準的なデプロイ方法では,Javaのアプリはコンパイルしてからデプロイすることになっています。そこでまず,Javaアプリのビルドを行うツールを整備します。

【OpenJDK 7】

$ sudo apt-get install openjdk-7-jdk -y

確認:

$ which javac
/usr/bin/javac

【Maven 3】

$ sudo apt-get install maven -y

確認:

$ which mvn
/usr/bin/mvn

ソースコードの取得&アプリのビルド

アプリのソースコードをGitHubからcloneします。

$ git clone https://github.com/cloudfoundry-community/postgresql-cf-service-broker.git

アプリをビルドします。

$ cd postgresql-cf-service-broker
$ mvn package

Org, Space の作成

このアプリをデプロイするための Org と Space を作成します。

アプリを service broker として使う場合,現状ではCFの管理者(admin)権限が必要です。従ってアプリ自体も admin ユーザーとしてデプロイする方が理に適っています。今回は特に,service broker アプリをデプロイするための Org と Space を作ります。既存の Org, Group にこのアプリをデプロイする方は,この操作は必要ありません。

$ cf create-org admin
$ cf create-space svcs

Application Security Group の解放

CFには Application Security Groups という機能があります。これは,アプリから接続できるIPアドレスを制限するもので,bosh-lite のデフォルトでは,アプリはプライベート・アドレス (10..., 192.168..*) には接続できません。

今回構築した PostgreSQL (の Docker Image) は 192.168.. 上に存在するので,そこに接続できるように application security group を設定する必要があります。パブリックIPアドレス上に PostgreSQL のインスタンスを構築した方は,この作業は不要です。

【既存の security group】

$ cf security-groups
Getting security groups as admin
OK

     Name              Organization   Space
#0   public_networks
#1   dns

パブリック・ネットワーク以外は,DNSにしかアクセスできないようになっています。

【security group の作成】

先ほど構築した PostgreSQL インスタンスにアクセスできるルールを持つ application security group を作成します。

まずはルール(JSON形式)を記述したファイルを作成します。

$ emacs postgresql-cf-service-broker.security-groups.json
...
$ cat postgresql-cf-service-broker.security-groups.json
[
    {
    "protocol": "tcp",
    "destination": "192.168.xxx.xxx",
    "ports": "5432" 
    }
]

次に,CF cli を使って,そのルールを持つ application security group をCF環境に登録します。Security group の名前は postgresql-cf-service-broker-security-groups としました。

$ cf create-security-group postgresql-cf-service-broker-security-groups postgresql-cf-service-broker.security-groups.json

確認:

$ cf security-groups
Getting security groups as admin
OK

     Name                                           Organization   Space
#0   public_networks
#1   dns
#2   postgresql-cf-service-broker-security-groups

【Default Running Security Group に bind】

今登録した application security group を Default Running Security Group に bind します。

Default Running Security Group は,全てのアプリの実行(running)時に適用される security group です。この設定をすることで,全てのアプリが,実行時に先ほど作った PostgreSQL インスタンスに接続可能になります。

$ cf bind-running-security-group postgresql-cf-service-broker-security-groups

確認:

$ cf running-security-groups
Acquiring running security groups as 'admin'
OK

public_networks
dns
postgresql-cf-service-broker-security-groups

以上でようやくアプリをデプロイする準備が整いました。

デプロイ

*本節の操作は基本的に https://github.com/cloudfoundry-community/postgresql-cf-service-broker/blob/2e550a065374ffab1a999657c3dabdaa312aa61b/README.md を参考にしました。

アプリの push

CF環境にアプリを登録し,アップロードします。

通常,CFでは,アプリはpushされると自動的に起動されますが,今回のアプリは起動前に環境変数の設定が必要なので,この段階ではまだ起動しません。そのために cf push コマンドで --no-start というオプションを指定します。

また,Java アプリの場合は,ディレクトリーではなく war ファイルをデプロイするので,先ほどのビルドで生成された war ファイルを -p オプションの引数として指定します。

さらに,README では特にアプリのメモリサイズは指定されていませんが,何度か試した結果デフォルトの256MBではメモリが逼迫しそうだったので,メモリサイズを512MBにしました。

$ cf push postgresql-cf-service-broker -p target/postgresql-cf-service-broker-2.3.0-SNAPSHOT.jar -m 512m --no-start

環境変数の設定

README に沿って,アプリの実行環境の環境変数を設定します。

$ cf set-env postgresql-cf-service-broker MASTER_JDBC_URL 'jdbc:postgresql://192.168.xxx.xxx:5432/cf?user=cf&password=xxxxxxxx'
$ cf set-env postgresql-cf-service-broker JAVA_OPTS "-Dsecurity.user.password=xxxxxxxx" 

ここで少し調査が必要だったのは,JDBCのURL形式におけるユーザー名とパスワードの扱いです。 DATABASE_URL (<scheme>://<username>:<password>@<host>:<port>/<database> と異なり,JDBCのURLでは jdbc:<scheme>://<host>:<port>/<dbname>?user=<username>&password=<password> となっていることがわかるまで,しばらく時間が必要でした。

cf. https://devcenter.heroku.com/articles/heroku-postgresql#spring-java

環境変数設定の確認:

$ cf env postgresql-cf-service-broker
Getting env variables for app postgresql-cf-service-broker in org admin / space svcs as admin...
OK

System-Provided:

{
 "VCAP_APPLICATION": {
  "application_name": "postgresql-cf-service-broker",
  "application_uris": [
   "postgresql-cf-service-broker.10.244.0.34.xip.io" 
  ],
  "application_version": "82587e6c-b7c8-410f-bbba-5766d611c4f6",
  "limits": {
   "disk": 1024,
   "fds": 16384,
   "mem": 512
  },
  "name": "postgresql-cf-service-broker",
  "space_id": "a74d2274-c546-49f4-ad38-499df073d499",
  "space_name": "svcs",
  "uris": [
   "postgresql-cf-service-broker.10.244.0.34.xip.io" 
  ],
  "users": null,
  "version": "82587e6c-b7c8-410f-bbba-5766d611c4f6" 
 }
}

User-Provided:
JAVA_OPTS: -Dsecurity.user.password=xxxxxxxx
MASTER_JDBC_URL: jdbc:postgresql://192.168.xxx.xxx:5432/cf?user=cf&password=xxxxxxxx

No running env variables have been set

No staging env variables have been set

アプリの起動

$ cf start postgresql-cf-service-broker
...
requested state: started
instances: 1/1
usage: 512M x 1 instances
urls: postgresql-cf-service-broker.10.244.0.34.xip.io
last uploaded: Mon Jun 1 01:56:13 +0000 2015
stack: lucid64

     state     since                    cpu    memory           disk      details
#0   running   2015-06-01 10:57:57 AM   0.0%   348.9M of 512M   0 of 1G

state が runnning になればOKです。

Service Broker 化

通常のアプリと異なり,動作確認をするためには,アプリの起動後にこれを service broker としてCF環境に認識させる必要があります。

本節の手順の概要は以下の通りです:

  • 1) Service Broker として登録
  • 2) Marketplace に公開

Service Broker として登録

まず,アプリをCFに service broker として登録します。

$ cf create-service-broker postgresql-cf-service-broker user xxxxxxxx http://postgresql-cf-service-broker.10.244.0.34.xip.io

Marketplace に公開

*本節の手順は http://docs.cloudfoundry.org/services/access-control.html を参考にしました。

create-service-broker で登録された service broker は,デフォルトで非公開になっています。従って,この service broker が提供するサービスをCF環境の全ユーザーが使えるようにするには,この service broker のサービス・プランを,サービス名とともに公開する必要があります。

$ cf enable-service-access PostgreSQL -p "Basic PostgreSQL Plan"

確認:

$ cf service-access
Getting service access as admin...
broker: postgresql-cf-service-broker
   service      plan                    access   orgs
   PostgreSQL   Basic PostgreSQL Plan   all
$ 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.

* These service plans have an associated cost. Creating a service instance will incur this cost.

TIP:  Use 'cf marketplace -s SERVICE' to view descriptions of individual plans of a given service.

意図した通りに公開されています。なお,このサービス・プランは無料ではないとの警告が出ていますが,今回は検証環境用に自分で構築したサービスなので特に問題はありません。

動作確認

以下,サービスの作成〜実際にアプリと結合しての動作確認については,前回の記事の この箇所 以降をごらんください。

今回使用した環境

(前回 と全く同じです。)