Kubernetes Gateway API入門

Gateway APIの開発が進んできて、2021年5月12日 現在アルファであるGateway APIを見ていきたいと思います。

本記事は、上記ページを参考にして作成しております。また、Contourを使って試しています。

背景

KubernetesにはIngressと呼ばれるリソースがあり、多くの方がIngressを利用してアプリケーションを外部に公開してきました。約5年経過し、コアのAPIに加えて、ベンダー固有の機能をアノテーションで使用していたり、Ingress自体では実現できないために、独自のCRDが作成されてきました。これは、独自のアノテーションやCRDを使うということになり、別のIngress Controllerにした場合には、リソースのマニフェストを変更する必要が出てきます。 こういったポータビリティを維持するために、Gateway APIの開発が進められてきました。

Gateway APIのコンセプト

下記4点がGateway APIのコンセプトになります。

  • Role-oriented
    ユーザのペルソナに合わせたAPIリソースの提供
  • Portable
    別のGateway API実装を利用した際に、マニフェストの変更が不要である
  • Expressive
    Ingressのアノテーションなどで提供されてきたヘッダーマッチングなどをAPIリソース内で表現できる
  • Extensible
    CRDといくつかのレイヤーで関連付けをできるようにします。これにより、細かいカスタマイゼーションをAPIの構造の正しい場所でできるようにする。

nginx Ingress Controllerのアノテーションの量や各LBベンダーが固有のCRDを実装しているのを見ると、Gateway APIというユニバーサルなリソースが開発されたのは理にかないます。特に、ラボ環境でアノテーションを使ってできたことが、プロダクションの環境だと実装されてない、もしくは、別のアノテーションを使う必要があるなど、様々な問題点がありました。これらを解決するためのリソースだと考えられます。

Gateway APIのモデル

コンセプトにある通り、GatewayAPIのリソースは誰がどのリソースを定義するのか意識して開発されています。ネットワークという共有のインフラを使用する性質上、誰が何をするのか、どこまで管理するのかという境界を引くのは大変重要です。それらをどうやって実装しているのか見ていきます。

まず、今回でてくる3つのロールについて説明します。

  • Infrastructure provider
    インフラの管理者。実際の物理的もしくは論理的なロードバランサーを管理する人たち
  • Cluster Operator
    Kubernetesクラスタを管理する人たち
  • Application developer もしくはSite Developer
    そのKubernetesクラスタ上でアプリケーションを提供する人たち
The resources of the Gateway API
引用: kubernetes.io

この3つのロールに合わせたAPIリソースが下記の通り提供されています。

インフラの管理者向け GatewayClass

クラスタスコープなリソースで、クラスタ内で利用可能なGatewayを定義します。

Contourの例では、spec/controllerにこのGatewayを管理するコントローラーをドメイン/パス方式で提供しています。また、spec/parametersRefでは他のKubernetesリソースを使って、Gatewayに必要な設定を指定できます。今回だと、contour-gateway-sampleで作られたContourのインスタンスを使うという内容が記載されています。

kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
  name: sample-gatewayclass
spec:
  controller: projectcontour.io/contour-operator
  parametersRef:
    group: operator.projectcontour.io
    kind: Contour
    scope: Namespace
    name: contour-gateway-sample
    namespace: contour-operator

クラスタ管理者向け Gateway

ネームスペーススコープなリソースで、インフラにロードバランサーのインスタンスを作ることができます。ここでいうロードバランサーは論理的なロードバランサーを示しており、ハードウェアのロードバランサーの場合には、設定の追加を示す場合もありますし、VMベースのロードバランサーであればVMのデプロイ、パブリッククラウドであれば新規のロードバランサーサービスの展開を意味します。

spec/gatewayClassNameでどのGatewayClassを使用するか指定します。
また、spec/listenersという項目で、どのHTTPRouteリソースをこのGatewayに設定できるか制御します。つまり、クラスタ管理者側で明示的にどのアプリケーションチームがこのGatewayを使えるか制御できるのです。今までは、Ingressの作成をアプリケーションチームに許可すると、インフラやクラスタ管理者からIngressの設定を許可したり拒否するスキームがありませんでした。この点がRole-orientedである所以でもあります。

Contourの例は以下の通りで、app: kuardをラベルにもつHTTPRouteのみがこのGatewayを使うことができます。今回の例だとprojectcontourネームスペースに作成されたHTTPRouteのみが対象です。

kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
  name: contour
  namespace: projectcontour
spec:
  gatewayClassName: sample-gatewayclass
  listeners:
    - protocol: HTTP
      port: 80
      routes:
        kind: HTTPRoute
        selector:
          matchLabels:
            app: kuard
    - protocol: HTTPS
      port: 443
      routes:
        kind: HTTPRoute
        selector:
          matchLabels:
            app: kuard

アプリケーションチーム向け HTTPRoute

ネームスペーススコープなリソースで、HTTPトラフィックを制御するものになります。今まで、Ingressを使ってHostname、 TLS、 ルールを指定してきたと思いますが、それらはここで定義されます。GatewayとHTTPRouteは双方向バインディングが必要なので、Gateway側で指定したラベルをつけないとHTTPRouteがGatewayに設定されません。

今回の例だと、hostnameがlocal.projectcontour.ioとなるHTTPリクエストをkuardと呼ばれるサービスに転送します。

kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
  name: kuard
  namespace: projectcontour
  labels:
    app: kuard
spec:
  hostnames:
    - "local.projectcontour.io"
  rules:
    - matches:
        - path:
            type: Prefix
            value: /
      forwardTo:
        - serviceName: kuard
          port: 80

また、下記の通り複数サービスへの重み付けロードバランシングもできるようになってます。それらの機能については次回以降で触れます。

