しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Azure Functions Proxies で実現出来ること

前にハッカソンを行った時に Azure Functions Proxies 周りの挙動が気になったので、一通り確認して気になったことを軽くメモとして残します。

まずは公式ドキュメントと牛尾さんの Qiita を読めば大体は理解できるはずです。

Azure Functions Proxies は名前の通り、入ってきた HTTP リクエストを別のバックエンドに流す機能がありますが、もうちょっと面白く使えるのではないかと思っています。

環境変数を使う

ARM Template や Deployment Slot と組み合わせて便利に使えそうなのが環境変数の参照ですね。

サンプルなので適当に App Settings に値を追加して試してますが、Slot Setting にチェックを入れると Swap を行った後でも値が変わらないので便利です。

f:id:shiba-yan:20190115154420p:plain

公式のドキュメントには App Settings で設定した値を参照できるとありますが、実際には環境変数を参照しているので App Settings 以外にも App Service が内部的に設定した値も参照できます。

プロキシの定義は以下のようにしました。%% で囲むと環境変数で置換されるという分かりやすい挙動です。

{
  "$schema": "http://json.schemastore.org/proxies",
  "proxies": {
    "buchizo": {
      "matchCondition": {
        "route": "/buchizo"
      },
      "backendUri": "https://%BLOG_AZURE_MOE%/"
    }
  }
}

f:id:shiba-yan:20190115154254p:plain

作成した Proxy URL にアクセスすると、ちゃんと App Settings で指定した URL へのリクエストが行われたことが確認出来ます。パスをキャプチャすれば、もっと柔軟に利用できます。

f:id:shiba-yan:20190115170046p:plain

フロントとバックエンドを複数用意した場合などで、その向き先を App Settings で指定できるので、Run From Package やマルチリージョンへのデプロイと相性が良いと思います。

ループバックアドレスを使う

Azure Functions Proxies を使って自分自身の Functions へのルーティングを行う場合にはループバックアドレスが使えます。つまり URL Rewrite でいうところの Rewrite に該当する挙動になります。

この場合はバックエンドへの HTTP 通信が発生しないため、余計なオーバーヘッドが発生しません。

もしこの挙動を変えたい場合には AZURE_FUNCTION_PROXY_DISABLE_LOCAL_CALL に true を設定します。その場合では localhost だと上手く動かなくなります。

しかし、パッと見は本当にバックエンドへのリクエストが発生していないか確認出来ないので、以下のような定義でトレースを有効にして確認しておきました。

{
  "$schema": "http://json.schemastore.org/proxies",
  "proxies": {
    "Internal Routing": {
      "debug": true,
      "matchCondition": {
        "route": "/internal"
      },
      "backendUri": "https://localhost/api/HttpTrigger1"
    }
  }
}

f:id:shiba-yan:20190115154242p:plain

ログが長いので割愛しますが forward-request を確認すれば、バックエンドへの HTTP ヘッダー設定などが含まれていないので、直接実行されたことが分かります。別のエンドポイントを指定した場合には、バックエンドへ送信する HTTP ヘッダーなどの情報がログに書き出されます。

ドキュメントには localhost を使えと書いてありましたが WEBSITE_HOSTNAME などを使って自分自身のホスト名を設定した場合でも、直接 Functions が実行されるようでした。

{
  "$schema": "http://json.schemastore.org/proxies",
  "proxies": {
    "Internal Routing": {
      "matchCondition": {
        "route": "/internal"
      },
      "backendUri": "https://%WEBSITE_HOSTNAME%/api/HttpTrigger1"
    }
  }
}

なので上の定義は先ほどの定義と全く同じ挙動となります。分かりやすさでは localhost のが良いですね。

リダイレクトを行う

Azure Functions Proxies では backendUri はオプションになっているので、別に指定しなくても適切に responseOverrides を使って値を設定すれば動作します。一般的にはモックの作成に使われていますね。

使う場面があるかわからないですが、302 と Location ヘッダーを返せばリダイレクトも出来ます。

{
  "$schema": "http://json.schemastore.org/proxies",
  "proxies": {
    "Redirect": {
      "matchCondition": {
        "route": "/redirect"
      },
      "responseOverrides": {
        "response.statusCode": "302",
        "response.headers.Location": "https://%BLOG_AZURE_MOE%/"
      }
    }
  }
}

f:id:shiba-yan:20190115175853p:plain

勿論ちゃんと動作します。Azure Functions では URL Rewrite が使えないので、簡単な処理でも Functions として実装しないといけないですが、多少のことなら Proxies で実現できます。

カスタム HTTP ヘッダーを追加する

普通の ASP.NET アプリケーションの場合は Web.config を使って HTTP ヘッダーを追加できますが、Azure Functions では Web.config を Function Runtime が持っているので基本的には弄れません。

なので Functions Proxies を使って同じような定義を書けば良いです。

{
  "$schema": "http://json.schemastore.org/proxies",
  "proxies": {
    "AddHeader": {
      "matchCondition": {
        "route": "/{*path}"
      },
      "backendUri": "https://localhost/{path}",
      "responseOverrides": {
        "response.headers.X-Kazuakix-Age": "50"
      }
    }
  }
}

上の定義を実行すると、ちゃんと HTTP ヘッダーが付与されて返ってきました。

f:id:shiba-yan:20190115174932p:plain

割と URL Rewrite と ARR の組み合わせに近いことが出来ますが、今のところはマッチする条件を全く指定できないので、せめて HTTP ヘッダーぐらいは条件として扱いたいですね。

パフォーマンス周りは調べてないですが、アーキテクチャ的に Application Gateway よりは悪いのではないかと思っています。しかし、Azure Functions Proxies は Consumption かつスケーリングが素早いので、デプロイに時間がかかる Application Gateway よりはシンプルに使えます。