🎃

GKE Gateway 環境を構築してみる

2023/10/07に公開

概要

今回は GKE Gateway を GKE で使えるところまでの設定を試してみます。

GKE Gateway API は Google が提供している Kubernetes の Gateway 実装です。

https://cloud.google.com/kubernetes-engine/docs/concepts/gateway-api?hl=ja

GKE クラスタ構築

GKE Gateway コントローラの要件を満たす様に以下のスペックで GKE クラスタを作成します。

resource "google_container_cluster" "default" {
  name                     = "tetsuya28"
  location                 = "asia-northeast1"
  remove_default_node_pool = true
  initial_node_count       = 1
  network                  = google_compute_network.default.name
  subnetwork               = google_compute_subnetwork.default.name
  # Gateway API を利用するために VPC native モードで作成する
  networking_mode          = "VPC_NATIVE"
  ip_allocation_policy {
    cluster_ipv4_cidr_block  = local.pod_cidr
    services_ipv4_cidr_block = local.service_cidr
  }
  # ここで Gateway API を有効化する
  gateway_api_config {
    channel = "CHANNEL_STANDARD"
  }
  workload_identity_config {
    workload_pool = "${local.project_id}.svc.id.goog"
  }
  cost_management_config {
    enabled = true
  }
}

クラスタ作成後 gatewayclass リソースが取得出来ることを確認します。

▶  kubectl get gatewayclass
NAME                             CONTROLLER                  ACCEPTED   AGE
gke-l7-global-external-managed   networking.gke.io/gateway   True       5m2s
gke-l7-gxlb                      networking.gke.io/gateway   True       5m2s
gke-l7-rilb                      networking.gke.io/gateway   True       5m3s

Gateway のデプロイ

Gateway API を有効化したクラスタの作成が完了したら実際に Gateway リソースの作成をしていきます。

今回は 2023 年 4 月 8 日 時点で GA になっている gke-l7-gxlb class を利用します。

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: http
spec:
  gatewayClassName: gke-l7-gxlb
  listeners:
  - name: http
    protocol: HTTP
    port: 80

上記マニフェストを適用後暫くすると IP アドレスが設定され Gateway のデプロイが完了します。

完了時のリソースとしては以下のような設定が取得出来ます。

▶  kubectl get gateway -o yaml http
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"gateway.networking.k8s.io/v1beta1","kind":"Gateway","metadata":{"annotations":{},"name":"http","namespace":"default"},"spec":{"gatewayClassName":"gke-l7-gxlb","listeners":[{"name":"http","port":80,"protocol":"HTTP"}]}}
    networking.gke.io/addresses: /projects/PROJECT_NUMBER/global/addresses/gkegw1-fgki-default-http-1mmbg95k7amq
    networking.gke.io/backend-services: /projects/PROJECT_NUMBER/global/backendServices/gkegw1-fgki-kube-system-gw-serve404-80-7cq0brelgzex
    networking.gke.io/firewalls: /projects/PROJECT_NUMBER/global/firewalls/gkegw1-fgki-l7-tetsuya28-global
    networking.gke.io/forwarding-rules: /projects/PROJECT_NUMBER/global/forwardingRules/gkegw1-fgki-default-http-s04zmpnbqq7f
    networking.gke.io/health-checks: /projects/PROJECT_NUMBER/global/healthChecks/gkegw1-fgki-kube-system-gw-serve404-80-7cq0brelgzex
    networking.gke.io/last-reconcile-time: "2023-04-08T05:58:10Z"
    networking.gke.io/ssl-certificates: ""
    networking.gke.io/target-http-proxies: /projects/PROJECT_NUMBER/global/targetHttpProxies/gkegw1-fgki-default-http-umg7zrlwi0u7
    networking.gke.io/target-https-proxies: ""
    networking.gke.io/url-maps: /projects/PROJECT_NUMBER/global/urlMaps/gkegw1-fgki-default-http-umg7zrlwi0u7
  creationTimestamp: "2023-04-08T05:55:41Z"
  finalizers:
  - gateway.finalizer.networking.gke.io
  generation: 1
  name: http
  namespace: default
  resourceVersion: "10896"
  uid: 0672def5-c5dd-4b7a-b947-d47dd55e9f49
