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

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

タグ:serverless

3月31日に IBM Cloud の新しいサーバーレス環境である Code Engine が正式リリースされました:
2021040215


ベータ公開の段階から利用レポートを見かけることもありましたが、価格も公開された状態で改めて利用してみました。その利用手順含めて紹介します。 なお詳しくは後述しますが、この Code Engine は無料枠を使って利用することも可能ですが、ライトプラン契約では利用できません。利用するにはクレジットカードを登録するなどしてベーシックプランに切り替えて利用する必要がある点に注意してください。

【Code Engine とは】
Knative ベースのサーバーレスエンジンです。実行エンジンそのものがコンテナオーケストレーションである Kubernetes 環境上に構築されており、Kubernetes をほとんど意識することなくイベント駆動型のアプリケーションをデプロイ/管理することができると同時に、Kubernetes による自動スケールも行われることで詳しい設定をすることなく安定した稼働を実現することができます。利用料金は後述しますが、「CPU やメモリを実際につかったぶんだけ」課金されます(使わない場合は無料です、加えて無料枠もあるのである程度の稼働は無料枠内で実現できます)。

エンジン上で動かすアプリケーションはコンテナイメージの URL を指定する形でもできますし、イメージ化されていなくてもソースコードが公開されていれば(Dockerfile を用意することで)コンテナをビルドして動かすことも可能です。


【利用手順】
IBM Cloud にログインし、「リソースの作成」を選択します:
2021040201


サービスのカタログ画面が表示されます:
2021040202


検索バーで "Code Engine" を指定して検索します("Code" くらいまで入力すると検索候補に表示されるので、これを選択します):
2021040203


Code Engine の説明ページが表示されます。実際に利用するには「作成の開始」ボタンをクリックします:
2021040204


作成する対象を選択します。ここでは通常の(利用者がウェブブラウザからアクセス可能な)ウェブアプリケーションを作ることにするので「アプリケーション」を選択します。また必要に応じて名前を指定します(デフォルトのままでも構いません):
2021040205


名前確定後に、プロジェクトを選択または作成します。初回ではまだプロジェクトは存在していないので「プロジェクトの作成」をクリックします:
2021040206


画面右にプロジェクト作成のダイアログが表示されます:
2021040207


このダイアログ内でエンジンを稼働させるロケーション(下図では「東京」)、およびプロジェクトを管理するための名称を指定します。最後に「作成」をクリック:
2021040208


作成したプロジェクトが選択された状態になります。続けてこのサーバーレス環境で実行するコードを指定します。コンテナイメージか、(Docker ファイルのある)ソースコードを指定できますが、ここではコンテナイメージを選択しています。コンテナイメージの場合は実際に公開されているコンテナイメージの URL および稼働ポート番号を指定します:
2021040209


※上の例ではコンテナ URL として docker.io/dotnsf/hostname を指定しています。このイメージは私が作って公開しているもので、「8080 番ポートに HTTP アクセスすると /etc/hostname の内容を表示する」というだけのシンプルなアプリケーションです。負荷少なく動くという意味で動作確認向きなので、よかったら使ってください。


コードの指定に続けてランタイムの設定を行います。稼働インスタンス数や各インスタンスのスペックを指定します(複数インスタンスでの稼働に未対応など、スケールアウトしてほしくない場合はインスタンス最大数を1に設定します)。最後に画面右のアプリケーションの「作成」をクリック:
2021040210


画面が切り替わって、プロジェクトのダッシュボードが表示されます。作成直後は「デプロイ中」というステータスになっているはずです:
2021040211


しばらく待つとコンテナのデプロイが完了し、「準備完了」というステータスに切り替わります。またこうなると画面右側に「アプリケーションの URL を開く」というホットスポットが表示されるので、ここをクリックしてアプリケーションにアクセスします:
2021040212


新しいタブが開いて、Code Engine 内で稼働しているアプリケーションにアクセスできました(このアプリケーションの場合はコンテナの /etc/hostname ファイルの内容が表示されています)。特別な設定はしていませんが、ホスト名が自動的に割り当てられて HTTPS でアクセスできています:
2021040213


実際には Kubernetes 上で動いているため、アプリケーションの負荷に応じた自動スケールなどは、ほぼ意識することなく(上記設定だけで)実現できています。Kubernetes を抽象化した形で利用しているため、非常に使いやすいプラットフォームを実現できています。


