Azure Functions:旅の行程

2016年4月27日 に投稿済み

このブログ記事は、Microsoft のプリンシパル ソフトウェア エンジニアである Mathew Charles が執筆しました。

最近、私たちのチームは //build で新しい Azure Functions サービスのプレビューをリリースしました。このサービスについては既にいくかつのブログで説明しました (「Introducing Azure Functions (Azure Functions の紹介)」など)。ここでは、舞台裏を少し掘り下げて、このプロジェクトがどのように始まったか、そして現在はどこまでたどり着いたかについて説明します。Functions ランタイム、動的コンピューティング レイヤー ("サーバーレス")、および Functions ポータルについて説明し、これらすべての要素がどのように進化し、まとまりのある製品へと編成されたかについて概要を示します。これはチームにとって楽しいドライブであり、まだ始まったばかりです

このプロジェクトの進化は、多数の既存のプラットフォーム要素にまたがる相乗効果を特定し、それらを互いに結び付けて新しい製品オファリングへとまとめる場合の良い例です。Azure App Service には構成要素が既に多数用意されていたため、Azure Functions のビジョンをさらに迅速に実現できました。このような既存の資産を活用し、新しい技術革新と機能を取り入れることで、プロジェクトを非常に迅速にまとめることができました。

WebJobs SDK

Chris の //build トーク「Introducing Azure Functions (Azure Functions の紹介)」では、Azure Files が Azure WebJobs SDK に基づいてどのように構築されているかが説明されました。WebJobs SDK は数年前から存在しており、さまざまなイベント ソースをトリガーとするバックエンド処理ジョブを構築するために多くのお客様に利用されています。WebJobs SDK には、最小限のコードで洗練されたジョブ関数をとても簡単に記述できる単純な宣言型プログラミング モデルがあります。次に例を示します。

public static void ProcessOrder(
    [QueueTrigger(“orders”)] Order order,
    [Blob(“processed/{Id}”)] out string receipt,
TraceWriter log)
{
log.Verbose(string.Format(“Processing Order {0}”, order.Id));

    // business logic

    receipt = “<some value>”;
}

単純な .NET コンソール アプリケーションで WebJobs SDK JobHost によってホストされる場合、新しいキュー メッセージが Azure Queue の "orders" に追加され、キュー ペイロードが Order POCO のインスタンスに逆シリアル化されるたびに、自動的にこの関数がトリガーされます。この関数は、受信メッセージの "Id" プロパティを BLOB パスの一部として使用して、自動的に出力 BLOB にバインドします。このプログラミング モデルでは、ジョブ関数はそのビジネス ロジックにのみ集中する必要があり、ストレージ操作を処理する必要はありません。素晴らしいことです。

WebJobs SDK を使用したこのような関数のホスティング モデルは、Azure WebJobs としてデプロイすることです。これは適切に機能し、柔軟性が高いので、とても人気の高い Azure App Service の機能であり続けています。

Functions ランタイム

昨年半ばごろ、この単純なプログラミング モデルを他の言語に移行するために必要なことについて議論を始めました。お客様からもこの質問をいただいていました。誰もが .NET C# プログラマーであるとは限りませんが、多くの人がそのような WebJobs SDK パターンを使用したいと考えるでしょう。そこで、このプロトタイプ作成に取り組み始め、メタデータのための新しい JSON 記述モデルを基に階層化することで、既存の実証済みの .NET WebJobs SDK ランタイムを活用できるようにするモデルを考え出しました。その結果、Node.js (または他の言語) で上記と同じ関数を記述できるようになりました。

module.exports = function (context, order) {
context.log(‘Processing order’, order.id);

    // business logic

context.bindings.receipt = “<some value>”;
context.done();
}

この関数は構造的に上記の C# 関数と同じである点に注目してください。これは、同じランタイム実装にマップされるためです。宣言コード属性は、メタデータを指定する 1 つの方法にすぎません。私たちは、同じ情報を単純な JSON 記述ファイルにキャプチャできることに気づきました。この関数のバインドを記述した対応するメタデータ ファイルを次に示します (つまり、C# の例の宣言属性内のすべての要素です)。

{
  “bindings”: [
    {
      “type”: “queueTrigger”,
      “name”: “order”,
      “direction”: “in”,
      “queueName”: “orders”
    },
    {
      “type”: “blob”,
      “name”: “receipt”,
      “direction”: “out”,
      “path”: “processed/{id}”
    }
  ]
}

基本的な考え方は、このメタデータを使用すると、さまざまな言語と .NET WebJobs SDK ランタイムの間にメモリ内アダプターを生成できるということです。効率的に前述の C# 関数を生成し、その関数のメソッド本文は実際のユーザー関数 (つまり、記述した Node.js 関数) に単純にデリゲートします。その結果、Azure Functions は、関数を実装する 1 つ以上のスクリプト ファイルの集まりと共に、関数バインドを記述する単純な function.json メタデータ ファイルになります。同じメタデータ ファイルを使用し、関数を Windows BAT ファイルとして記述した、前述の例と同じ例を次に示します。

SET /p order=<%order%
echo Processing order ‘%order%’
echo ‘<some value>’ > %receipt%

同じメタデータ ファイルを使用して、サポートされている 7 つの言語のいずれかで関数を記述することができます。当然ながら、各言語には独自の記述方法や機能があり、タスクに応じて適している言語があります。ここでの重要な点は、これらすべての言語に対して同じトリガー/バインド ランタイムを使用し、各言語を独自の方法でそのモデルにマップできるということです。BAT ファイルには多少制限がありますが、環境変数とファイル ストリームを介して、入力と出力の両方を受け取ることができます。また、それは Functions ランタイムによって基盤となる Azure Storage アーティファクトに自動的にマップされます。

Azure Functions はコア WebJobs SDK に基づいて構築されています。つまり、言語ごとに異なるバージョンの WebJobs SDK を作成して保守する必要がありません。これは技術的に大きな成果です。Microsoft には、すべてのバインド/トリガー ロジックを処理する 1 つのコア ランタイムがあり、そのコアが関数だけでなくすべての WebJobs SDK のお客様の利益になるように投資しています。また、これはコア SDK 用に作成されたすべてのトリガー/バインド拡張機能も Functions で使用できることも意味します。Microsoft は、従来のお客様と Azure Functions の両方のために、コア WebJobs SDK と拡張機能に引き続き重点的に投資します。

Webhook のサポート

重点を置き始めたもう 1 つの重要な分野は Webhook のストーリーでした。Azure Storage イベントで関数がトリガーされる機能は優れていますが、WebJobs のお客様から、Webhook 要求を介してジョブ関数をトリガーする機能も要望されてきました。この機能は、Webhook 拡張機能を記述することで昨年既に実験して成功しましたが、WebJobs が Kudu SCM サイトの下で動作するという大きな欠点がありました。つまり、要求を実行するには、基本認証の資格情報が必要です。そのエンドポイントにしか到達できないように制限された単純な認証コードを使用して URL を配布する機能が必要なため、これはほとんどの Webhook 統合シナリオにとっては問題です。

これに対処するために、Functions ランタイムを WebApp のルートで実行されるサイト拡張機能としてパッケージ化することにしました。つまり、SCM エンドポイントの背後にはないので、必要な認証パターンを達成することができます。これにより、Webhook 関数用の単純な認証済みエンドポイント セットを公開できるようになりました。また、ASP.NET Webhook ライブラリもこれに統合しました。その結果、ライブラリがサポートする多数の Webhook プロバイダーを利用し、GitHub、Slack、DropBox、Instagram などのプロバイダーに対する最上級レベルのサポートが可能になりました。

