APC 技術ブログ

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

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

AKSで Contour Ingress Controllerを導入してみる(1)

はじめに

5月15日はJリーグの日。 1993年の今日(5月15日)Jリーグが開幕しました。Jリーグ開幕試合はヴェルディ川崎 vs 横浜マリノス、場所は旧国立霞ヶ丘競技場。 キックオフは19:29だったそうです。 そんな歴史的な日を記念してこの記事は5月15日19:29に投稿しています。

前置きはこれくらいにして、突然ですがみなさんはIngress controllerに何をご利用でしょうか? よく利用されるのはnginx ingress controllerだと思います。 普通のReverse proxyとしてnginx ingress controllerは十分な機能を提供しています。 ただ「もうちょっと高機能だったらいいのに」と感じるケースもあるかと思います。

最近、まさにその「もうちょっと」なことを実現したいなというケースに遭遇しました。

こうしたときに選択肢の1つとして挙げられるのがContourというIngress controllerです。 ContourはEnvoy proxyをベースにしたL7 reverse proxyで、2017年にHeptioが開発、公開しました。現在はCNCFのIncubating projectとなっています。 Heptio社がVMware社に買収されたこともあり、VMWare Tanzuでも利用可能なIngress controllerです。 またMicrosoftが主要開発元となっているOpen service meshでもサポートするIngress controllerの1つでもあります。 Ingress v1もサポートしていますが、独自にCRDも提供しておりEnvoyの様々な機能を利用することができるという 特徴を持っています。たとえば以下のような機能が利用できます。

これがすべてではありません。そう考えるとだんだん「使ってみようかな」と思えてきたのではないでしょうか。

今回はContour ingress controllerのAKSクラスターへの導入方法を紹介していきたいと思います。

想定システムイメージ

アプリケーション部分は以前Daprの紹介の際に利用したものを使います。
(HTTP呼出しならば、設定を変更するだけでDaprの有無にかかわらず動作する、というのはDaprの利点でもありますね)

構成は以前の記事と同様です(もちろん、Ingress controllerがContourになります)。

インストール

Contourのインストール

まずContourをインストールします。ここではhelmを利用します。 インストール先のnamespaceは ingress-system とします。chartはこちらを利用します。

また、ContourはPrometheusによるメトリックス収集に対応しています。 そちらも有効にしたいと思います。 設定はこちらの内容となります。

config.yaml

contour:
  podAnnotations:
    # see https://projectcontour.io/guides/prometheus/
    prometheus.io/scrape: "true"
    prometheus.io/path: "/metrics"
    prometheus.io/port: "8000"
envoy:
  podAnnotations:
    # see https://projectcontour.io/guides/prometheus/
    prometheus.io/scrape: "true"
    prometheus.io/path: "/stats/prometheus"
    prometheus.io/port: "8002"

実行コマンドは以下のとおりです。

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

これでContourのインストールは完了です。

アプリケーションのデプロイ

想定システムイメージのところでも説明したとおり、アプリケーションはdapr-sampleのものを利用します。 appinsights-agentaks-helloworldaggregatortimefeed アプリケーションのコンテナイメージをあらかじめ作成しContena Registryにプッシュしておいてください。

それをそれぞれ指定したnamespaceにデプロイします。参考として aggregator 用の設定をご紹介します。

aggregator.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: web
---
apiVersion: v1
kind: Secret
metadata:
  name: instrumentation-string
  namespace: web
type: Opaque
data:
  instrumentationString: ${BASE64_INSTRUMENTATION_STRING}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: aggregator
  namespace: web
  labels:
    app: aggregator
spec:
  selector:
    matchLabels:
      app: aggregator
  template:
    metadata:
      labels:
        app: aggregator
    spec:
      containers:
      - name: aggregator
        image: ${ACR_NAME}.azurecr.io/dapr-sample/aggregator:0.1.0-SNAPSHOT
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
        volumeMounts:
        - mountPath: /shared/java-agent
          name: java-agent
          readOnly: true
        env:
        - 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
  namespace: web
