AKS と Emissary-Ingress で簡易的なパスベースルーティングを試してみた
2025-05-02
azblob://2025/05/02/eyecatch/2025-05-02-emissary-ingress-aks-run-000.jpg

はじめに

Emissary-Ingress とはトラフィックルーティングやロードバランシングなどの機能を提供する、Envoy Proxy ベースの Kubernetes ネイティブな API Gateway です。また、Emissary-Ingress は CNCF プロジェクトにて 2021 年 4 月 13 日に Incubating レベルのプロジェクトと認定されたプロジェクトです。

Emissary-Ingress was accepted to CNCF on April 13, 2021 at the Incubating maturity level.

引用元: CNCF | Emissary-Ingress

本記事では、Azure Kubernetes Service(以下、AKS) を使用して Azure 上の Kubernetes クラスター内に Emissary-Ingress をセットアップし、背後にある複数の静的 Web サイトに対して、パスに基づいたルーティングを実現する手順を試します。

想定されるインフラ構成は下図のとおりです。

構成図

前提条件

  • Kubernetes クラスター v1.31.7 (AKS)
  • Azure CLI v1.35.0
  • kubectl v1.32.0
  • Helm v3.17.3
  • Emissary-Ingress の Helm Chart v8.12.2
  • Emissary-Ingress の アプリケーション v3.12.2

事前準備

(1) 変数定義

以降の手順で使用するコマンドに必要な変数の初期化を行います。
※ TENANT_ID と SUBSCRIPTION_ID の値は適宜必要な値に置き換えて実行してください。

export TENANT_ID='00000000-0000-0000-0000-000000000000'
export SUBSCRIPTION_ID='00000000-0000-0000-0000-000000000000'
export RESOURCE_GROUP_NAME='rg-emissary'
export LOCATION='japaneast'
export AKS_NAME='aks-emissary'
export STORAGE_ACCOUNT_NAME_1='stemissaryweb1'
export STORAGE_ACCOUNT_NAME_2='stemissaryweb2'

(2) テナントにログイン

作業予定のテナントに対して、下記のコマンドでログインします。

az login -t $TENANT_ID

コマンドを実行するとブラウザが開き、ログインが求められます。
認証が完了すると、CLI はサブスクリション情報を表示します。

(3) サブスクリプションのセット

下記コマンドを実行してサブスクリプションをセットします。

az account set --subscription $SUBSCRIPTION_ID

インフラリソース構築

前提として、リソースの構築は Azure CLI を使用して進めていきます。
また、コマンドに使用するフラグは、期待する動作を実現する必用最低限のみを使用します。

リソースグループ作成

まず、リソースグループを作成します。

az group create \
 --name $RESOURCE_GROUP_NAME \
 --location $LOCATION

AKS 作成とシークレットの取得

次に、AKSクラスターを作成します。

az aks create \
 --resource-group $RESOURCE_GROUP_NAME \
 --name $AKS_NAME \
 --generate-ssh-keys

クラスターの作成には数分かかります。完了したら、クラスターへの接続情報を取得します。

az aks get-credentials \
 --resource-group $RESOURCE_GROUP \
 --name $AKS_NAME

接続情報が取得できたら接続先クラスターが aks-emissary になっていることを確認します。

kubectl config current-context

Storage Account 作成と静的 Web サイトホスティングの有効化

静的 Web サイトをホストするためのストレージアカウントを2つ作成します。

az storage account create \
 --name $STORAGE_ACCOUNT_NAME_1 \
 --resource-group $RESOURCE_GROUP

az storage account create \
 --name $STORAGE_ACCOUNT_NAME_2 \
 --resource-group $RESOURCE_GROUP

作成した2つのストレージアカウントに対して、静的 Web サイトのホスティングを有効にします。

az storage blob service-properties update \
 --account-name $STORAGE_ACCOUNT_NAME_1 \
 --static-website \
 --index-document index.html
