APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

AKSでContour Ingress Controllerを導入してみる(3)Multiple Upstream

はじめに

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だけで実現できてしまうんですね。

やり方は簡単。

まずは新しいバージョンのアプリケーションをデプロイしましょう。サンプルアプリケーションを少し修正し、複数のバージョンが動いていることがわかるようにします。

github.com

こちらを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やコンテナ技術の知見を持つエンジニアが対応いたします。ご相談等ありましたらぜひご連絡ください。