2016.03.04
Swiftでサーバレスアーキテクチャ 〜 OpenWhiskを動かしてみる
こんにちは。F.S.です。
前回のFirebaseに続き、今回もバックエンドサービスの話題です。
2014年11月のAWS Lambdaの発表(2015年4月に正式公開)により、サーバーレスアーキテクチャという考え方が登場しました。
サーバレスアーキテクチャとは、イベント駆動でクラウド上に登録したコードを実行できるもので、利用者がコードを実行するためのサーバインスタンスを構築・管理する必要がありません。
BaaSと比較されることが多いですが、BaaSはサービス提供者側の制約のもとに利用するもので自由度は少ない一方、サーバレスアーキテクチャは利用者がバックエンドのサービスを組み立てる分、自由度があります。サーバインスタンスを意識せずに、バックエンドでアプリケーション特有の処理を必要とするケースに利用されることになります。マイクロサービスの一種の形態とも考えられています。
2016年2月になり、 GoogleはAWS Lambda同等の機能を提供する Google Cloud Functions のα版サービスを公開しました。また、Iron.ioがAWS Lambda互換ソフトウェアの開発を Project Kratos として発表しました。クラウドベンダーから続々とサーバーレスアーキテクチャが提供され始めています。
本エントリでは、IBMから先日(2016年2月22日)発表されたサーバレスアーキテクチャである OpenWhisk を試してみたいと思います。
OpenWhiskの特徴
OpenWhiskはJavaScriptに加え、現状唯一Swiftで書かれたコードを実行することができます。また、Dockerコンテナ内のアプリケーションもイベント駆動で実行でき、オープンソース(Apache License, Version 2.0)であるというのも大きな特徴となっています。
IBMはSwiftのクラウドランタイム環境である Swift Sandbox、およびREST API対応Webアプリケーションフレームワークである Kitura を提供するなど、Appleとのグローバルなパートナーシップがエンタープライズアプリケーションだけでなく、サーバアーキテクチャにも現れてきているのが面白いところです。
なお、いくつかのサービスはまだβ版であるように、OpenWhiskも現段階では商用環境での使用は推奨されていません。
実行環境
クラウド環境
IBM Bluemix上でOpenWhiskを利用することができます。
BluemixはCloud FoundryベースのPaaSで、30日のトライアル期間は無料で使用することができます。
Bluemixのアカウントを作成後、コンソールにてOpenWhiskの利用申請をすると、「アカウントが有効になったらメールで通知するよ」という旨のメッセージが出てきます。
ただ、この後いくら待ってもアカウントが有効になりません。。
今回はOSSで提供されているので自前の環境で試してみることにします。
オンプレ環境
ソースはGitHubにあります。
OpenWhisk – GitHub
コミットバージョン:28f19bbf4c8aecb4dc0492d7fc28a4bf618e959d
こちらのREADMEにしたがって、VM上にOpenWhisk環境を作成します。
OpenWhiskはデータストアにApache CouchDBベースの Cloudant を使用しているので、Bluemix上でCloudantサービスを追加するか、Cloudantに直接アカウントを作成する方法のいずれかでCloudantを利用可能にします。
※今のところCloudantを利用してますが、代替のデータストアを準備しているみたいです。
VMはメモリ4GBが推奨となってますが、なにも気にせずマニュアル通り淡々と進めてしまった挙句、手元の非力なMacBook AirではVM上でのビルド&デプロイ中にMacが不安定になり落ちてしまいました。。
Vagrantfileをみるとメモリ4GB、CPU8コアのVMが作成されるようになっています。
それでは落ちるのも納得。。と、メモリ2GB、CPU2コアに編集し、45分かけてビルド&デプロイが成功しました。この時点で、ディスクは12GBほど消費しています。
セットアップができたら簡単に動作確認してみましょう。
あらかじめguestユーザーが設定されていますので、guestユーザーでVM上のOpenWhiskにホストOSからアクセスしてみます。
まずはAPIホストと認証キーを設定します。設定したpropertyは~/.wskpropsに保存されます。
$ wsk property set --apihost 192.168.33.13 --auth $(cat config/keys/auth.guest)
echoサンプルを起動してみます。
$ wsk action invoke /whisk.system/samples/echo -p message hello --blocking --result
こちらの出力結果が得られれば、コードが実行できている状態になります。
{ "message": "hello" }
なお、-v オプションをつけるとverboseモードで実行され、リクエスト/レスポンスの詳細が確認できます。
$ wsk -v action invoke /whisk.system/samples/echo -p message hello --blocking --result {'apihost': '192.168.33.13:443', 'namespace': '_', 'clibuild': '2016-02-28T10:15:24-05:00', 'apiversion': 'v1'} ======== REQUEST: POST https://192.168.33.13:443/api/v1/namespaces/whisk.system/actions/samples/echo?blocking=true Headers sent: { "Authorization": "Basic MjNiYzQ2YjEtNzFmNi00ZWQ1LThjNTQtODE2YWE0ZjhjNTAyOjEyM3pPM3haQ0xyTU42djJCS0sxZFhZRnBYbFBrY2NPRnFtMTJDZEFzTWdSVTRWck5aOWx5R1ZDR3VNREdJd1A=", "Content-Type": "application/json" } Body sent: {"message": "hello"} -------- RESPONSE: Got response with code 200 Body received: { "name": "echo", "subject": "guest", "activationId": "1b750f9a42204c3d9f0cc4feda957897", "publish": false, "annotations": [], "version": "0.0.1", "response": { "result": { "message": "hello" }, "success": true, "status": "success" }, "end": 1456673738162, "logs": [], "start": 1456673738145, "namespace": "guest" } ======== { "message": "hello" }
コードの実行
アクションの作成
JavaScriptおよびSwiftのコードでアクションを作成し、実行してみましょう。
それぞれコードを記述します。
hello.js
function main(params) { return {payload: 'Hello, ' + params.name + '!'}; }
hello.swift
func main(args: [String:Any]) -> [String:Any] { if let name = args["name"] as? String { return [ "payload" : "Hello \(name)!" ] } else { return [ "payload" : "Hello stranger!" ] } }
続いて、上記のコードからアクションを作成します。
$ wsk action create hellojs hello.js $ wsk action create helloswift hello.swift
作成したアクションは下記のように確認することができます。
$ wsk action list actions /guest/hellojs private /guest/helloswift private
Cloudantデータベースを覗くと、それぞれのコードがストアされているのがわかります。
アクションの実行
まずは同期処理で実行してみます。
hellojs
$ wsk action invoke --blocking hellojs --param name 'Sato' ok: invoked hellojs with id 9ffd2f375c884da2a897c4e1a5cff93b response: { "result": { "payload": "Hello, Sato!" }, "status": "success", "success": true }
helloswift
$ wsk action invoke --blocking helloswift --param name 'Sato' ok: invoked helloswift with id 4c935afc571b45e893e7cef2f7de3672 response: { "result": { "payload": "Hello Sato!" }, "status": "success", "success": true }
非力VMのせいかCloudantのせいなのか、レスポンスは1〜2秒程度と結構もっさりしています。JSよりSwiftのほうがよりもっさりする感じです。まれに8秒くらいかかったりします。
半日以上たっても未だにBlumixでのアカウントが有効になってませんが、アカウントが有効になったらそちらの実行環境でも試してみたいと思います。
なお、–blockingオプションを指定しない場合、非同期での実行になります。こちらが基本なのかもしれません。
$ wsk action invoke helloswift --param name 'Sato' ok: invoked helloswift with id 27b9f6f5a8e442888ea7e297c3b6bdf5
返却されたidを指定して結果を取得します。
$ wsk activation result 27b9f6f5a8e442888ea7e297c3b6bdf5 { "payload": "Hello Sato!" }
実行済みのIDは下記のように確認でき、存在するものは何度でもIDを指定して結果を取得することができます。
$ wsk activation list activations e06d261c1b1044a3b0f9b3f788a84fa2 helloswift 27b9f6f5a8e442888ea7e297c3b6bdf5 helloswift dfd07253575c4f16907a06b2ecb7b48a helloswift 9ffd2f375c884da2a897c4e1a5cff93b hellojs 0279799fdea046ea83575acfc6551ca1 helloswift 4af69121a90744e08b9ce52dc677afe1 hellojs 4c935afc571b45e893e7cef2f7de3672 helloswift bf21c7acc95346ac878ecdce8a8dc7cf hellojs 5629f5523d7b4f77bedcf32bbd4b17c5 helloswift b7a5e23317cf4bb687d76a79b7bfff1c hellojs 1b750f9a42204c3d9f0cc4feda957897 echo
ここまででOpenWhisk環境を構築してJavaScriptとSwiftのコードからなるアクションを実行することができました。またの機会にSystem Overviewにあるように、アクションをChainでつなげ、Triggerを機にRuleベースで実行するというサーバレスアーキテクチャの醍醐味を試していきたいと思います。
それではまた。
次世代システム研究室では、アプリケーション開発や設計を行うアーキテクトを募集しています。アプリケーション開発者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。
皆さんのご応募をお待ちしています。
グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。
Follow @GMO_RD