KubernetesクラスターでのWebアプリケーションゲートウェイ(Ingress)の構成について整理する


前回のブログでは、Kubernetesクラスターに対するL4アクセス制御をAzure Kubernetes Serviceを例にして整理しました。

しかしながら、多くのケースではWebアプリケーションへの急激なトラフィックの増加やトランザクションの集中にも対応できるようにするだけでなく、バックエンドサーバー群に効率よくルーティングする機能やSSL終端、またDDoS攻撃からの防御やSQLインジェクションなどから保護するWeb Application FirewallなどL7でのアクセス制御が必要です。さらに流量制御や証明書管理などなど、さまざまな非機能要件があります。

で、基盤方式設計フェーズでは、これらの処理をだれがどこでどう行うか?の処理方式を検討しておく必要があるわけですが。。。

レジェンドな企業の多くの場合は、アプリケーション開発部門とインフラ構築部門、運用保守部門が組織として分かれているケースが多く、Webアプリケーションのゲートウェイ機能の方式設計は、インフラ構築部門が行い、共通基盤化してアプリ開発チームに引き渡し、運用フェーズになると運用保守部門にてメンテナンスすることがおおいでしょう。 大規模なシステムの場合、組織での責任分界点も踏まえたうえで、基盤方式設計を行うというのは極めて大事です。

システム内でKubernetesを利用する場合、L7ロードバランサの方式設計時に考慮しておくべきことがいくつかありますので、簡単なメモ書きとしてまとめます。

Kubernetes でのWebアプリケーションゲートウェイの構成パターン

Kubernetes では、L7ロードバランシングを提供するとき、「Ingress」というリソースを使います。これは、HTTP やHTTPS の外部アクセスを制御するオブジェクトで、バーチャルホストやURLルーティング、ロードバランシング、SSL 終端などの機能を提供するものです。

Kubernetes のIngressには大きく分けて次の2つがあります。

クラスタ内でゲートウェイ処理を行うパターン

これは、Kubernetes クラスター内でソフトウエアとしてWebアプリケーションゲートウェイの機能を動かすパターンです。Kubernetesクラスターからみるとコンテナアプリケーション(Pod)として動作し、これがミドルウエアの機能を果たします。

代表的なものがNginx Ingress Controller で、そのほかにもContour やContainous 社のTraefik、HAProxy などがあります。

クラスタ外でゲートウェイ処理を行うパターン

ゲートウェイで処理したいもののなかには、SSL 終端のようにコンピューティングリソースを多く使うものもあったりします。 そのため、ゲートウェイ処理に特化したのものをクラスタ外部で動かし、クラスタとは疎結合にしておきたい!というニーズもあります。 普段オンプレをメインに担当されている方は、直感的に理解できるかと思います。

たとえばAzureの場合「Azure Application Gateway」という専用のサービスがあり、バックエンドがKuberbetes に限らずAzure 上の仮想マシンやオンプレなどのバックエンドもサポートできるものが提供されています。 またGCP の場合だと「Cloud Load Balancing」という最強サービスがあります。

これらを使ってバックエンドにKuberbetes クラスターをおいてあげれば、よさそうです。

Web アプリケーションゲートウェイの設定はどう運用するのか?

URLルーティングなどはアプリケーション開発者の関心ごとである一方、特にマルチクラウドでシステムを運用している場合、各クラウドごとに実装の異なるL7 ロードバランサーの操作手順をいちいち勉強するのはあまりテンションがあがるものではないでしょう。

しかもそれがものすごい勢いでアップデートしていくわけなので、だれかに任せたい気分になるとおもいます。

KubernetesでWeb アプリケーションゲートウェイの設定変更したり監視したりなどの運用保守を考えるとき、次の2つのパターンが考えられます。

運用管理者が行う方法

オンプレや仮想マシンベースのアーキテクチャの場合、URL ルーティングのポリシーの管理などはシステム変更があるたびにアプリケーション開発者からインフラ運用部門に変更依頼や承認などを経て、人間の手を介して本番環境へ反映するケースが多いと思います。

しかしながら、人間には信頼性がないことが広く知られています。

万全な冗長構成をとり基盤テストを繰り返して99.99999…を追求し、広域災害にも配慮した方式設計にすることでシステムの可用性もコストも高まり、クラウドベンダーは喜びます。しかしながら、SLAのない人間による手作業による温かみのあるURL ルーティングの設定変更がsingle point of failure になる可能性もありますので、運用方式設計にきちんと盛り込んでおきましょう!

が、すでに既存のシステムでなんらかのWeb アプリケーションゲートウェイを導入済みで、それらの運用スタイルが確立していて特に問題がないようであれば、使い慣れたものをそのまま利用するのもよいでしょう。

Azure の場合だと、すでにApplication Gateway を稼働中であればバックエンドサーバー群にAKS を配置してロードバランシングやルーティングなどを配置すればよいでしょう。なによりシステム構成がシンプルで直感的です。 アプリケーション開発者と運用保守エンジニアの心の距離が近い、または同一人物である、などの組織であれば、フレキシブルに対応できると思います。

Kubernetes から自動で設定を行う方法

KuberbetesではIngress の設定を行うコントローラーがあり、これを「Ingress Controller」とよびます。Ingress/Ingress Controller をつかうとL7 ロードバランサの実装の差を吸収し、抽象化できます。

