まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:custom

前2回の続きです:
IBM Bluemix にカスマムサービスを追加する(1/3)
IBM Bluemix にカスマムサービスを追加する(2/3)


前回作成した REST API を実際に IBM Bluemix のカスタムサービスとして登録し、利用するまで(正確には使用を終えてカスタムサービスから削除するところまで)の手順を紹介します。なおこの手順はコマンドラインツールである cf が必要になるので、インストールしていない場合は各自の環境にあった cf をあらかじめダウンロード&インストールしておいてください:
https://github.com/cloudfoundry/cli/releases


また、今回カスタムサービスとして登録する REST API は前回紹介した app.js が https://dotnsf-operation.mybluemix.net/ にデプロイされて動いているものとします。以下の説明でのこのホスト名部分を実際にみなさんがデプロイしたホスト名に合わせて読み替えてください:
2017021401

2017021401


まず最初に、以下で登録するカスタムサービスをバインドして動作確認するためのランタイムを用意しておきます。動作確認用のアプリケーション(後述)を PHP で用意したので、IBM Bluemix 上に PHP のランタイムを1つ作成します(以下の例では teyande-php-env という名前で作成しています)、なおこの段階ではサービスは何もバインドしないでください:
2017021402


このランタイムに以下の内容の PHP アプリケーションをプッシュします:
https://github.com/dotnsf/phpEnv


上記アプリケーション(index.php)はシンプルに「ランタイムサーバー上の全環境変数とその値を表示する」というアプリケーションです。プッシュ後にサーバーにアクセスすると以下のような画面になります。この時点ではサービスを1つもバインドしていないので、環境変数 VCAP_SERVICES の値は空オブジェクトを示す "{}" となっていることが確認できるはずです:
2017021403


ここまでで準備は完了です。では前回紹介したサービスを IBM Bluemix のカスタムサービスとして登録した上でインスタンス化し、このランタイムにバインドした上で、この環境変数がどのように変わるかを確認してみます。

コマンドプロンプトかターミナルを起動し、上記の PHP ランタイムと同じデータセンター(この場合は US-SOUTH)の自分の組織に cf コマンドでログインします:
2017021404


カスタムサービスを利用するにためには Cloud Foundry の「サービスブローカー」(カスタムカタログのように理解してください)に登録しておく必要があります。まず現在のサービスブローカー一覧を確認するため "cf service-brokers" コマンドを実行して、この時点では何も登録されていないことを確認します:
2017021301
 ↑"No service brokers found"(何も登録されていません)です


ではサービスブローカーを新規に1つ作成します。以下のパラメータを付けてコマンドを実行します:
> cf create-service-broker サービスブローカー名 認証ユーザー名 認証パスワード サービスの基本URL --space-scoped
2017021302


今回、サービスブローカー名は "dotnsf-operation" とします。認証のユーザー名とパスワードは dotnsf-operation の Catalog API などが実行される時用に指定した auth_user / auth_pass の値を指定します(詳しくは前回の記事参照)。サービスの基本 URL は今回 "https://dotnsf-operation.mybluemix.net" です。そして最後にオプションの "--space-scoped"(同一組織内のユーザーが使えるサービスとするための指定)を加えています。

コマンドが成功したことを確認し、再度 "cf service-brokers" を実行してみます。先程は結果に何も含まれていませんでしたが、今度は直前に作成したばかりの "dotnsf-operation" サービスブローカーが、指定した URL で登録されていることを確認してください:
2017021303


これで dotnsf-operation API がカスタムカタログに登録された状態になりました。ただ IBM Bluemix のウェブ UI ではカスタムカタログを表示する画面が存在していないので、この時点ではまだウェブ UI には現れませんが、cf からは同様にインスタンスを作成することができるようになっています。

というわけで、続けて cf でこのサービスをインスタンス化してみます:
> cf create-service サービスブローカー名 プラン名 サービス名