az storage blob service-properties update \
 --account-name $STORAGE_ACCOUNT_NAME_2 \
 --static-website \
 --index-document index.html

作成したストレージアカウントそれぞれに、サンプルの HTML ファイルを作成してアップロードします。

# 1つ目のストレージアカウントへの対応
echo '<html><body><h1>Hello from Azure Storage 1!</h1></body></html>' > index.html
az storage blob upload \
 --account-name $STORAGE_ACCOUNT_NAME_1 \
 --container-name '$web' \
 --file index.html \
 --name index.html
# 2つ目のストレージアカウントへの対応
echo '<html><body><h1>Hello from Azure Storage 2!</h1></body></html>' > index.html
az storage blob upload \
 --account-name $STORAGE_ACCOUNT_NAME_2 \
 --container-name '$web' \
 --file index.html \
 --name index.html

2つのストレージアカウントに対して、静的 Web ページがホストされているかを確認します。

# ストレージアカウント1の確認
URL1=$(az storage account show \
 --name $STORAGE_ACCOUNT_NAME_1 \
 --resource-group $RESOURCE_GROUP \
 --query 'primaryEndpoints.web' \
 --output tsv)
# 動作確認コマンド
curl -i $URL1
# レスポンス
HTTP/1.1 200 OK
~ 省略 ~
<html><body><h1>Hello from Azure Storage 1!</h1></body></html>
# ストレージアカウント2の確認
URL2=$(az storage account show \
 --name $STORAGE_ACCOUNT_NAME_2 \
 --resource-group $RESOURCE_GROUP \
 --query 'primaryEndpoints.web' \
 --output tsv)
# 動作確認コマンド
curl -i $URL2
# レスポンス
HTTP/1.1 200 OK
~ 省略 ~
<html><body><h1>Hello from Azure Storage 2!</h1></body></html>

期待通りのレスポンスが確認できれば、静的 Web ページのホスティングは完了になります。

AKS 内に Emissary-Ingress をインストールする

Helm を使用して Emissary-Ingress をインストールします。

# ローカルに Emissary-Ingress のリポジトリへの紐付けを追加する。
helm repo add datawire https://app.getambassador.io
helm repo update

# 名前空間の追加とCRDのインストール
kubectl create namespace emissary && kubectl apply -f https://app.getambassador.io/yaml/emissary/3.9.1/emissary-crds.yaml
kubectl wait --timeout=90s --for=condition=available deployment emissary-apiext -n emissary-system
# Emissary-Ingress のインストール (パブリック IP の名前とアドレスはコマンド実行前に書き変える必要があります)
helm install emissary-ingress datawire/emissary-ingress \
 --namespace emissary \
 --set service.type=LoadBalancer \
 --set service.annotations.'service\.beta\.kubernetes\.io/azure-load-balancer-internal'='false' \ # AKS のパブリックなマネージドロードバランサーを指定する
 --set service.annotations.'service\.beta\.kubernetes\.io/azure-pip-name'='00000000-0000-0000-0000-000000000000' \ # マネージドなパブリック IP アドレスの名前を指定する (Azure Portal 上からリソースグループ MC_${RESOUCE_GROUP_NAME}_${AKS_NAME}_${LOCATION} を検索することで確認可能)
 --set service.loadBalancerIP='0.0.0.0' # マネージドなパブリック IP アドレスの値を指定する
kubectl -n emissary wait --for condition=available --timeout=90s deploy -lapp.kubernetes.io/instance=emissary-ingress

ここまで完了すると Emissary-Ingress の本体の起動と Emissary-Ingress が使用する CRD のインストールが完了します。

今回、Emissary-Ingress の Service は AKS のマネージドなパブリックロードバランサーを指定しています。
そのため、Emissary-Ingress の Service の External IP アドレスはマネージドなロードバランサーのフロントエンド IP 構成に紐づいたパブリック IP アドレスと同一の値になります。

