1
/
5

【TECH BLOG】動作検証しながら理解する「Kubernetes Gateway API」と「GKE Gateway Controller」

はじめに

こんにちは、技術本部 データサイエンス部 MLOpsブロックの鹿山(@Ash_Kayamin)です。

みなさんは2021年4月にGCPから「GKE Gateway コントローラによる Kubernetes ネットワーキングの進化」という記事が投稿されたのを覚えていますでしょうか。



この記事は、Kubernetesコミュニティが発表したKubernetes Gateway APIに対し、そのGKE(Google Kubernetes Engine)版実装であるGKE Gateway Controllerのリリースをアナウンスするものでした。

それから半年が経ち、本番導入の可能性を模索するためにKubernetes Gateway APIとGKE Gateway Controllerを調査、動作検証しました。本記事では、Kubernetes Gateway APIの概要と、APIで定義されるトラフィックのルーティングがGKE Gateway ControllerによってどのようにGCP上で実現されるのかを、動作検証の流れに沿って解説します。

なお、2021年11月時点で、Kubernetes Gateway APIの最新バージョンはv1alpha2、GKE Gateway ControllerがサポートするGateway APIのバージョンはv1alpha1であり、今後仕様が大きく変わる可能性がある点にご注意ください。

Kubernetes Gateway APIの開発背景と特徴

よりスムーズに理解していただくために、Kubernetes Gateway APIが作成された背景から順にご紹介します。

Kubernetes Gateway APIが開発された背景

Gateway API(Kubernetes Gateway API)はIngress API(Kubernetes Ingress API)の課題を解消するために開発されました。

そのIngress APIは、Kubernetesクラスタ外部からクラスタ内Service(Kubernetes Service)に対し、アプリケーション層でHTTPやHTTPSを用いたルーティングを制御するAPIです。多数のプロバイダーでIngress APIの仕様に則ったIngress Controllerが実装されています。また、Ingress Controllerの実装によっては負荷分散やSSL終端といった機能も提供します。MLOpsブロックでもGKEでコンテナネイティブな負荷分散を利用するために、GCPが提供するIngress ControllerであるGLBCを利用しています。GLBCはIngress APIを通して、GCLB(Google Cloud Load Balancing)を用いたルーティングの設定が可能です。そのIngress APIは、Kubernetesクラスタ外部からクラスタ内Service

実は、Ingress APIでは非常にシンプルな機能を実現するための仕様しか定義されていません。そのため、Ingress Controllerのプロバイダー、Ingress Controllerの利用者それぞれに以下の負担が発生していました。

  • のManifestに独自のannotationを定義する必要があるIngress APIでは定義されていないトラフィックの荷重ルーティング等の機能を追加するには、プロバイダーはIngress
  • 開発者はプロバイダー毎にannotationが大きく異なるManifestを書かなくてはならない

例えば、各Ingress Controller毎にannotationへ定義可能な設定項目数を比較すると以下のように大きな差があります。

・GLBC:6個
  GLBCで利用可能なannotation 内部LBの場合
GLBCで利用可能なannotation 外部LBの場合

・AWS Load Balancer Controller:40個
  AWS Load Balancer Controllerで利用可能なannotation

・NGINX Ingress Controller:110個
  NGINX Ingress Controllerで利用可能なannotation

これは、対応している機能や、設定項目の表現方法(annotationのみを使うのか、annotationとCR(Custom Resource)を組み合わせるのか等)が異なるため、結果としてannotationの数に大きな差が生じています。

例えば、L7外部ロードバランサーを定義して、ロードバランサーをSSL終端とし、バックエンドのサービスへのヘルスチェックを設定することを考えてみます。

AWS Load Balancer Controllerを用いる場合のManifestは以下のように定義します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: zozo-techblog
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:xxxx
alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
alb.ingress.kubernetes.io/healthcheck-port: '80'
alb.ingress.kubernetes.io/healthcheck-path: /health
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: zozo-techblog
servicePort: 80