spec:
  type: ClusterIP
  ports:
  - port: 8080
  selector:
    app: aggregator

このあたりは普通のアプリケーションでも同様ですので、説明は省略します。デプロイ方法は以下のとおりです。

export APPINSIGHTS_JAVA_AGENT_VER=3.2.10
export BASE64_INSTRUMENTATION_STRING=`echo -n ${AI_INSTRUMENTATION_STRING} | base64`
cat aggregator.yaml | envsubst | kubectl apply -f -

Ingressによるルーティング

それではまず、kubernetesのIngressを使用したルーティングを設定してみましょう。

ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cont-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: contour
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  defaultBackend:
    service:
      name: aks-helloworld
      port:
        number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cont-ingress
  namespace: web
  annotations:
    kubernetes.io/ingress.class: contour
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  rules:
  - host: aggregator.${DOMAIN_NAME}
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: aggregator
            port:
              number: 8080

こちらの内容もnginx ingress controllerを利用した時と変わりません。唯一違うとすれば ingress.classの指定が contour になっていることでしょうか。 こちらもdeployします。

cat ingress.yaml | envsubst | kubectl apply -f -

これで aks-helloworldやaggregatorにアクセスできるようになると思います。

curl -v http://aks-helloworld.${DOMAIN_NAME}/
curl -v http://aggregator.${DOMAIN_NAME}/service

通常のingressがサポートされているということがこれでわかります。

HTTPProxyによるルーティング

ContourではIngressの設定以外にもHTTPProxyという設定によってルーティングを設定できます。 さまざまな付加機能がありますが、 ingressでそれを指定することはできません。ということでContourを利用する場合にはIngressではなく、 このHTTPProxyを利用することが多いようです。

さきほどのIngressの設定と同等のものをHTTPProxyで指定してみましょう。 まずはIngressの設定を削除します。

cat ingress.yaml | envsubst | kubectl delete -f -

つづいてHTTPProxyの設定です。

http-proxy.yaml

apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: aggregator
  namespace: web
spec:
  virtualhost:
    fqdn: aggregator.${DOMAIN_NAME}
  routes:
    - services:
      - name: aggregator
        port: 8080
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: aks-helloworld
  namespace: default
spec:
  virtualhost:
    fqdn: aks-helloworld.${DOMAIN_NAME}
  includes:
  - name: default-web
    namespace: default
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: default-web
  namespace: default
spec:
  routes:
    - services:
      - name: aks-helloworld
        port: 80

HTTPProxyではVirtulaHost単位で1つのHTTPProxy設定をします。 1つのファイルで複数のVirtualHostを定義できるIngressとはこの点が異なります。

こちらもデプロイしてみましょう。

cat http-proxy.yaml | envsubst | kubectl apply -f -

結果確認はIngressの時と同様です。

curl -v http://aks-helloworld.${DOMAIN_NAME}/
curl -v http://aggregator.${DOMAIN_NAME}/service

設定内容もそれほど難しいものはなく、IngressとHTTPProxyでまったく同じ動作が確認できます。

アプリケーション動作

今回の内容とは関係ありませんが、Application InsightsのJavaAgentも前回のDaprサンプル同様導入していますので、分散トレーシングも確認することができます。 残念ながらContourのDistributed Tracing対応についてはまだ確認できていませんので設定できていません。 したがってトレーシングの起点はAggregatorアプリケーションからとなっています。

ここまでは比較的簡単に実現できました。

お知らせ

今回はAKSにインストールし、一般的なReverse proxy機能だけを実現しました。 次回は 「もうちょっと(プラスアルファ)」な機能を加えていきたいと思います。 どんな機能を追加するはは次回のお楽しみということで。

利用した設定ファイル等は以下のGitHub repository にて公開しています。

最後に宣伝。 私たちは、Azure・AKSを活用したシステムのSIや内製化のお手伝いをさせていただいております。 Azureやコンテナ技術の知見を持つエンジニアが対応いたします。ご相談等ありましたらぜひご連絡ください。

それではまた。