下記のコマンドで得られた EXTERNAL_IP のアドレスとマネージドなロードバランサーに紐づいたパブリック IP アドレスが同じ値であることを確認します。

kubectl get svc -n emissary

Listener の作成

Listener を作成して、どのポートでリクエストを受け付けるかを設定します。

$ kubectl apply -f - <<EOF
---
apiVersion: getambassador.io/v3alpha1
kind: Listener
metadata:
 name: emissary-ingress-listener-8080
 namespace: emissary
spec:
 port: 8080
 protocol: HTTP
 securityModel: XFP
 hostBinding:
   namespace:
     from: ALL
EOF

Mapping の作成

次に、パスベースのルーティングを設定するための Mapping リソースを作成します。
設定するパスは下記の2つです。

  1. /web1/ - ストレージアカウント (stemissaryweb1) にホストした静的 Web ページ
  2. /web2/ - ストレージアカウント (stemissaryweb2) にホストした静的 Web ページ

では、Mappingリソースを作成します。

kubectl apply -f - <<EOF
---
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
 name: static-web-page1
spec:
 hostname: "*"
 prefix: /web1/
 service: https://stemissaryweb1.z11.web.core.windows.net
 host_rewrite: stemissaryweb1.z11.web.core.windows.net
---
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
 name: static-web-page2
spec:
 hostname: "*"
 prefix: /web2/
 service: https://stemissaryweb2.z11.web.core.windows.net
 host_rewrite: stemissaryweb2.z11.web.core.windows.net
EOF

これで必要なリソースの作成が完了になります。

動作確認

Emissary-Ingress 経由で、その背後にある静的 Web ページをホストしたストレージアカウントにアクセスします。
また、これに加えて、設定していないパスではアクセスできないことも確認します。
確認内容はこれら 3 件です。

  1. /web1/ でアクセスすると、ストレージアカウント1 にホストした静的 Web ページが表示される。
  2. /web2/ でアクセスすると、ストレージアカウント2 にホストした静的 Web ページが表示される。
  3. / でアクセスすると HTTP ステータスコード 404 が返される。

実際に下記のコマンドで確認します。

# マネージドなロードバランサーのパブリック IP アドレスを環境変数に設定する。
# ${PUBLIC_IP_ADDRESS} は実行前に書き変えて下さい。
export PUBLIC_IP='${PUBLIC_IP_ADDRESS}'
# ストレージアカウント1の静的 Web ページにアクセス
curl -i http://$PUBLIC_IP/web1/
# レスポンス
HTTP/1.1 200 OK
~ 省略 ~
<html><body><h1>Hello from Azure Storage 1!</h1></body></html>
# ストレージアカウント2の静的 Web ページにアクセス
curl -i http://$PUBLIC_IP/web2/
# レスポンス
HTTP/1.1 200 OK
~ 省略 ~
<html><body><h1>Hello from Azure Storage 2!</h1></body></html>
# Mapping に設定していないパスでリクエストを送る
curl -i http://$PUBLIC_IP/
# レスポンス
HTTP/1.1 404 Not Found
~ 省略 ~

まとめ

今回は、Emissary-Ingress を使用して AKS 上でパスベースのルーティングを実現する機能を実装しました。Emissary-Ingress は、Envoy Proxy をベースにした高性能な API ゲートウェイで、以下のような利点があります。

  • 柔軟なルーティング設定
  • Kubernetes CRD を使用した宣言的な設定
  • 高いパフォーマンスと信頼性

パスベースのルーティングは、特にマイクロサービスアーキテクチャのような、単一のエンドポイントから複数のサービスにトラフィックを分散する際に非常に有用です。今回の例では、Kubernetes 内のサービスと外部の Azure Storage へのルーティングを組み合わせましたが、実際のユースケースに応じて様々な設定が可能です。

Kubernetes を使用している際に、 API Gateway の基盤として Emissary-Ingress を検討してみてはどうでしょうか?

参考リンク