目次


Node.js クラウド・アプリのシングル・サインオンをスケーリングする

Bluemix の IBM Single Sign On サービスで Redis を使用して認証をスケーリングする

Comments

思い通りの動作をするクラウド・スケーリング・アプリの設計には、アプリのコンポーネントとサービスを適切に水平スケーリングする方法を計画することが求められます。このチュートリアルでは、Bluemix 内で、IBM Single Sign On サービスを利用した単純な Node.js アプリを作成し、このアプリを単一インスタンスから複数のインスタンスへとスケーリングしてから認証しようとすると、どのような事態になるのかを調べます (ヒント: 正常に機能しなくなります)。その後、何が問題だったのかを説明し、Bluemix の Redis Cloud サービスの助けを借りて、その問題を解決するための 1 つの実装について説明します。

最適なスケーリングを実現するには、各プロセスがステートレスになるように設計し、すべてのプロセスで利用できるバッキング・サービスに常にデータを永続化するようにしてください。

このチュートリアルを最後まで終えるために必要となるもの

  • Bluemix アカウント
  • 以下のソフトウェアがインストールされたワークステーション
    • Git (アプリの基本リポジトリーを複製するため)
    • Cloud Foundry コマンド・ライン・インターフェースのバージョン 6.5 以降
    • ※訳注: 原文のリンク先から日本語ページにリダイレクトされます。
    • テキスト・エディター (提供されているソース・コードに簡単な変更を加えるため)

私が作成したデモ・アプリを実行する際は、ユーザー名には clouduser、パスワードには Bluemix123 を入力してサインインしてください。

ステップ 1. 初期アプリをセットアップする

最初のタスクは、Bluemix 内で、Single Sign On サービスを利用した単純な Node.js アプリを作成することです。新規にアプリを作成し、Single Sign On サービス・インスタンスを追加して構成した後、作成したアプリにこのサービスをバインドして、コールバック URL を指定します。

  1. Bluemix にログインし、「CREATE AN APP (アプリの作成)」をクリックして、アプリのタイプとして「WEB」を選択します。
  2. 「SDK for Node.js」をクリックしてから、「CONTINUE (続行)」をクリックします。
  3. アプリに一意の名前を指定します。例えば、scaleSSO の後にハイフンを続け、その後に名前を一意にするために自分のイニシャルと日付を続けます (例: scaleSSO-TOR0815)。アプリ名の例として「scaleSSO-TOR0815」を指定した画面のスクリーンショット
    アプリ名の例として「scaleSSO-TOR0815」を指定した画面のスクリーンショット

    このチュートリアルの残りでは、ここで入力した名前で <your app name> を置き換えてください。
  4. 「FINISH (完了)」をクリックします。Bluemix がアプリをステージングして稼働状態にしている間、待ちます。
  5. 「VIEW APP OVERVIEW (アプリの概要の表示)」をクリックします (ページの下部にあります)。
  6. アプリの概要ページで、「STOP (停止)」ボタンをクリックし、停止することを確認します。アプリを Single Sign On サービスと連動させるには、その前に特定のコードをアプリに追加する必要があります。
  7. Bluemix のカタログにアクセスして、「Security (セキュリティー)」サービス・セクションにある「Single Sign On」をクリックします。Bluemix のカタログに表示された「Single Sign On」サービス・タイルのスクリーンショッ
    Bluemix のカタログに表示された「Single Sign On」サービス・タイルのスクリーンショッ
  8. 「App (アプリ)」ドロップダウン・リストから「Leave unbound (アンバインドのまま)」を選択して、「CREATE (作成)」をクリックします。サービスが作成されて、サービスの構成マネージャーが起動するまで待ちます。
  9. サービスの名前として「scaleSSOtest」と入力し、「Continue (続行)」をクリックします。サービスの名前として「scaleSSOtest」と入力した画面のスクリーンショット
    サービスの名前として「scaleSSOtest」と入力した画面のスクリーンショット
  10. 新規 ID ソースの追加を促すページで、「Cloud Directory (クラウド・ディレクトリー)」をクリックして単純な ID ソースを追加します。
  11. プラス・アイコンをクリックし、新規ユーザーを追加します。
  12. 「Add User (ユーザーの追加)」ダイアログ・ボックスで、任意のユーザー名およびパスワードと併せて、その他のプロファイル属性を入力します。「Save (保存)」をクリックしてユーザーを追加してから、「Save (保存)」をクリックして ID ソースの編集パネルを閉じます。ユーザーを追加するための UI のスクリーンショット
    ユーザーを追加するための UI のスクリーンショット
  13. 「Back to Dashboard (ダッシュボードに戻る)」をクリックします。ダッシュボードで、作成したアプリをクリックしてアプリの概要ページを開きます。
  14. アプリの概要ページで、「BIND A SERVICE OR API. (サービスまたは API のバインド)」をクリックします。
  15. 作成した Single Sign On サービスに対応するラジオ・ボタンを選択し、「ADD (追加)」をクリックします。Single Sign On サービスを選択して「ADD (追加)」ボタンをクリックする画面のスクリーンショット
    Single Sign On サービスを選択して「ADD (追加)」ボタンをクリックする画面のスクリーンショット
  16. 「Back to Dashboard (ダッシュボードに戻る)」リンクの右にある逆 V 字型アイコンをクリックし、ドロップダウン・メニューから「Single Sign On」サービスを選択します。アプリとサービスを示すメニュー・ナビゲーションから「Single Sign On」を選択する画面のスクリーンショット
    逆 V 字型アイコンをもう一度クリックして、ドロップダウン・メニューを非表示にします。
  17. Single Sign On 構成マネージャーの右上にある「INTEGRATE (統合)」ボタンをクリックします。
  18. 「Return-to URL (戻り先 URL)」フィールドに、次の URL を入力します。

    https://<your app name>.mybluemix.net/auth/sso/callback

  19. 「Save (保存)」ボタンをクリックし、「OK」をクリックします。
  20. 「Back to Dashboard (ダッシュボードに戻る)」をクリックします。