Gateway API Roles
引用: gateway-api.sigs.k8s.io

動作確認

Contourのガイドを参考に実施します。サポートされてるKuberneteのバージョン等には注意してください。

今回のKubernetesのバージョンは以下のとおりです。

# kubectl version
Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.0", GitCommit:"cb303e613a121a29364f75cc67d3d580833a7479", GitTreeState:"clean", BuildDate:"2021-04-08T21:15:16Z", GoVersion:"go1.16.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"20", GitVersion:"v1.20.1", GitCommit:"c4d752765b3bbac2237bf87cf0b1c2e307844666", GitTreeState:"clean", BuildDate:"2020-12-18T12:00:47Z", GoVersion:"go1.15.5", Compiler:"gc", Platform:"linux/amd64"}

Contourのオペレータをセットアップをします。

kubectl apply -f https://projectcontour.io/quickstart/operator.yaml

オペレータが動いていることを確認します。

# kubectl -n contour-operator get pod
NAME                                READY   STATUS    RESTARTS   AGE
contour-operator-7c6cfb8845-jpt56   2/2     Running   0          109m

Contour、GatwayClass、Gatewayを作成します。

kubectl apply -f https://projectcontour.io/quickstart/gateway.yaml

作ったリソースを確認します。

# kubectl -n contour-operator get contour.operator.projectcontour.io
NAME                     READY   REASON
contour-gateway-sample   True    GatewayClassAdmitted

# kubectl get gatewayclass.networking.x-k8s.io/sample-gatewayclass
NAME                  CONTROLLER
sample-gatewayclass   projectcontour.io/contour-operator

# kubectl -n projectcontour get gateway.networking.x-k8s.io/contour
NAME      CLASS
contour   sample-gatewayclass

HTTPRouteとそのバックエンドで動くサンプルアプリをデプロイします。

kubectl apply -f https://projectcontour.io/quickstart/kuard.yaml

作成したリソースを確認します。

# kubectl get po,svc,httproute -n projectcontour -l app=kuard
NAME                         READY   STATUS    RESTARTS   AGE
pod/kuard-798585497b-cxgpz   1/1     Running   0          5s
pod/kuard-798585497b-sbjtp   1/1     Running   0          5s
pod/kuard-798585497b-zmbbr   1/1     Running   0          5s

NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/kuard   ClusterIP   172.30.66.190   <none>        80/TCP    5s

NAME                                  HOSTNAMES
httproute.networking.x-k8s.io/kuard   ["local.projectcontour.io"]

私の環境下では、ContourのenvoyがExternalIPを持っているので、そのIPを使用してアプリケーションにアクセスします。

# kubectl -n projectcontour get svc envoy
NAME    TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
envoy   LoadBalancer   172.30.214.210   192.168.11.62   80:32679/TCP,443:32001/TCP   4m7s

curlで動作確認します。

curl -H 'Host: local.projectcontour.io'  http://192.168.11.62/

下記のようにレスポンスが返ってくれば成功です。

$ curl -H 'Host: local.projectcontour.io'  http://192.168.11.62/
<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">

  <title>KUAR Demo</title>

  <link rel="stylesheet" href="/static/css/bootstrap.min.css">
  <link rel="stylesheet" href="/static/css/styles.css">

  <script>
var pageContext = {"hostname":"kuard-798585497b-zmbbr","addrs":["172.16.2.19"],"version":"v0.8.1-1","versionColor":"hsl(18,100%,50%)","requestDump":"GET / HTTP/1.1\r\nHost: local.projectcontour.io\r\nAccept: */*\r\nUser-Agent: curl/7.64.1\r\nX-Envoy-Expected-Rq-Timeout-Ms: 15000\r\nX-Envoy-Internal: true\r\nX-Forwarded-For: 192.168.10.62\r\nX-Forwarded-Proto: http\r\nX-Request-Id: 17a98ac8-3ed7-4791-be82-7971f6ae9e5e\r\nX-Request-Start: t=1620785532.982","requestProto":"HTTP/1.1","requestAddr":"172.16.2.17:47774"}
  </script>
</head>


<svg style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="icon-power" viewBox="0 0 32 32">
<title>power</title>
<path class="path1" d="M12 0l-12 16h12l-8 16 28-20h-16l12-12z"></path>
</symbol>
<symbol id="icon-notification" viewBox="0 0 32 32">
<title>notification</title>
<path class="path1" d="M16 3c-3.472 0-6.737 1.352-9.192 3.808s-3.808 5.72-3.808 9.192c0 3.472 1.352 6.737 3.808 9.192s5.72 3.808 9.192 3.808c3.472 0 6.737-1.352 9.192-3.808s3.808-5.72 3.808-9.192c0-3.472-1.352-6.737-3.808-9.192s-5.72-3.808-9.192-3.808zM16 0v0c8.837 0 16 7.163 16 16s-7.163 16-16 16c-8.837 0-16-7.163-16-16s7.163-16 16-16zM14 22h4v4h-4zM14 6h4v12h-4z"></path>
</symbol>
</defs>
</svg>

<body>
  <div id="root"></div>
  <script src="/built/bundle.js" type="text/javascript"></script>
</body>
</html>

さいごに

現時点でのGatewayAPIの実装について見てきました。Ingressと比べると複数のリソースの定義が必要なものの、ペルソナに合わせたリソースの定義がされていて使いやすい印象です。実運用だとGatwayClassとGatewayリソースを頻繁に更新することもないと思いますので、今までのIngressと同じように運用はでき、インフラやクラスタ管理者からある程度制御ができるきれいな構造になっています。

今後GatewayAPIにてサポートされているいくつかの機能も触って行ければと思ってます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA