はじめに
AKSでContour Ingress Controllerを導入する。本体のインストール(1)、Let's Encrpytによるhttps有効化(2)に引き続いて今回が第3回です。
第3回は前回に引き続き、Contur Ingress Controllerの「プラスアルファ」な機能をご紹介していきたいと思います。
プラスアルファな機能
Request Rewriting
先日公開した(1)ではホスト名ごとに転送先バックエンドを設定しました。もちろんnginx ingress controller同様パス名毎に転送先を変更することもできます。それがRequest Rewriting機能です。
Requestの内容に対して、条件に合致したものRequestを書き換える機能、それがRequest Rewritingです。パスプレフィックスの書き換えだけではなく、Request Headerの追加・更新・削除も行うことができます。
今回は一番単純なパスプレフィックスの書き換えを行います。変更内容は以下のとおりです。
新旧 | 外部向けPath | 転送先パス |
---|---|---|
旧 | /* | /* |
新 | /backend/* | /* |
(旧)はこれまで設定してきた内容です。これに対して(新)では外部向けにプレフィックス(backend)を追加します。
変更内容はこちらになります。
http-proxy.yaml
apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: aggregator namespace: web spec: virtualhost: fqdn: aggregator.${DOMAIN_NAME} tls: secretName: aggregator routes: - services: - name: aggregator port: 8080 # 追加ここから conditions: - prefix: /backend pathRewritePolicy: replacePrefix: - prefix: /backend replacement: / # 追加ここまで
これをデプロイすると完了です。
export DOMAIN_NAME="put your domain name" cat http-proxy.yaml | envsubst | kubectl apply -f -
修正前は curl -v https://aggregator.${DOMAIN_NAME}/service
でアクセスできていましたが、変更後はアクセスできません。
代わりに curl -v https://aggregator.${DOMAIN_NAME}/backend/service
でアクセスしてみましょう。修正前と同様の応答があると思います。
簡単ですね。
1つだけ注意が必要な点があります。それは書き換えはRequest Pathのみということです。Response は書き換えてくれません。 HTMLの中に絶対パスで記載されたURLなどはそのままブラウザに返されます。また、301/302 のResponseにあるリダイレクトのパスも書き換えません。 したがってパスの書き換えに関してはREST APIサーバーなどパス情報を含まない状況で活用したほうがよいでしょう。
Request Routing (Multiple Upstream)
もうひとつプラスアルファな機能となるのが Service Meshなどでもよく実現されている Multiple Upstream です。1つのリクエストの転送先として複数のバックエンドを指定することができます。A/BテストのようなこともContour Ingress Controllerだけで実現できてしまうんですね。
やり方は簡単。
まずは新しいバージョンのアプリケーションをデプロイしましょう。サンプルアプリケーションを少し修正し、複数のバージョンが動いていることがわかるようにします。
こちらをACRにプッシュしてアプリケーションの準備はOKです。続いてアプリケーションのデプロイです。 今回は新旧両バージョンのAggregatorを実行しますので、新バージョンを別名のサービスとしてデプロイします。
aggregator-v2.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: aggregator-2 namespace: web labels: app: aggregator-2 spec: selector: matchLabels: app: aggregator-2 template: metadata: labels: app: aggregator-2 spec: containers: - name: aggregator image: ${ACR_NAME}.azurecr.io/dapr-sample/aggregator:0.2.0-SNAPSHOT imagePullPolicy: Always ports: - containerPort: 8080 volumeMounts: - mountPath: /shared/java-agent name: java-agent readOnly: true env: - name: TITLE_VERSION value: v2.0 - name: JAVA_TOOL_OPTIONS value: "-javaagent:/shared/java-agent/applicationinsights-agent.jar -Dreactor.netty.http.server.accessLogEnabled=true" - name: TIMEFEED_HOST value: http://timefeed:8080 - name: TIMEFEED_BASE value: / - name: SPRING_MAIN_BANNER-MODE value: "off" - name: APPLICATIONINSIGHTS_ROLE_NAME value: aggregator-web - name: APPLICATIONINSIGHTS_CONNECTION_STRING valueFrom: secretKeyRef: name: instrumentation-string key: instrumentationString initContainers: - name: init-agent image: ${ACR_NAME}.azurecr.io/applicationinsights-agent:${APPINSIGHTS_JAVA_AGENT_VER} command: ["cp", "applicationinsights-agent.jar", "/shared/java-agent/applicationinsights-agent.jar"] volumeMounts: - mountPath: /shared/java-agent name: java-agent volumes: - name: java-agent emptyDir: {} --- apiVersion: v1 kind: Service metadata: name: aggregator-2 namespace: web spec: type: ClusterIP ports: - port: 8080 selector: app: aggregator-2
内容はaggregatorのものそのままですが、名称をaggregator-2に変更しています。また、異なるバージョンとわかるように画面上にその内容を表示するようにしました。表示内容は以下の環境変数で定義しています。
- name: TITLE_VERSION value: v2.0
こちらをデプロイします。
cat aggregator-v2.yaml | envsubst | kubectl apply -f -
さらにHTTPProxyの設定を変更します。
http-proxy.yaml
apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: aggregator namespace: web spec: virtualhost: fqdn: aggregator.${DOMAIN_NAME} tls: secretName: aggregator routes: - services: - name: aggregator port: 8080 weight: 70 # 旧バージョンは70%振り分け - name: aggregator-2 port: 8080 weight: 30 # 新バージョンは30%振り分け conditions: - prefix: /backend pathRewritePolicy: replacePrefix: - prefix: /backend replacement: /
spec.routesに2つのバージョンを並べ振り分け比率を定義しています。こちらをデプロイして準備は完了です。
cat http-proxy.yaml | envsubst | kubectl apply -f -
ブラウザでアクセス・リロードを繰り返すと、旧バージョンのもの(左図)と新バージョン(右図)の両方が表示されると思います。
この機能でA/Bテストを実行する、またはカナリアデプロイを実現するといったことが可能になります。
External authorization
実は本当にやりたかったのは External Authorizationでした。 External Authorizationの追加機能として contour-authserverがあります。5月3日に公開されたv3ではOIDC対応が追加されていました。 であればAzure ADなどで認証・認可もできるのではないか、そう考え早速トライしたのでした。
ところが、、、うまくいきませんでした。このため今回はあまり紹介はできません。 設定はできたのですが、envoy => contour-authserver間のgRPC接続で TLSV1_ALERT_PROTOCOL_VERSION でエラーとなってしまいました。まさに、Issue の内容です。
今回はExternal authorizationという機能もあるよ、ということだけにとどめたいと思います。時間が取れれば後日対応方法を考えたいと思います、一応、実際にトライしたコードは公開します。
Envoy / Contour関連のニュース
5月16日、Envoy Gatewayに関するアナウンスがありました。
その中で、Contour・Emissary2つのEnvoyベースのプロジェクトをEnvoyにマージしていくと発表されています。
Merging the existing CNCF API gateway projects (Contour and Emissary) into a common core that can provide the best possible onboarding experience, while still allowing vendors to build value-added solutions based on Envoy Proxy and Envoy Gateway.
現在の機能は引き続き提供されると思いますし、統合されより多くの機能が追加されていくとこが期待されます。 (今回エラーとなった contour-authserver などももっと改善スピードがあがるかもしれません)
今後のEnvoy Gatewayにさらに注目していきたいと思います。
おわりに
いつものように検証で利用したコードは以下のGitHub Repositoryで公開しています。
最後に宣伝。
弊社エンジニアが協力した、「AKSのセキュリティ対策に関するホワイトペーパー」の3,4章がMicrosoftから公開されました。
ホワイトペーパー本体はこちらです。 ぜひご覧頂きたいと思います。
私たちは、Azure・AKSを活用したシステムのSIや内製化のお手伝いをさせていただいております。 Azureやコンテナ技術の知見を持つエンジニアが対応いたします。ご相談等ありましたらぜひご連絡ください。