spec:
  gatewayClassName: gke-l7-gxlb
  listeners:
  - allowedRoutes:
      namespaces:
        from: Same
    name: http
    port: 80
    protocol: HTTP
status:
  addresses:
  - type: IPAddress
    value: 35.190.2.25
  conditions:
  - lastTransitionTime: "2023-04-08T05:57:31Z"
    message: The OSS Gateway API has deprecated this condition, do not depend on it.
    observedGeneration: 1
    reason: Scheduled
    status: "True"
    type: Scheduled
  - lastTransitionTime: "2023-04-08T05:57:31Z"
    message: ""
    observedGeneration: 1
    reason: Accepted
    status: "True"
    type: Accepted
  - lastTransitionTime: "2023-04-08T05:57:31Z"
    message: ""
    observedGeneration: 1
    reason: Ready
    status: "True"
    type: Ready
  listeners:
  - attachedRoutes: 0
    conditions:
    - lastTransitionTime: "2023-04-08T05:57:31Z"
      message: ""
      observedGeneration: 1
      reason: Ready
      status: "True"
      type: Ready
    name: http
    supportedKinds:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute

GCP のリソースとしては HTTP ロードバランサ ( Classic ) が作成されています。

このタイミングではバックエンドをまだデプロイしていないので 404 が返ってきます。

curl 35.190.2.25 -i
HTTP/1.1 404 Not Found
Date: Sat, 08 Apr 2023 06:00:16 GMT
Content-Length: 74
Content-Type: text/plain; charset=utf-8
Via: 1.1 google

response 404 (backend NotFound), service rules for the path non-existent

HTTPRoute のデプロイ

次に実際に Gateway のバックエンドをデプロイしていきます。

サンプルアプリケーションには Google のサンプルを利用します。

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/store.yaml

次に、上記のサンプルアプリケーションへのルーティングを HTTP Route を利用して設定します。

kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: store-external
spec:
  parentRefs:
  - kind: Gateway
    name: http
  hostnames:
  - "store.example.com"
  rules:
  - backendRefs:
    - name: store-v1
      port: 8080
  - matches:
    - headers:
      - name: env
        value: canary
    backendRefs:
    - name: store-v2
      port: 8080
  - matches:
    - path:
        value: /de
    backendRefs:
    - name: store-german
      port: 8080

この時点でロードバランサにバックエンドに対する設定が追加されます。

ドメインを store.example.com で設定しているため curl で強制的に store.example.com のドメイン名を Gateway API の IP アドレスで名前解決をすることでアクセスの確認を行います。

無事、 Gateway API 経由でバックエンドへの疎通を行うことが出来ました。

curl store.example.com/de --resolve "store.example.com:80:35.190.2.25" -i
HTTP/1.1 200 OK
Server: Werkzeug/2.2.2 Python/3.10.9
Date: Sat, 08 Apr 2023 06:19:31 GMT
Content-Type: application/json
Content-Length: 365
Access-Control-Allow-Origin: *
Via: 1.1 google

{
  "cluster_name": "tetsuya28",
  "gce_instance_id": "836092675233726340",
  "gce_service_account": "tetsuya28.svc.id.goog",
  "host_header": "store.example.com",
  "metadata": "Gutentag!",
  "pod_name": "store-german-678c8d4d54-dvkt9",
  "pod_name_emoji": "😯",
  "project_id": "tetsuya28",
  "timestamp": "2023-04-08T06:19:31",
  "zone": "asia-northeast1-b"
}

おまけ

Gateway ですが、権限分離の考え方など個人的に期待しているのですが現状以下の機能を使うことが出来ず、 GA にはなっているもののプロダクションに導入出来るレベル感かと言われると微妙なところではありますが、今後の機能改善にも期待していきたいと思います。

  • Cloud CDN
  • IAP
  • Cloud Armor
  • HTTPS リダイレクト

Discussion