初期アプリのセットアップは、これで完了です。

ステップ 2. アプリのコードに変更を加えて再デプロイする

このステップでは、Single Sign On を使用するように構成された単純な Node.js アプリが格納されている、IBM DevOps Services プロジェクトを複製します。このコードに変更を加え、自分の既存のアプリに対して Single Sign On を使用するようにした後、変更後のコードを Bluemix にプッシュしてアプリをデプロイします。

  1. ローカル・ワークステーションでコマンド・プロンプトを開き、以下のコマンドを実行します。

    git clone https://hub.jazz.net/git/timro/scaleSSO-base <your app name>

  2. テキスト・エディターを使用して、app.js ファイルを更新します。このファイルは、git clone によって作成された新しいディレクトリー内にあります。ファイルの 49 行目にある callback_url を、ステップ 1 (サブステップ 18) で指定した戻り先 URL の値と一致するように変更します。
    // you MUST change the host route to match your application name
    var callback_url = 'https://<your app name>.mybluemix.net/auth/sso/callback';
  3. manifest.yml ファイルを更新して、アプリの host プロパティーと name プロパティーの値を置き換えます。
    applications:
    - disk_quota: 1024M
      host: <your app name>
      name: <your app name>
      path: .
      domain: mybluemix.net
  4. コマンド・ラインの作業ディレクトリーをこのプロジェクトのディレクトリーに変更し、以下のように Cloud Foundry コマンド・ライン・ツールを使用して Bluemix にログインします。

    cf login -a https://api.ng.bluemix.net

  5. 以下のコマンドを実行して、Bluemix 内のアプリを更新およびデプロイします。

    cf push

  6. cf push コマンドによって出力されるステージング・メッセージを観察します。デプロイが完了すると、アプリが起動し、アプリのインスタンスの状態が「running」として表示されます。 アプリの起動とインスタンスの詳細が示された、cf コマンド出力のスクリーンショット
    アプリの起動とインスタンスの詳細が示された、cf コマンド出力のスクリーンショット

これで、アプリをテストできる状態になりました。

ステップ 3. Bluemix 内でアプリをスケーリングする