サービスブローカー名は dotnsf-operation の Catalog API(GET /v2/catalog) 内で定義したもの(今回の場合は dotnsf-operation-service)を指定します。プランも同様に Catalog API 内で定義したもの(今回は "free" と "enterprise" の2つ)の中から指定できますが、今回は "free" を指定しています。最後に IBM Bluemix 内でのサービス名として "dotnsf-operation-1" と指定しています:
2017021304


ここまでの手続きが完了すると、dotnsf-operation サービスがインスタンス化され、ウェブ UI の利用中サービス一覧の中にも表示されるようになります:
2017021301


この時点でサービスを選択し、管理タブを開くと Dashboard API で定義した内容が表示されるはずです(https で Dashboard API にアクセスできることが条件です):
2017021000


ではこのサービスを最初に作成した PHP ランタイムにバインドしてみましょう。PHP ランタイムの画面に移動し、接続タブの「既存に接続」をクリックします:
2017021302


現在利用中のサービスインスタンスの一覧が表示されます。その中に "dotnsf-operation-1" という名前のサービスが含まれているはずなので、これを選択して「接続」をクリックします。そしてこの内容をランタイムの環境変数にも反映させるため「再ステージング」します:
2017021303


改めて同ランタイムの接続タブを参照すると、"dotnsf-operation-1" サービスが追加されていることを確認できます。ここで「資格情報の表示」をクリックします:
2017021304


今回の dotnsf-service の Bind API では credentials 情報として uri だけを追加していました。そのためこのサービスインスタンスの資格情報にも uri 1つだけが credentials 情報として表示されていることが確認できるはずです:
2017021305


改めてランタイムのトップ画面にアクセス(リロード)します。今回は先程と異なり dotnsf-operation-1 サービスがバインドされているので、環境変数 VCAP_SERVICES は空オブジェクトではなく、dotnsf-operation-1 の情報が表示されているはずです。credentials 情報も先程確認したものと同じものが表示されています:
2017021306



・・・というわけで、IBM Bluemix のカスタムサービスを作成して、登録して、インスタンス化して、ランタイムとバインドして環境変数に反映させる、という一連の作業ができることを確認できました!

最後に使い終わったサービスブローカーを削除する手順を紹介しておきます。まず(同サービスブローカーを使っているランタイムからのバインドを全て解除した上で)サービス一覧画面からインスタンス化されたサービスを削除します:
2017021305


サービスが削除されるとウェブ UI からは見えなくなります。が、まだサービスブローカーには登録されているので、以下の cf コマンドでサービスブローカーからも削除します:
> cf delete-service-broker サービスブローカー名
2017021306


このコマンドが成功すると、サービスブローカー一覧からも削除されます。念のため "cf service-brokers" コマンドで確認します:
2017021307




久しぶりの超大作ブログとなり、3回に分けて紹介しましたが、IBM Bluemix のカスタムサービスを作るために実装しないといけない内容や、実装後の登録方法などを紹介できたつもりです。自分が作った REST API を IBM Bluemix に統合して使いたい場合や、公式なサードパーティ API としての登録を検討する場合に必要となる実装がどんなものかを説明しました。

今回紹介した内容はあくまで「同一組織内でのみ有効なカスタムサービス」の登録方法および手順の紹介でしたが、全 IBM Bluemix ユーザー向けに実装する場合であっても同様の API 実装は必要になります。そういったエコシステムを活性化する上での役立つ情報になれば幸いです。


(参考)
 https://www.ibm.com/blogs/bluemix/2017/01/extend-bluemix-service-broker/

IBM Bluemix には Watson や IoT など、数多くの IBM /サードパーティ API がサービスとして登録されており、利用者はこれらを活用してアプリケーションの高速な開発ができるようになります:
2017021301