なお、この Code Engine の料金は以下のようになっていました(2021/04/03 時点)。CPU 稼働時間、利用メモリ、および HTTP リクエスト数について1ヶ月ごとの無料枠と、無料枠を超えて利用した場合の価格が表示されています。このあたりはプロジェクト作成時のインスタンスリソース指定内容とも関わってくるので、アプリケーションの特性に応じてカスタマイズする余地があると思っていますが、試験的に利用する想定であればかなりお手軽な価格帯のように感じます:
2021040214







 

IBM Cloud から提供されているサーバーレス環境である Cloud Functions は、オープンソースの Apache OpenWhisk をベースとした FaaS(Functions as a Service)となっており、数あるサーバーレス環境の中でもよりオープンなものとなっています:
2018082301


IBM Cloud の Cloud Functions の場合、専用のダッシュボードが用意されており、手元に開発環境を用意することなく、ここから(ブラウザから)簡易的なアクションを記述/保存/実行することもできるようになっています:
2018082302
 ↑Node.js でアクションを記述している様子


Cloud Functions はこのブラウザからアクションを記述して実行することができる、というメリットがあるのですが、個人的にはここで記述できるアクションはかなり限定的なものだと思っています。理由はここで編集できるものはアクションとして実行する関数の中身だけであって、関連する設定ファイルを変更したりすることはできません。Node.js では npm という強力な外部モジュール連携の仕組みがあり、npm を使って標準の Node.js では提供されていない機能を呼び出して利用することができます。が、この仕組を使うには npm コマンドであらかじめ利用する機能を導入しておくか、 package.json と呼ばれる設定ファイルを変更して利用を宣言しておく必要があります。実行する関数の記述を変更するだけでは対応しきれない仕組みがあり、この機能に関してはこのウェブブラウザからのアクション記述だけでは使えないのでした。


前置きが長くなりましたが、ここからが本エントリの本番です。この外部パッケージを使ったアクションの記述は CLI(Command Line Interface)を使うことで実現できます。その手順を紹介します。

まず利用したい外部パッケージを明示した package.json を用意します。この例では "request" という HTTP クライアントパッケージ(のバージョン 2.88.0)を利用することと、エントリーポイントとなる JavaScript ファイル名(main.js)を指定しています:
{
  "name": "requestAction",
  "version": "0.0.1",
  "main": "main.js",
  "dependencies": {
    "request": "^2.88.0"
  }
}

次にエントリーポイントとなる JavaScript ファイル main.js を以下の内容で用意します。この中で request パッケージを require して使っている点に注目してください:
// main.js
async function myAction( params ){
  try{
    const result = await getHtml( params );
    return result;
  }catch( err ){
    return err;
  }
}

function getHtml( params ){
  return new Promise( function( resolve, reject ){
    if( params.url ){
      const request = require( 'request' );

      var options = {
        method: 'GET',
        url: params.url,
        encoding: null
      };
      request( options, function( err, res, buf ){
        if( err ){
          reject( { status: false, error: err } );
        }else{
          var html = buf.toString( 'utf-8' );
          resolve( { status: true, html: html } );
        }
      });
    }else{
      reject( { status: false, error: 'parameter url is needed.' } );
    }
  });
}

exports.main = myAction;

このアクションでは実行時に url パラメータを指定します(未指定の場合はエラー)。指定された url の HTML コンテンツを request パッケージを使って取得し、その結果を return します。 なお request() は非同期に実行される関数のため、HTML コンテンツを取得する部分だけを関数化(getHTML())し、この関数は Promise オブジェクトを(実行結果が得られたら)返すようにしています。 なお、このアクションは Node.js V8 で実行することを想定しているので、getHTML() 関数を実行する際に async/await を使って非同期に呼ぶようにしています。

この2つのファイル(package.json と main.js)でアクションに必要な設定と内容が用意できました。なお、同じファイルをこちらに用意しておいたので、興味ある方は参照ください:
https://github.com/dotnsf/requestAction


ではこのアクションを実際に IBM Cloud Functions にデプロイして実行するまでの手順を紹介します。今回用意したスクリプトはブラウザからデプロイするのではなく、 CLI (ibmcloud コマンド)を使ってデプロイする必要があります。というわけで、まだ CLI の導入ができていない場合で最初に CLI をデプロイする必要があります。