このステップでは、アプリの認証をテストします。まずは、アプリを単一のインスタンスでテストし、次に 2 つ目のインスタンスを追加してテストします。

  1. ブラウザーの新しいウィンドウまたはタブで、アプリの URL https://<your app name>.mybluemix.net を開き、「Login (ログイン)」ボタンをクリックします。 Single Sign On サービスを構成するときに「Cloud Directory (クラウド・ディレクトリー)」に追加したユーザー名とパスワードを入力して、「Login (ログイン)」をクリックします。初期パスワードを変更するよう促されたら、それに従って新しいパスワードに変更します。 ユーザーの初期パスワードの変更を促す、Single Sign On サービスのダイアログ・ボックスのスクリーンショット
    ユーザーの初期パスワードの変更を促す、Single Sign On サービスのダイアログ・ボックスのスクリーンショット

    認証済みユーザー名と認証のレルムを組み合わせた、「Hello, scalessotest-nw2nz9occb-ck11.iam.ibmcloud.com/www.ibm.com/clouduser!」のような挨拶メッセージが表示されます。これは、ユーザーがこのアプリのインスタンスに対する認証に成功したことを意味します。
  2. Bluemix ダッシュボードに戻って、アプリをスケーリングします。アプリの概要を開き、「Instances (インスタンス)」の下にある「^」ボタンをクリックしてインスタンス数を 2 に増やした後、「SAVE (保存)」をクリックします。
  3. Bluemix によって、2 つ目のインスタンスが起動されます。「APP HEALTH (アプリの正常性)」セクションにマウスのカーソルを合わせると、2 つのインスタンスがアクティブになっていることが示されます。
  4. Single Sign On をテストするために使用したブラウザー・セッションを終了し、ブラウザーの新しいウィンドウまたはタブを開きます。https://<your app name>.mybluemix.net にアクセスして、「Login (ログイン)」ボタンをクリックします。Single Sign On に対する認証を行い、個人情報の共有を許可するかどうかを尋ねられたら同意します。
  5. 今度は単純な挨拶メッセージは表示されず、おそらく「404 not found」ページ、または「Cannot GET /auth/sso/callback?scope=openid&code=EuPWIJBuCQdDjFbnGtgIAUsCiacMdE」のようなエラー・メッセージが表示されるはずです。

ステップ 4. テストの結果を理解する

この単純なアプリは、単一のインスタンスのときには認証の問題はありませんでしたが、インスタンスを 2 つに増やすと問題が発生しました。それは、このアプリが「The Twelve-Factor App (アプリの開発に必要な 12 要素)」の方法論に従っていないためです。具体的には、要素 6 の「アプリケーションを 1 つもしくは複数のステートレスなプロセスとして実行する」に違反しています。

この不慮の失敗は、Bluemix 内の Node.js アプリが Passport および express-session ミドルウェアを使用して、Bluemix の Single Sign On サービスに対して OpenID Connect のサポートを提供する方法に原因があってもたらされた結果です。express-session サービスでは、セッション・データをインメモリーで保持するため、2 つのインスタンスのうち、どちらか一方しかセッション・データを使用することができません。従って、ユーザーの認証後に、Single Sign On サービスがブラウザーをコールバック URL にリダイレクトするときに、ブラウザーがもう一方のインスタンスにルーティングされたとすると、Express Web エンジンは認証済みユーザーのセッション ID を参照できず、404 メッセージを表示するというわけです。

以下の図に、アプリのインスタンス 0 でしかセッションのデータを使用できない様子を示します。

アプリのインスタンス 0 でしかセッション ID 1 を使用できないことを示す図
アプリのインスタンス 0 でしかセッション ID 1 を使用できないことを示す図

それでは、これに対するソリューションは何でしょう?「The Twelve-Factor App (アプリの開発に必要な 12 要素)」の要素 6 ではさらに、「永続化する必要のあるすべてのデータは、ステートフルなバッキング・サービス (一般的にはデータベース) に格納しなければならない。」と言っています。GitHub にある express-session のドキュメントに、これに対応したいくつかのバッキング・ストアがリストアップされています。これから、キー・バリュー型のインメモリー・キャッシュを提供する Redis を使用して、この永続化機能を実装します。このように変更すると、express-session のセッション・データが特定のインスタンスのメモリーから、すべてのインスタンスで使用できる永続ストアに移されることになります。

Redis を使用して永続化機能を実装した後、セッション・データがすべてのインスタンスで使用可能になることを示す図
Redis を使用して永続化機能を実装した後、セッション・データがすべてのインスタンスで使用可能になることを示す図

ステップ 5. Redis を使用してセッションの永続化機能を追加する

