Azure Relay で場所を選ばず HTTP 要求の受信と処理が可能に

執筆者: Clemens Vasters (Architect, Azure Service Bus)

このポストは、2018 年 5 月 31 日に投稿された Receiving and handling HTTP requests anywhere with the Azure Relay の翻訳です。

 

マイクロソフトは Build 2018 カンファレンスにて、別々の場所にいる Visual Studio ユーザーどうしが容易にピアツーピアでコードを共同編集できる Visual Studio Live Share (英語) 機能を発表しました。この機能を使用すると、たとえば、カフェにいる開発者と飛行機で機内 Wi-Fi を使用している開発者がコードを直接共同編集するといったことが可能になります。

この「ネットワークの魔法」とも呼べるような機能を Visual Studio チームが実現できたのは、Azure Service Bus、Azure Event Hubs、Azure Event Grid などのメッセージング サービス ファミリの 1 つである Azure Relay のおかげです。Relay は Azure の中でも最も古いサービスで、ちょうど 12 年前に (英語) 登場し、2010 年 1 月にリリースされた Azure プラットフォームに導入されました。

その後、Relay はあらゆる WebSocket クライアント スタックで動作する完全にドキュメント化されたオープンなプロトコルに準拠し、受信側のファイアウォール ルール、パブリック IP アドレス、DNS 登録などがなくても、クライアントを他からの受信接続のリスナーとして使用できるようになりました。すべての受信接続が、ネットワーク リンクの深い階層ではなくアプリケーション層で終わるため、仮想プライベート ネットワーク (VPN) テクノロジを使用するよりも安全に個別アプリに接続することができます。

Build 2018 カンファレンスでは、他の Azure 関連の多数の機能と共に Relay の新機能を発表しました。見逃してしまった方のために、改めて Relay の HTTP 要求のリレー サポートについてお伝えします。

これは、パブリック エンドポイントを提供できないコンテナー内のアプリケーションやアプリケーション コンポーネント向けの機能で、Webhook を実装して Azure Event Grid と統合する際に役立ちます。

Relay は、ファイアウォールを介して通信するアプリケーションやデバイスで広く使用されます。一般的なアプリケーション シナリオには、クラウド ベースの SaaS アプリケーションを POS システム (店舗、喫茶店、レストラン、日焼けサロン、ジム、修理屋など) や専門職のオフィス (税理士、弁護士、病院など) に統合する場合などがあります。また、Relay は複雑な VPN をセットアップする代わりにリレーを基盤とする通信経路を使用しており、企業の IT 部門でも導入されています。詳しいシナリオについては、今後お伝えしていきます。

この新しい HTTP サポートにより、どこにいても、スマートフォンなどのあらゆるデバイスでパブリックからアクセスする HTTP(S) リスナーを作成しホストできるようになります。解決可能な DNS 名、TLS サーバーの証明書、パブリックからアクセス可能な IP アドレスなどは Azure Relay サービスが提供します。アプリケーション側で行う操作は、一般的な 443 番の HTTPS ポートで Azure Relay への Websocket 接続を確立するだけです。

ここで、簡単な Node.js のサンプルをご紹介します。最初のコードは、Node.js で作成された「設定不要の」最小限のローカル HTTP リスナーです。

 
var http = require('http');
var port = process.env.PORT || 1337; 

http.createServer(function (req, res) {
     res.writeHead(200, { 'Content-Type': 'text/plain' });
     res.end('Hello World\n');
}).listen(port);

これと同等の Node.js アプリケーションを Azure Relay を使用して作成すると、次のようになります。

 
var http = require('hyco-https');

var uri = http.createRelayListenUri("cvbuild.servicebus.windows.net", "app");
var server = http.createRelayedServer({
       server: uri,
       token: () => http.createRelayToken(uri, "listen", "{…key…}")
     },
     function (req, res) {
         res.writeHead(200, { 'Content-Type': 'text/plain' });
         res.end('Hello World\n');
}).listen();

大きく異なるのは、Relay アプリケーションでは、Node.js に組み込まれている ‘http’ モジュールではなく ‘hyco-https’ モジュールを使用している点と、Relay 接続にエンドポイントとセキュリティ トークンの情報を提供する ‘createRelayedServer’ メソッドを使用してサーバーが作成されている点です。大きなポイントは、Node.js の HTTP ハンドラー部分のコードがまったく同じであることです。

.NET Standard では、従来の Relay API が最新のプレビュー版 Microsoft.Azure.Relay (英語) NuGet パッケージを拡張し、HTTP 要求の処理もサポートしました。Websocket 接続の確立と同様に、HybridConnectionListener でハイブリッド接続用リスナーを作成し、RequestHandler コールバックを追加するだけです。

 
var listener = new HybridConnectionListener(uri, tokenProvider);
listener.RequestHandler = (context) =>
{     
context.Response.StatusCode = HttpStatusCode.OK;     context.Response.StatusDescription = "OK";
     using (var sw = new StreamWriter(context.Response.OutputStream))
     {
         sw.WriteLine("hello!");
     }     context.Response.Close();
};

既存の ASP.NET Core サービスで Relay の要求をリッスンしたい場合には、先日リリースしたばかりの Microsoft.Azure.Relay.AspNetCore (英語) NuGet パッケージを使用して、Web ホストのビルダーに "UseAzureRelay()" 拡張子を追加します。ハイブリッド接続の共有アクセス ルールの接続文字列を構成すると、Relay 越しに既存の ASP.NET Core アプリをホストすることができます (詳しくは readme (英語) およびサンプル (英語) を参照)。

 
public static IWebHost BuildWebHost(string[] args) =>
             WebHost.CreateDefaultBuilder(args)
                 .UseStartup<Startup>)
                 .UseAzureRelay(options =>
                 {
                     options.UrlPrefixes.Add(connectionString);
                 })
                 .Build();

この HTTP 機能は現在運用環境向けプレビューとして、Relay の従来の機能と併用可能で、サポートと SLA が提供されています。ただし、完成していないプレビュー版のため、今後も HTTP 関連の接続プロトコルが大幅に変更される可能性があります。

Relay は通常のリバース プロキシとは異なるため、下位階層の HTTP の詳細の一部がオーバーライドされています。この点は今後調整していく予定です。典型的な既知の問題として、HTTP 応答がチャンク転送エンコーディングを使用する形式に毎回変換されるようになっています。アプリケーション レベルではほとんど実質的な影響はありませんが、プロトコルの純粋性を重視する開発者は不便さを感じるかもしれません。

使用を開始する場合は、C# (英語) または Node.js (英語) のチュートリアルをご確認ください。チュートリアル下部のフィードバック オプションから、この機能に関するご意見をお聞かせください。