
はじめに
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.
本記事では、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つです。
- /web1/ - ストレージアカウント (stemissaryweb1) にホストした静的 Web ページ
- /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 件です。
- /web1/ でアクセスすると、ストレージアカウント1 にホストした静的 Web ページが表示される。
- /web2/ でアクセスすると、ストレージアカウント2 にホストした静的 Web ページが表示される。
- / でアクセスすると 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 を検討してみてはどうでしょうか?