Bluemix の Redis Cloud サービスは、アプリと同じ SoftLayer 環境にホストされているため、最小限の応答時間でこのバッキング・サービスにアクセスすることができます。

  1. Bluemix でカタログにアクセスし、「Data & Analytics (データおよび分析)」カテゴリーから「Redis Cloud」を選択します。Bluemix カタログの「Data and Analytics (データおよび分析)」カテゴリーにある「Redis Cloud」タイルのスクリーンショット
    Bluemix カタログの「Data and Analytics (データおよび分析)」カテゴリーにある「Redis Cloud」タイルのスクリーンショット
  2. 作成した Single Sign On アプリを「App (アプリ)」のドロップダウン・リストから選択し、「Selected Plan (選択済みプラン)」のドロップダウン・リストから「30MB」を選択します (このプランには料金が請求されません。しかも、このチュートリアルのセッションに対しては十分なスペースがあります)。
  3. 「CREATE (作成)」をクリックしてサービスを追加し、アプリにバインドします。
  4. 「RESTAGE (再ステージ)」をクリックして、サービスをアプリに追加するプロセスを完了させます。
  5. アプリのソース・コードのローカル・コピーに含まれる package.json で、dependencies セクションの 14 行目にコンマを追加し、それに続けて 2 つのエントリーを追加します。
      "passport-idaas-openidconnect": "1.0.x",
      "connect-redis": "2.4.x",
      "redis": "0.12.1"
    },
  6. app.js で、17 行目の require セクションに redisconnect-redis を追加します。
    var OpenIDConnectStrategy = require('passport-idaas-openidconnect').IDaaSOIDCStrategy;
    var redis = require('redis');
    var RedisStore = require('connect-redis')(session);
  7. 29 行目に、Redis Cloud サービスの構成詳細を該当する環境から取得して、このサービスに接続するためのコードを追加します。
    // get configuration for redis backing service and connect to service
    var redisConfig = appEnv.getService(/Redis.*/)
    var redisPort = redisConfig.credentials.port;
    var redisHost = redisConfig.credentials.hostname;
    var redisPasswd = redisConfig.credentials.password;
    
    var redisclient = redis.createClient(redisPort, redisHost, {no_ready_check: true});
    redisclient.auth(redisPasswd, function (err) {
        if (err) {
          throw err;
        }
    });
    
    redisclient.on('connect', function() {
        console.log('Connected to Redis');
    });
  8. 48 行目近くの app.use(cookieParser()) に続く、当初からある app.use(session(... ステートメントをコメントアウトし、Redis をストアとして使用して express-session を初期化するためのブロックで置き換えます。
    // define express-session services, etc. for SSO
    
    app.use(cookieParser());
    // app.use(session({resave: 'true', saveUninitialized: 'true' , secret: 'keyboard cat'}));
    app.use(session({
      store: new RedisStore({ client: redisclient }),
      resave: 'true',
      saveUninitialized: 'true',
      secret: 'top secr8t'
    }));
    app.use(passport.initialize());
    app.use(passport.session());
  9. app.js と package.json をまだ保存していない場合は保存します。
  10. コマンド・ラインから、以下のコマンドを実行してアプリを更新します。

    cf push

  11. アプリが起動した後、recent オプションを指定した Cloud Foundry の logs コマンドを実行します。

    cf logs <your app name> --recent

  12. アプリが起動時に Redis に接続したことを通知するメッセージが出力されていることを確認します。 「Connected to Redis (Redis に接続済み)」というメッセージが示された、アプリのログ出力のスクリーンショット
    「Connected to Redis (Redis に接続済み)」というメッセージが示された、アプリのログ出力のスクリーンショット
  13. manifest.yml ファイルには 1 つのインスタンスしか指定されていないため、アプリは単一のインスタンスで起動します。アプリの概要ページを利用して、インスタンス数を 2 に増やして変更を保存します。
  14. https://<your app name>.mybluemix.net/ にアクセスしてアプリに戻り、ステップ 3 のログイン・テストを繰り返します。

成功です!アプリは 2 つ (あるいはそれ以上) のインスタンスで正常に機能するようになりました。

まとめ

このチュートリアルでは、Bluemix の Single Sign On サービスを利用する単純なアプリを作成し、このアプリを 1 つのインスタンスを実行させた状態でテストし、次に 2 つのインスタンスを実行させた状態でテストしました。2 つのインスタンスを実行させた場合、Node.js express-session ミドルウェアがローカルのインメモリー・ストアを使用するようにデフォルト設定されているため、アプリは失敗しました。

この問題を解決するために、Bluemix の Redis Cloud サービスを利用して、express-session セッションの永続ストアを追加しました。このチュートリアルでは、クラウド・アプリをスケーリングするための重要な設計原則に、プロセス・モデルの観点でハイライトを当てました。最適なスケーリングを実現するには、ステートレスになるように各プロセスを設計し、すべてのプロセスで利用できるバッキング・サービスに常にデータを永続化するようにしてください。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development, セキュリティ, Cloud computing
ArticleID=1023582
ArticleTitle=Node.js クラウド・アプリのシングル・サインオンをスケーリングする
publish-date=12102015