一方、GLBCを用いる場合のManifestは以下のように定義します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: zozo-techblog-ingress
annotations:
kubernetes.io/ingress.allow-http: "false"
ingress.gcp.kubernetes.io/pre-shared-cert: "api-cert"
spec:
defaultBackend:
service:
name: zozo-techblog-service
port:
number: 80
---
apiVersion: v1
kind: Service
metadata:
name: zozo-techblog-service
annotations:
cloud.google.com/neg: '{"ingress": true}' # ref. https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing
# BackendConfigを用いてヘルスチェック等をサービス毎にカスタマイズする
cloud.google.com/backend-config: '{"default": "zozo-techblog-backendconfig"}'
spec:
selector:
app: zozo-techblog-pod
ports:
- port: 80
protocol: TCP
targetPort: 8080
---
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
name: zozo-techblog-backendconfig
spec:
healthCheck:
checkIntervalSec: 15
type: HTTP
port: 8080
requestPath: /health

annotationが異なるのはもちろんですが、ヘルスチェックの指定方法が大きく異なっていることが分かります。AWS Load Balancer ControllerではIngressのannotationにヘルスチェックの定義を記載します。一方、GLBCを用いる場合はBackendConfigというCRにヘルスチェックの定義を記載します。そこでは、Ingressで指定するServiceのannotationでBackendConfigを指定する必要があります。

また、L7ロードバランサーの機能への対応状況も大きく差があります。例えば、AWS Load Balancer ControllerではService毎に割合を指定することでトラフィックの細かな分割ができます。一方、GLBCではトラフィックの分割割合の指定はできません。GLBCで設定をするL7ロードバランサーGCLBにはトラフィックの分割割合を指定する機能は存在します。しかしながら、現状GLBCにはGCLBでのトラフィック分割割合を設定する機能は実装されていません。L7ロードバランサーを構成するなら当然利用できるはずだと思う機能も、現状では利用できるかどうかはプロバイダー次第となってしまっています。

このように、Ingress Controller毎に対応している機能や設定項目の表現方法が大きく異なります。そのため、開発者が普段とは異なるIngress Controllerを利用する際には、Manifestを書くことに苦労します。

Gateway APIは、この問題を解消するために開発されました。Gateway APIはL4/L7ロードバランサーで実現可能なルーティングをできる限り共通の仕様で実現できるように配慮しています。

また、Ingress APIでは、L7でのServiceへのルーティングの定義を1つのリソースで定義していました。一方、Gateway APIではルーティングの定義を責務毎に、3種類のリソースに分割しています。リソースを分割することで権限管理の対象が細分化されるため、RBAC(Role-based access control)を用いて「最小権限の原則」に基づいた安全な運用が可能です。

Kubernetes Gateway APIを構成する3種類のリソース

Gateway APIは、Kubernetesクラスタ外部からクラスタ内のServiceへのL4/L7でのルーティングを、3種類リソース GatewayClassGatewayRouteを用いて定義するAPIです。

GatewayClass
Gatewayを構成するためのテンプレートを示すリソース
Gatewayを構成するために使用するGateway Controllerをパラメータと共に指定する
このパラメータでGateway構成時に構築されるロードバランサーの設定項目(L4、L7、外部、内部等)を指定する

Gateway
リクエストをクラスタ内へルーティングするルールを定義するリソース
指定したGatewayClassの定義を元にロードバランサーやプロキシ等を実際に構築する
クラスタ内のどこにルーティングするかはRouteによって定義する

Route
GatewayからServiceに対するルーティングのルールを定義するリソース
ロードバランサーでのパスベースのルーティングの指定等に対応
対応するプロトコル毎にHTTPRouteTCPRouteTLSRouteUDPRouteが存在する
以下、公式ドキュメントにある図に描かれているように、GatewayClassGatewayRoute(図ではHTTPRoute)の3つのリソースを組み合わせることで、Serviceへのルーティングを定義します。


引用 https://gateway-api.sigs.k8s.io/

2021年11月時点で、GKEやIstioを含む複数のプロジェクトがGateway APIで定義された挙動を実現するGateway Controllerを実装しています。

Gateway APIを用いる利点

Gateway APIにはIngress APIと比べて以下の利点があります。

  1. ルーティングの設定に必要最小限な権限をRBACで付与できる
  2. プロバイダー依存性の低いManifestでルーティングの設定を定義できる
  3. 拡張性が高い

順に説明します。

続きはこちら

株式会社ZOZO's job postings

Weekly ranking

Show other rankings
If this story triggered your interest, go ahead and visit them to learn more