またランタイム(アプリケーションサーバー)とサービスをバインド(紐付け)することで、ランタイムの環境変数からサービスへの接続情報(ユーザー名、パスワードなど)を動的に参照することができるようになります。これによって接続情報を外出しする必要がなくなり、非常にセキュアな外部 API 連携が可能になる仕組みが提供されています:
2017021302


さて、このような IBM Bluemix 環境において、「標準では登録されていない API をサービスとして利用したい」という要望を(少なくとも自分が知る限りでも何件か)いただいています。もちろんサードパーティ製 API として正規に登録する手順というものもあります。ただこちらは Cloud Foundry Service として最低限必要ないくつかの API(後述)を実装した上で申請し、条件や審査といったプロセスを経て IBM Bluemix サードパーティサービスとして登録されるものになります。この正規の手順について、詳しくはこちらを参照ください:
https://developer.ibm.com/marketplace/docs/vendor-guide/how-do-i-integrate/integrating-bluemix/


一方、いくつかの制約事項がある中で、この申請や審査といった手順を通さずに自身のサービスを IBM Bluemix のカスタムサービスとして利用可能にする方法もあり、以下のブログで紹介されています:
https://www.ibm.com/blogs/bluemix/2017/01/extend-bluemix-service-broker/


上記エントリによると、その制約事項の中で大きなものは以下の4つです:
(1) IBM Bluemix の Web UI には 100% 統合されない
(2) 同一組織の中だけで利用可能なサービスとして登録される
(3) Web API 自体は https で運用されている必要がある(オプション)
(4) 課金の仕組みが必要であれば別途実装する


(1) について補足すると、IBM Bluemix はオープンソース製品である Cloud Foundry をベースに IBM が機能拡張したものなのですが、(あまり知られていませんが)Web ブラウザから操作できるようにしているのも IBM の拡張によるものです(CloudFoundry 自体は cf というコマンドラインツールを使って操作するものです)。この Web の UI は Bluemix のサービスラインナップとも密に統合されており、以下で紹介するカスタムサービスで追加したサービスは Bluemix Web UI には反映される部分とされない部分が出てきてしまいます(例えば追加したカスタムサービスはカタログ画面には表示されません)。基本的には cf ツールを使ってサービスを追加してバインドして・・という手順をとって実行する前提の方法になります。

(2) はカスタムサービスの利用可能な範囲についてです。通常の Bluemix サービスは Bluemix ユーザー全員に公開されて利用可能になりますが、以下の方法で追加したカスタムサービスの場合は同一の組織内(または同一のスペース内)だけで利用可能なサービスになります。異なる組織のユーザーからは利用できない方法であることをご了承いただきます。

(3) はその API 自体が http に加えて https でも稼働する必要がある、という条件です。この (3) に関しては(動くか動かないかだけの条件であれば、http だけでも動くので)必須ではないのですが、Bluemix の Web UI から参照するページの一部が https 必須になっており、https 非対応だとそのページが正しく表示されない、という問題が生じるのでした。繰り返しますがそのページがブラウザから正しく表示されるかどうかと、API として実行できるかどうかは別の問題なので、その意味では必須ではない(が、対応されている方が好ましい)とお考えください。要するにピュアな Cloud Foundry サービスとして認識させるための要件ではなく、IBM Bluemix 統合のための要件であるという意味です。

(4) は今回作成するカスタムサービスは(複数のプランを実装することはできますが)Bluemix 上では無料サービスとして動く、ということを意味しています。課金が必要な場合は正規の手順でサードパーティサービスとして登録いただくか、あるいは別途課金の仕組みをサービス側に実装する必要がある、ということです。


上記のような制約事項がある中で、自分で作った Web サービスの API を IBM Bluemix のカスタムサービスとして統合する手順を紹介します。全体的に長くなりそうなので紹介は3回に分け、第一回目である今回は上記の解説に加えて「自分で作った(IBM Bluemix に統合するためのカスタマイズをする前の) Web サービス API 」の紹介をすることにします。もちろん最終的には皆さん自身で作った API をカスタマイズしていただくことになると思いますが、そのカスタマイズ前の題材の紹介であると理解してください。