Ingress Controller は実装によって異なるので、ここではAzure を例に説明します。

Application Gateway Ingress Controller の場合

Application Gateway Ingress Controller(AGIC) はAzure Kubernetes Service 上で動くコンテナアプリケーションです。このアプリから直接、Azure Application Gateway L7 ロードバランサーを操作できるものです。厳密にいうと、Azure Resource Manager というAzure のサービスをコントロールするしくみを介して操作します。

Kubernetes のIngress のリソースの設定ファイルは、だいたいこんな感じで、path によってBackend のルーティング先を振り分けるんだなと直感的に分かると思います。これをAKS クラスタにapply すると、AGIC を介してApplication Gateway が操作できます。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-world-ingress
  namespace: ingress-basic
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: aks-helloworld
          servicePort: 80
        path: /(.*)
      - backend:
          serviceName: ingress-demo
          servicePort: 80
        path: /hello-world-two(/|$)(.*)

現在、AKS とAGIC を連携してできる主な機能は以下の通りです。

その他使用可能なAGIC機能のリストはこちらになります。

Ingress Controller を使うと、Ingress のルールがKubernetes のマニュフェストとして管理できます。Kubernetes のReconciliation Loop にのっかれますので、宣言ベースでインフラを保持できます。

Reconciliation Loopってなに?という方はまかべさんによる資料Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーをぜひ。

また、インフラの構成情報がコードとして管理できるので、GitOps のようなしくみを導入してPipeline に組み込むことができます。アプリケーションのCI/CD だけでなく、インフラ部分もなるべく人手を介さないオペレーションで本番環境にデプロイできるのは、システム全体の可用性を向上させるという点でも重要なポイントです。

KubernetesのIngress を覚えるだけで、実装の差異はIngress Controller が吸収し抽象化してくれるので、さまざまなスキルセットの人が混在する大規模開発などでも展開しやすいでしょう。

AKS の場合はApplication Gateway が、GKEの場合はCloud Load Balancing が実体として動くわけなのですが、これらをアプリケーション開発者が強く意識しなくてもよいのは助かります。

Azure でApplication Gateway Ingress Controller を使うときの注意点は?

Kubernetes Ingress の仕様では、Application Gatewayのすべての機能をIngress リソースを通じて公開することは許可されていません。したがって、Application GatewayのIngress Controller 固有のアノテーションを設定する必要があります。

Annotation KeyValue TypeDefault ValueAllowed Values
appgw.ingress.kubernetes.io/backend-path-prefixstringnil
appgw.ingress.kubernetes.io/backend-hostnamestringnil
appgw.ingress.kubernetes.io/backend-protocolstringhttphttp, https
appgw.ingress.kubernetes.io/ssl-redirectboolfalse
appgw.ingress.kubernetes.io/appgw-ssl-certificatestringnil
appgw.ingress.kubernetes.io/appgw-trusted-root-certificatestringnil
appgw.ingress.kubernetes.io/connection-drainingboolfalse
appgw.ingress.kubernetes.io/connection-draining-timeoutint32 (seconds)30
appgw.ingress.kubernetes.io/cookie-based-affinityboolfalse
appgw.ingress.kubernetes.io/request-timeoutint32 (seconds)30
appgw.ingress.kubernetes.io/use-private-ipboolfalse
appgw.ingress.kubernetes.io/waf-policy-for-pathstring

サポートされているアノテーションの詳細はこちらになります。

また、Application Gateway Ingress Controller を使いたい大きなモチベーションの1つにApplication Gateway のメトリックを使用した AKS 上のPod のオートスケールがあるとおもいます。

スパイクアクセスで着信トラフィックが急増増えたとき、需要に応じてPod をオートスケールさせたいわけですが、デフォルトだとAKS ノードのCPU やメモリなどを監視してのスケーリングとなります。このスケーリングのトリガーとしてApplication Gateway のメトリックを使う機能が提供されています。が、現在はまだベータ公開中ですのでプロダクション環境ではご利用いただけません。

その他Application Gateway Ingress Controllerのソースコードはこちらですので、ご興味あるかたはぜひ!

Nginx Ingress Controller の場合

クラスタ外部にAzure Application Gateway を配置するとそれを利用するための料金が発生します。

そのため、AKS 上でNginx を動かしURLルーティングやSSL終端などを行わせることもできます。 これもIngress Controller が提供されているので、KubernetesのIngress リソースを使って、Ngnixの設定変更ができます。

AKS でNginx Ingress Controller を使うときはこちらの手順になります。Helm を使ってインストールできますのでそれほど大変ではないとおもいます。Ingress リソースのマニュフェストは次のような感じとなり、annotationskubernetes.io/ingress.class: nginxを指定します。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-world-ingress
  namespace: ingress-basic
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: aks-helloworld-one
          servicePort: 80
        path: /(.*)
      - backend:
          serviceName: aks-helloworld-two
          servicePort: 80
        path: /hello-world-two(/|$)(.*)

まとめ

Kubernetesクラスターに対するL7でのWebアプリケーションのゲートウェイ処理について整理しました。

Kubernetesはじめクラウドネイティブな世界でのDevOpsでは、GitOpsという方法が注目されています。すぱぶらさんがめちゃくちゃ分かりやすい資料Kubernetes で実践するクラウドネイティブ DevOpsを公開してくださったので、こちらをぜひ読んでください。

参考情報