はじめに
今回のテーマは「AKSでDaprを使ってみる(5)Contourと組み合わせる」、
別名「AKSでContour Ingress Controllerを導入してみる(X)Daprと組み合わせる」
となります。ここまでやってきた DaprとContourが合流します。
以前DaprとNginx ingress controllerを組み合わせて利用する方法をご紹介しました。
Nginx ingress controllerでできるならば、Contourを利用した場合でも同様にできるはず、そう考える方も多いかと思います。 私も「前と同じようにやればOKだろう」と考えていましたが、実際やってみるとそれほど簡単ではなかった・・。 どうやればContourとDaprを組み合わせて利用できるか? その内容をご紹介できればと思います。
今回の作業目標
ベースとなる環境はContourの検証を行ってきたものとします。
全体的な構成はNginx ingress controllerの時と同じです。Contour(Envoy)のReverse ProxyにDaprのsiide carを入れ、 daprの通信で振り分けを実現します。
ただ、せっかく前回ContourのRequest RewritingやMultiple Upstreamという便利な機能もご紹介していますので、 これらもDaprと組み合わせて利用できるようになることを目指したいと思います。
ということで対象は、HTTPProxyオブジェクトによるルーティングだけに限定させて頂いております。
設定内容
Daprのインストール
Daprとotel-collectorのインストール
こちらの内容は以前の Nginx ingress controllerの時と同じものです。
dapr-config.yaml
global: logAsJson: true
helmでupdate --installを実行すればインストールできます。
helm repo add dapr https://dapr.github.io/helm-charts/ helm repo update helm upgrade --install dapr dapr/dapr \ --namespace dapr-system --create-namespace \ --values dapr-config.yaml
続いて OpenTelemetry Collectorのインストールです。サンプルソースコードにYamlが用意しておきました。そちらをデプロイします。
cat open-telemetry-collector-appinsights.yaml | envsubst | kubectl apply -f - kubectl apply -f collector-config.yaml
Contourの設定アップデート
次にContourをアップデートします。
contour: podAnnotations: # see https://projectcontour.io/guides/prometheus/ prometheus.io/scrape: "true" prometheus.io/path: "/metrics" prometheus.io/port: "8000" envoy: serviceAccount: # see https://github.com/dapr/dapr/issues/4227 we probably don't need this option from dapr 1.8 automountServiceAccountToken: true podAnnotations: # see https://projectcontour.io/guides/prometheus/ prometheus.io/scrape: "true" prometheus.io/path: "/stats/prometheus" prometheus.io/port: "8002" # 以下Dapr関連追加 dapr.io/config: "appconfig" dapr.io/enabled: "true" dapr.io/app-id: "contour-ingress" dapr.io/sidecar-listen-addresses: "0.0.0.0"
envoy.podAnnotations
にdaprの設定を追加します。
導入の際、当初は envoy.serviceAccount.automountServiceAccountToken
の指定はしませんでした。
ところが、この場合以下のIssueと同じエラー( Failed to init state store on xxx with error: "/home/noroot/.kube/config: no such file or directory" )が発生しました。
Issueの内容を参考にContourのheml templateを確認してみると、自動的にtokenをマウントする機能はcontour内で無効にされていました。 どうやらこの設定はDaprではエラーなってしまうようです。関連するチケットもあります。
Issue 4227で、今後のバージョン(おそらくdapr 1.8)で改善策を提供すると記載があるので、
今回はいったん automountServiceAccountToken
をtrueにすることにしました。
またdaprの設定には dapr-port
というものがあったと思います。
dapr-port 設定例
dapr.io/app-port: "80"
最初こちらの指定を入れていたのですが、contour envoyにinjectされるdaprd (dapr sidecar)の起動に失敗してしまいました。 ずっとこのportでアプリケーションの応答を待っているのですが受け取れず、タイムアウトしてしまうもののようです。
はっきりとした原因はまだ掴んでいませんが、 どうやらenvoyとdaprの指定が競合してしまうようです。 (類似のIssueが以下のものです)
このIssue同様Contour envoyは外部に対する公開はしますが、Daprによるデータ受信は行いません。 この場合 dapr-portは指定しなくてよいので、contour envoyの指定からは外しました。
設定内容で helm updateを実行します。
helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update helm upgrade --install ingress-contour bitnami/contour \ --namespace ingress-system --create-namespace \ --values config.yaml
アプリケーションデプロイの修正
アプリケーションの指定はNginx ingress controllerのときと同じです。
aggregator.yamlの抜粋
# 前省略 spec: selector: matchLabels: app: aggregator template: metadata: labels: app: aggregator annotations: dapr.io/enabled: "true" dapr.io/app-id: "aggregator" dapr.io/app-port: "8080" dapr.io/config: "appconfig"
同様の設定を aggregator-2やtimefeedにも行いデプロイします。 なお、aggregator/aggregator-2/timefeed 用に作成していたServiceは使用しない (service-id-daprというServiceが自動的にさくせされる)ため、削除します。
kubectl delete service -n web aggregator kubectl delete service -n web aggregator-2 kubectl delete service -n web timefeed export APPINSIGHTS_JAVA_AGENT_VER=3.2.10 export BASE64_INSTRUMENTATION_STRING=`echo -n ${AI_INSTRUMENTATION_STRING} | base64` cat timefeed.yaml | envsubst | kubectl apply -f - cat aggregator.yaml | envsubst | kubectl apply -f - cat aggregator-v2.yaml | envsubst | kubectl apply -f -
ルーティングの修正
Contour の設定で dapr-port
の指定をしないため解決しなければならない課題が1つあります。それは contour-ingress-dapr というサービスを自動的に作成しないということです。(aggregatorやtimefeedなどは aggregator-daprというサービスが作成されていると思います)
このcontour-ingress-daprに相当する指定は Routingの際の宛先として利用しますので、手動で作成する必要があります。aggregator/timefeedサービスで自動作成するものの内容を参考にcontour-ingress用のサービスを作成します。
(-daprという名称は今後Daprの自動作成と衝突する可能性もあるため、contour-ingress-headless と名称を変えています)
contour-ingreess-headless.yaml
apiVersion: v1 kind: Service metadata: name: contour-ingress-headless namespace: ingress-system spec: type: ClusterIP clusterIP: None ports: - name: dapr-htp port: 3500 - name: dapr-grpc port: 50001 - name: dapr-metrics port: 9090 selector: app.kubernetes.io/component: envoy app.kubernetes.io/instance: ingress-contour app.kubernetes.io/name: contour
続いてHTTPProxyの設定変更です。
http-proxy.yaml
apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: aggregator namespace: ingress-system # namespaceを webからingress-systemに変更 spec: virtualhost: fqdn: aggregator.${DOMAIN_NAME} tls: secretName: aggregator routes: - services: - name: contour-ingress-headless port: 3500 weight: 70 # Dapr通信用設定 requestHeadersPolicy: set: - name: dapr-app-id value: "aggregator.web" # Dapr通信設定ここまで - name: contour-ingress-headless port: 3500 weight: 30 # Dapr通信用設定 requestHeadersPolicy: set: - name: dapr-app-id value: "aggregator-2.web" # Dapr通信設定ここまで conditions: - prefix: /backend pathRewritePolicy: replacePrefix: - prefix: /backend replacement: / --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: aggregator namespace: ingress-system # namespaceを webからingres-system に変更 spec: commonName: aggregator.${DOMAIN_NAME} dnsNames: - aggregator.${DOMAIN_NAME} issuerRef: name: letsencrypt-prod kind: ClusterIssuer secretName: aggregator
まずポイントは転送先の指定方法です。
Nginx Controllerの際は 転送先ホストを Nginx(nginx-ingress )転送先パスを Daprのインターフェースに従い
/v1.0/invoke/${service-id}/method/$1
と指定していました。今回も、と思いましたがHTTPProxyの pathRewritePolicy
が転送先ホストごとではなく
転送先グループでしか指定できません。(aggregatorまたはaggregator-2への転送振り分けのグループ単位) ${service-id}の部分が固定となってしまいます。
ここでDaprのService Invocationインターフェースの別のやり方を採用します。実は Daprのインターフェースはパス名だけではなく、Request Headerに転送先サービスIDを設定することでも実現できまます。
転送内容 service: service-id path:/$1 の指定方法。
転送先ホストは daprの localhost(ingress-dapr):3500 )
形式 | ヘッダ | パス |
---|---|---|
パス名指定 | 指定なし | /v1.0/invoke/${service-id}/method/$1 |
ヘッダ指定 | dapr-app-id: service-id | /$1 |
HTTPProxyのRequest Rewriting には requestHeadersPolicy
というヘッダ情報追加更新の機能もあります。こちらはサービス転送先単位で指定できます。よって、転送先パス名はaggregator/aggregator-2ともに同じ /$1
とし、ヘッダ情報に転送先を埋め込むことにします。
その指定がこちらの部分です。
- services: - name: contour-ingress-headless # 省略 requestHeadersPolicy: set: - name: dapr-app-id value: "aggregator.web" # 省略 conditions: - prefix: /backend pathRewritePolicy: replacePrefix: - prefix: /backend replacement: /
なお転送先ホスト名は手動で作成する contour-ingress-headless
となります。
こちらはContourが動作する ingress-system namespaceに作成します。
そのサービス名を参照するために aggregator HTTPProxy指定やCertificateのnamespaceも web
から
ingress-system
とし、 dapr-app-idをaggregator.web
とdapr namespace付きの名称としています。
これらをデプロイします。
kubectl apply -f contour-ingress-headless.yaml cat http-proxy.yaml | envsubst | kubectl apply -f -
動作確認をしてみましょう
ブラウザから https://aggregator.${DOMAIN_NAME}/backend/service
すると以下の左右いずれかの画面が表示されると
思います。これで、
「AKSでContour Ingress Controllerを導入してみる(3)Multiple Upstream」の環境で
Daprが利用可能になりました。
Contour EnvoyへのDapr Sidecarの導入でかなり苦労しましたが、なんとか実現できました。 また、ContourのRequest Rewriting機能にも助けられました。
いつものように設定内容は以下のGitHub Repositoryで公開しています。
おわりに
それぞれのサービスのドキュメントから類推すると「この組み合わせは簡単にできるはず」と思ったことが 実はそれほど簡単ではなかった、やはりある程度やってみないとわからないことがあるものです。 今回のDaprとContourの組み合わせもその一例になるかと思います。 そうした知見をどれだけ効果的に得られるかがこうした調査・検証では重要になってくると実感する内容でした。
最終目標はこの構成にさらに Open Service Meshや KEDAを加え、Azure Container Apps相当の機能をAKS上でも実現することですが、 それらを追加するのは少し時間をおいてからにしたいと思います。その際は内容を公開していきたいと思いますので またお付き合いください。
最後に宣伝。 弊社エンジニアが協力した、「AKSのセキュリティ対策に関するホワイトペーパー」の3,4章がMicrosoftから公開されました。
ホワイトペーパー本体はこちらです。 ぜひご覧頂きたいと思います。
私たちは、Azure・AKSを活用したシステムのSIや内製化のお手伝いをさせていただいております。 Azureやコンテナ技術の知見を持つエンジニアが対応いたします。ご相談等ありましたらぜひご連絡ください。