Web API は非常にシンプルな、「四則演算を行う API 」とします。今回用意したサンプルは Node.js で実装されています:
https://github.com/dotnsf/dotnsfOperation/blob/master/app0.js


今回対象とする上記コードは以下のような内容です。まあ普通の Node.js + Express による API 定義(/:operation/:x/:y)に加え、/ にアクセスがあった場合の表示と、/doc に簡易ドキュメントを用意しています:
//. app0.js
var express = require( 'express' ),
    cfenv = require( 'cfenv' ),
    appEnv = cfenv.getAppEnv(),
    app = express();


//. Service APIs
app.get( '/', function( req, res ){
  var html = '<title>My Broker</title>';
  html += '<h1>My Broker</h1>';
  html += '<p>ドキュメントは<a target="_blank" href="./doc">こちら</a>を参照ください</p>';
  res.writeHead( 200, [ { 'Content-Type': 'text/html; charset=UTF8' } ] );
  res.write( html );
  res.end();
});

app.get( '/:operation/:x/:y', function( req, res ){
  var operation = req.params.operation;
  var x = parseFloat( req.params.x );
  var y = parseFloat( req.params.y );
  var z = 0;

  if( operation == 'plus' ){
    z = x + y;
  }else if( operation == 'minus' ){
    z = x - y;
  }else if( operation == 'multiply' ){
    z = x * y;
  }else if( operation == 'divide' ){
    z = x / y;
  }

  res.writeHead( 200, [ { 'Content-Type': 'text/plain' } ] );
  res.write( '' + z );
  res.end();
});

app.get( '/doc', function( req, res ){
  var html = '<title>My Operation Document</title>';
  html += '<h1>My Operation Document</h1>';
  html += '<p>This is a document for my operation</p>';
  html += '<hr/>';
  html += '/plus/x/y => return ( x + y )<br/>';
  html += '/minus/x/y => return ( x - y )<br/>';
  html += '/multiply/x/y => return ( x + y )<br/>';
  html += '/divide/x/y => return ( x / y )<br/>';
  res.writeHead( 200, [ { 'Content-Type': 'text/html; charset=UTF8' } ] );
  res.write( html );
  res.end();
});

var service_port = appEnv.port ? appEnv.port : 1337;
app.listen( service_port );
console.log( "server starting on " + service_port );

肝となる API (/:operation/:x/:y)は4つの機能をもち、それぞれ以下のような URI で実装されます:
URI関数の処理内容
/plus/x/yx + y を実行した結果を返す/plus/2.3/3 → 5.3
/minus/x/yx - y を実行した結果を返す/minus/2.3/3 → -0.7
/multiply/x/yx * y を実行した結果を返す/multiply/2.5/-3 → -7.5
/divide/x/yx / y を実行した結果を返す/divide/5/4 → 1.25


実際に上記の URI に数値パラメータを入れてアクセスすると、実行結果を(text/plain で)画面に表示します:
2017021303


また、API とは別にドキュメントルートにアクセスがあった場合のページと、
2017021401


API の簡易ドキュメントページが用意されています:
2017021402


ここまでのアプリケーション(というか API)は上記の app0.js をそのまま Node.js で実行すれば動かすことができますので、興味がある方は実際に試してみてください。

そして次回は、この app0.js に対して IBM Bluemix のカスタムサービスとして統合するための変更を加える、その内容や手順を紹介します。IBM Bluemix(Cloud Foundry) のサービスとして利用するためには(サービスのインスタンス化や削除、バインド/アンバインドの仕組みを実現するためには)どのような実装が必要になるのか、といった辺りを紹介する予定です。


(追記)続きはこちら:
http://dotnsf.blog.jp/archives/1064347464.html


このページのトップヘ