【ibmcloud コマンド CLI のインストール&セットアップ】
Windows や MacOS、Linux 向けの ibmcloud コマンドは以下のページからインストールできます:
https://console.bluemix.net/docs/cli/reference/ibmcloud/download_cli.html

Windows はダウンロードしてインストール、MacOS や Linux であれば以下のコマンドを実行してインストールします:
$ curl -sL http://ibm.biz/idt-installer | bash

ibmcloud コマンドが導入できたら IBM Cloud Functions を使うためのプラグインをあわせて導入/更新しておきます:
$ ibmcloud plugin install cloud-functions -r Bluemix

また、このあとのコマンドを実行する際に IBM Cloud にログインしている必要があるため、この段階で ibmcloud コマンドによる IBM Cloud へのログインとターゲットの設定を済ませておきます:
$ ibmcloud login

$ ibmcloud target --cf


【Node.js および npm のインストール】
ブラウザからアクションを記述する場合はクライアントに Node.js をインストールする必要はなかったのですが、今回の CLI を使った手順ではローカルで npm コマンドを実行することになります。つまり Node.js や npm がインストールされた環境が必要です。まだ導入していない場合は、公式ページなどから(V8 以上の Node.js の)ダウンロード&インストールを済ませておいてください:
http://nodejs.org/


【ライブラリのインストール、zip ファイル化、デプロイ】
まず package.json の内容にしたがってパッケージ(今回のケースでは request パッケージ)とその依存ライブラリをインストールします:
$ npm install

次にこのディレクトリ内の全ファイルを zip ファイルにまとめます。IBM Cloud Functions では zip ファイルでまとめたアクションをデプロイすることができるため、ここで実行に必要な全てのファイルが揃った zip ファイル(myAction.zip)を作成します:
$ zip -r myAction.zip *

そして、この zip ファイルをアクションとして ibmcloud コマンド CLI でデプロイします:
$ ibmcloud wsk action create requestAction myAction.zip --kind nodejs:8

↑この例ではアクションの名前を "requestAction" として myAction.zip をデプロイしています(アクション名やファイル名は任意です)。なおこの方法でアクションをデプロイする場合、--kind オプションで実行ランタイムの種類を指定する必要があります。今回は Nodejs V8 を指定しています(V6 では未対応の機能を使っているためです)。 また新規にデプロイする場合はこのコマンドになりますが、アクションを変更して同名で上書きデプロイする場合は上記の create 部分を update に変更して実行してください。


【動作確認】
デプロイしたアクションは CLI でもダッシュボード画面からも、どちらでも動作を確認することができます。まずはダッシュボードで確認してみます。ダッシュボードから Actions メニューを選び、アクション一覧の中にデプロイしたアクション(requestAction)が含まれていることを確認します:
2018082401


デプロイしたアクションを選択します。zip ファイルという特殊(?)な方法でデプロイしたので、この画面から直接コードを参照したり変更することはできないのですが、実行(Invoke)したり、実行時の入力パラメータを編集することはできます。今回のアクションは url パラメータを受け取って動作するので、実行前にパラメータを指定します。"Change Input" をクリックします:
2018082402


入力パラメータを編集する画面が表示されます。今回は何らかの url パラメータを指定したいので、
{ "url": "http://dotnsf.blog.jp/" }
のように何らかの実在する(パスワード等なしで参照できる)URL を url パラメータに指定して "Apply" をクリックします:
2018082403
 ↑このブログの URL を指定した例


改めて "Invoke" をクリックして、このアクションを先程の入力パラメータで実行します:
2018082404


アクションが実行され、少し待つと結果の JSON が表示されます。正しく実行されていれば status = true と、指定した URL から取得した HTML が返ってくることが確認できます:
2018082405


全く同じことを ibmcloud CLI からも実行してみます。CLI の場合は以下のようにパラメータを指定して実行し、その実行結果を確認します(実行そのものは --result オプションなしでも行えますが、--result オプションをつけると実行結果が同じ画面に出力され、確認ができます)。期待していたような HTML が表示されれば確認成功です:
$ ibmcloud wsk action invoke requestAction --param url "http://dotnsf.blog.jp/" --result

2018082406


とりあえず、本来の目的であった「Cloud Functions で npm 外部パッケージを使ったアクションを実行する」方法については実現できそうだ、という目処がたちました。


このページのトップヘ