そのため、この時点で、7 つの言語 (Node.js、C#、F#、Bash、BAT、Python、PHP) 用の完全な WebJobs SDK トリガー/バインド モデルをサポートする柔軟な Functions ランタイムと、幅広い Webhook 統合シナリオをサポートする HTTP ヘッドとなりました。

動的コンピューティング

前述のランタイム作業と並行して、サーバーレス コンピューティングとその分野で何をしたいかについても議論しました。そこで、WebJob に対して行っていたこの作業は非常に相乗的であることがわかりました。私たちは、サンドボックス環境でユーザー コードを大規模に実行できる柔軟な多言語関数ランタイムを開発していました。ただし、従来の WebJobs モデルでは、そのような WebJob を実行する WebApp ホストをユーザーが作成および管理する必要があります。その部分を抽象化し、ユーザーは関数を作成するだけで済み、デプロイと規模の問題は Microsoft がすべて解決できたとしたらどうでしょうか。基本的には、WebJobs SDK をサービスとして使用してきました。そこでひらめいたのです。

計画のある部分の調査を開始するようにチームの方針を変えました。つまり、"動的コンピューティング" です。これが少数のメンバーからはるかに大規模なチームへと急速に成長したプロジェクトの転換点でした。私たちのスクラム会議は毎日 2、3 人ずつ増えました。動的コンピューティング レイヤーでは、負荷が増加すると自動的に関数がスケールアウトされ、減少すると元のスケールに戻ると考えられました。エンド ユーザーにとっては、この処理について心配する必要がまったくなく、実際に使用したコンピューティング時間に対してのみ請求されるという結果になります。このプロジェクトの動的コンピューティング領域は広く、監視、診断、テレメトリなどの他のサービスの側面も含まれています。この領域には、今後、独自のブログ記事を作成する価値があります。

Functions ポータル

次に重点を置き始めたことは、このような関数の作成と管理を本当に簡単にするためのポータル エクスペリエンスでした。従来の WebJobs SDK モデルでは、コンパイル済みのすべてのジョブ関数を含む .NET コンソール アプリケーション (JobHost) をコンパイルし、デプロイします。Azure Functions の場合、デプロイ モデルははるかに単純です。Functions ランタイムは非常に単純なファイル システム レイアウトになるように設計されました。これにより、Kudu API を介してこのようなファイルを操作する簡単なポータル UI が容易になります。このようなファイルを作成/編集してそれらを関数コンテナー (関数を実行している WebApp) にプッシュすることができる簡単なポータル エディターを用意できました。また、この単純なファイル システム モデルによって、ARM テンプレートを介して Azure Functions をデプロイできるようになります。実際のところ、これは現在でも可能ですが、まだ文書化されていません。

チームはポータルを短期間で立ち上げて実行することができました。また、このポータルを使用して新しい製品に取り組めることにとても興奮しました。ポータルの準備が整い、本当の意味でさまざまなことがまとまってきたと感じられるようになりました。より広いチームがこの製品の利用できるようにしたことで、さまざまなユーザビリティの議論や改善が進み、バグの解決にも役立ちました。  ポータルの作業が開始されたときは、Functions ランタイムの場合と同様に 1 人か 2 人が作業していましたが、その初期の作業で牽引力が高まり、範囲や計画が広くなるにつれて、人員を増加しました。スクラム会議も人数が増えました

テンプレート

関数の単純なファイル システム モデルによって、現在 Functions ポータルに見られる素晴らしいテンプレート モデルを開発することもできました。私たちは、さまざまな言語にまたがる共通シナリオ用の単純なメタデータ/スクリプト テンプレートの作成に取りかかりました。"QueueTrigger - Node"、"GitHub WebHook C#" などです。変更せずにすぐに実行できる簡単な "レシピ"、つまりお客様の関数の出発点を用意し、それをお客様のニーズに合わせてカスタマイズし、拡張できるようにするという考え方です。将来的には、コミュニティがこのようなテンプレートを作成してエコシステムを推進できるようにしたいと考えています。

拡張性

Azure Functions の //build 発表までに重点を置いていたもう 1 つの領域は、Functions で利用できるようにした新しい WebJobs SDK 拡張機能セットです。去年の秋、Microsoft は WebJobs SDK 拡張機能モデルをリリースしました。これでプログラミング モデルが新しいトリガー/バインド ソースに開かれました。私たちのチームは、既にいくつかの新しい便利な拡張機能 (TimerTrigger、FileTrigger、SendGrid バインドなど) を WebJobs SDK 拡張機能リポジトリでコミュニティに紹介してきました。また、コミュニティ メンバーにも独自の拡張機能を作成していただきました。Functions は SDK に基づいて構築されているため、これらすべての拡張機能を Azure Functions でも使用できます。これまで作成したいと思っても時間がないことがわかっていた拡張機能が多数ありましたが、新しい大規模なチームになり、そのうちの一部に着手できるリソースができました。ここ数か月間で追加の拡張機能を追加し、それらを Functions の最上級の機能にしました。つまり、EventHub、DocumentDb、NotificationHub、MobileApps、ApiHub という拡張機能です。これは始まりに過ぎません。さらに多くの拡張機能が計画されています。また、コミュニティでもさらに作成されることが期待されます。また、サード パーティが独自の拡張機能を Functions に組み込めるように、簡単なモデルにも取り組んでいます。引き続き今後の情報にご期待ください。

もう 1 つの素晴らしいことは、コア WebJobs SDK および WebJobs SDK 拡張機能のリポジトリと同様に、私たちのすべての作業をオープン ソースにしたいと早期に決断したことです。そこで、Functions ランタイムを含む WebJobs SDK Script を作成しました。同様に、Functions ポータルもオープン ソースです。AzureFunctionsPortal です。

上記のすべてをまとめると、Functions ランタイム、Functions ポータル、動的コンピューティングというプロジェクトのさまざまな部分とそれらがどのように組み合わされたかについての非常に簡単な概要です。今後の記事では、これらのさまざまな領域について詳しく説明します。