とにかく手軽に Kubernetes + Istio 環境を用意したい人のための GKE & ASM 入門

Kubernetes と Istio の組み合わせは、その拡張性やエコシステムの充実度などから、マイクロサービスの実行環境を検討する際の有力な選択肢のひとつに挙げられます。
一方、Kubernetes や Istio を構築・運用することが技術的なハードルとなり、アプリケーションの検証にまでなかなか到達できない、というケースもあるのではないでしょうか。
そこで今回は、「とにかく手軽に Kubernetes + Istio の環境が欲しい」といった方向けに、いま現在の Google Cloud で採りうる最もマネージドな構成をご紹介します。

概要

今回ご紹介する構成は、Kubernetes のマネージドサービスである GKE (Google Kubernetes Engine)と、Istio のマネージドサービスである Anthos Service Mesh を、GKE Autopilot + Managed Anthos Service Mesh + Managed Data Plane という利用形態で組み合わせたものです。

それぞれの簡単な説明は以下のとおりです。

  • GKE Autopilot は、GKE Standard と同様のマネージドなコントロールプレーンに加えて、ノードの管理も Google に任せることができる GKE クラスタの利用形態です。
  • Managed Anthos Service Mesh(以下、Managed ASM)は、従来から提供されてきた In-place Control Plane よりもさらにマネージドな範囲を拡大し、Istiod の運用も Google に任せることができる Anthos Service Mesh の利用形態です。
  • Managed Data Plane は、Managed ASM の Data Plane(サイドカーとしてワークロードの Pod に挿入される Istio-proxy)の運用を Google に任せることができるオプション機能として提供されています。

これまで、Managed ASM は GKE Standard のみがサポートされてきたこと、Managed Data Plane が GA していなかったことから、上記の組み合わせはサポートされていませんでしたが、2022 年 9 月に発表された下記リリースによってこれが実現可能となりました。
加えて、9 月 8 日のリリースでは、マルチクラスタのグルーピングやポリシー管理に用いられる Fleet API を使って Managed ASM を構成することが可能になったとアナウンスされていました。
今後は Fleet API の使用が推奨となるようですので、今回は Fleet API を使って ASM をセットアップする流れをご紹介します。

  • Managed ASM による GKE Autopilot のサポートが GA に到達

cloud.google.com

  • Managed ASM のオプションである Managed Data Plane が GA に到達
  • Fleet API による ASM のセットアップが GA に到達

cloud.google.com

GKE Autopilot クラスタの作成

まずは GKE Autopilot のクラスタを作成します。
今回は、特にオプションを付与しないプレーンなクラスタを作成します。
クラスタ作成のリクエスト後、しばらくするとステータスが Running となり、クラスタが正常に起動したことがわかります。

$ gcloud container clusters create-auto autopilot-cluster
Note: The Pod address range limits the maximum size of the cluster. Please refer to https://cloud.google.com/kubernetes-engine/docs/how-to/flexible-pod-cidr to learn how to optimize IP address allocation.
Creating cluster autopilot-cluster in us-central1... Cluster is being health-checked (master is healthy)...done.     
Created [https://container.googleapis.com/v1/projects/***************/zones/us-central1/clusters/autopilot-cluster].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1/autopilot-cluster?project=***************
kubeconfig entry generated for autopilot-cluster.
NAME: autopilot-cluster
LOCATION: us-central1
MASTER_VERSION: 1.23.12-gke.100
MASTER_IP: ***************
MACHINE_TYPE: e2-medium
NODE_VERSION: 1.23.12-gke.100
NUM_NODES: 3
STATUS: RUNNING

クラスタはコンソールで作成することもできます。
コンソールの場合は GKE Autopilot クラスタを作成する際にチェックボックスを入れることで Managed ASM を有効化できるようになっていますが、今回は Fleet API を使った手順をみていきましょう。

Fleet API による ASM のセットアップ

Fleet API を用いて Managed ASM を構成する手順は、下記の公式ドキュメントに記載されています。
ASM 1.11 以降、ここ 1 年ほどは、asm_install の後継である asmcli が推奨のインストール手段とされてきましたが、Managed ASM を利用する場合であれば今後は Fleet API による構成が推奨となるようです。

cloud.google.com

なお、Managed ASM を利用する場合であっても、以下の条件では引き続き asmcli を使って構成する必要があるため注意が必要です。

  • Managed ASM を VPC Service Controls で保護する必要がある場合
  • Istio-proxy が利用する mTLS の証明書管理に(Mesh CA ではなく)プライベート CA を利用する場合
  • GKE のリリースチャネルと ASM のリリースチャネルが異なる場合

それでは、前節で作成した GKE Autopilot クラスタに Managed ASM をセットアップしていきましょう。
なお、説明の簡単のため、クラスタの作成とフリートの管理は同じプロジェクトで行うものとします。
また、これまでに一度も mesh.googleapis.com を有効化したことがない、フリート機能を使ったことがない、という場合は以下の手順を参考に事前作業が必要です。

cloud.google.com

作業前の状態では、クラスタは存在するものの、フリートには登録されていません。

$ gcloud container fleet memberships list
(出力なし)

クラスタをフリートに登録していきます。
Fleet API は、GKE URI という一意の識別子によって登録する GKE を特定するため、gcloud container clusters list--uri オプションを付与して URI を取得しておきましょう。
メンバーシップ名は任意のようですが、クラスタ名と揃えておくと管理しやすいかと思います。

$ gcloud container clusters list --uri
https://container.googleapis.com/v1/projects/***************/locations/us-central1/clusters/autopilot-cluster

$ gcloud container fleet memberships register autopilot-cluster \
  --gke-uri=https://container.googleapis.com/v1/projects/***************/locations/us-central1/clusters/autopilot-cluster \
  --enable-workload-identity
  
Waiting for membership to be created...done.     
Finished registering to the Fleet.

$ gcloud container fleet memberships list
NAME: autopilot-cluster
EXTERNAL_ID: ***************
LOCATION: global

次に、mesh_id ラベルをクラスタに付与します。
これは ASM ダッシュボードにメトリクスを表示するなどの目的で利用されます。

$ gcloud container clusters update autopilot-cluster --update-labels mesh_id=proj-***************
Note: GKE Dataplane V2 has been certified to run up to 500 nodes per cluster, including node autoscaling and surge upgrades. You may request a cluster size of up to 1000 nodes by filing a support ticket with GCP. For more information, please see https://cloud.google.com/kubernetes-engine/docs/concepts/dataplane-v2
Updating autopilot-cluster...done.
Updated [https://container.googleapis.com/v1/projects/***************/zones/us-central1/clusters/autopilot-cluster].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1/autopilot-cluster?project=***************

余談ですが、GKE Autopilot では eBPF を使った CNI 実装のひとつである Cilium を使った Dataplane V2 が採用されているため、 Dataplane V2 を使用する場合のノード数上限に関する通知が出ていますね。

これで Managed ASM を設定する準備が整いました。
現状は、クラスタがフリートに登録されたものの、Managed ASM やそのオプションである Managed Data Plane は有効化されていない状態です。

$ gcloud container fleet mesh describe
createTime: '2021-10-11T05:47:33.463228309Z'
membershipSpecs:
membershipStates:
  projects/***************/locations/global/memberships/autopilot-cluster:
    servicemesh:
      controlPlaneManagement:
        state: DISABLED
      dataPlaneManagement:
        details:
        - code: DISABLED
          details: Data Plane Management is not enabled.
        state: DISABLED
    state:
      code: OK
      description: Please see https://cloud.google.com/service-mesh/docs/install for
        instructions to onboard to Anthos Service Mesh.
      updateTime: '2022-11-26T05:09:24.043654068Z'
name: projects/***************/locations/global/features/servicemesh
resourceState:
  state: ACTIVE
spec: {}
state:
  state: {}
updateTime: '2022-11-26T05:11:32.289019496Z'

以下のコマンドで、Fleet API から Managed ASM を有効化することができます。

$ gcloud container fleet mesh update \
     --management automatic \
     --memberships autopilot-cluster

しばらく待ってから gcloud container fleet mesh describe コマンドで確認してみると、controlPlaneManagement, dataPlaneManagement がともにアクティブになっていることがわかります。

$ gcloud container fleet mesh describe
createTime: '2021-10-11T05:47:33.463228309Z'
membershipSpecs:
  projects/***************/locations/global/memberships/autopilot-cluster:
    mesh:
      management: MANAGEMENT_AUTOMATIC
membershipStates:
  projects/***************/locations/global/memberships/autopilot-cluster:
    servicemesh:
      controlPlaneManagement:
        details:
        - code: REVISION_READY
          details: 'Ready: asm-managed'
        state: ACTIVE
      dataPlaneManagement:
        details:
        - code: OK
          details: Service is running.
        state: ACTIVE
    state:
      code: OK
      description: 'Revision(s) ready for use: asm-managed.'
      updateTime: '2022-11-26T12:34:08.393270443Z'
name: projects/***************/locations/global/features/servicemesh
resourceState:
  state: ACTIVE
spec: {}
state:
  state: {}
updateTime: '2022-11-26T12:35:12.350418568Z'

asmcli で有効化する場合と比較して、Fleet API を用いて Managed ASM を有効化する場合は Managed Data Plane もセットで有効化される点が特徴ですね。

ワークロードの実行とサイドカー(Data Plane)の挿入

環境が用意できましたので、ワークロードを実行する Namespace にラベルを付与して適当なワークロードをデプロイし、Istio-proxy が自動挿入されることを確認してみましょう。
今回は httpd を利用します。

$ kubectl describe namespace default
Name:         default
Labels:       kubernetes.io/metadata.name=default
Annotations:  <none>
Status:       Active

Resource Quotas
  Name:                              gke-resource-quotas
  Resource                           Used  Hard
  --------                           ---   ---
  count/ingresses.extensions         0     100
  count/ingresses.networking.k8s.io  0     100
  count/jobs.batch                   0     5k
  pods                               0     1500
  services                           1     500

No LimitRange resource.

$ kubectl label namespace default istio-injection=enabled istio.io/rev- --overwrite
label "istio.io/rev" not found.
namespace/default labeled

$ kubectl describe namespace default 
Name:         default
Labels:       istio-injection=enabled
              kubernetes.io/metadata.name=default
Annotations:  <none>
Status:       Active

Resource Quotas
  Name:                              gke-resource-quotas
  Resource                           Used  Hard
  --------                           ---   ---
  count/ingresses.extensions         0     100
  count/ingresses.networking.k8s.io  0     100
  count/jobs.batch                   0     5k
  pods                               1     1500
  services                           1     500

No LimitRange resource.

$ kubectl run httpd --image httpd
Warning: Autopilot set default resource requests on Pod default/httpd for container httpd, as resource requests were not specified, and adjusted resource requests to meet requirements. See http://g.co/gke/autopilot-defaults and http://g.co/gke/autopilot-resources.
pod/httpd created

$ kubectl get pod -o jsonpath='{.items[0].spec.containers[*].name}' |  tr ' ' '\n'
httpd
istio-proxy

補足:Control Plane と Data Plane をセットで有効化するための Google 側の工夫

上記の構成を試す過程で、Fleet API によって Managed ASM と Managed Control Plane をセットで有効化するために Google 側が実装面でどのような工夫をしているのか、ユーザが観測できる情報から少し覗いてみたいと思います。

Fleet API で ASM を有効化している最中に、gcloud container fleet mesh describe コマンドでステートを確認してみると、controlPlaneManagement のステートは以下のような順序で変化していました(過程のすべてのステートを拾えているかはわかりません)。

DISABLEDPROVISIONING (REVISION_PROVISIONING)ACTIVE (REVISION_READY)

更に、dataPlaneManagement のステートは以下のように変化していました。

DISABLEDFAILED_PRECONDITION (MANAGED_CONTROL_PLANE_REQUIRED) → (Control Plane が ACTIVE に到達) → PROVISIONING (PROVISIONING)ACTIVE (OK)

Fleet API は Managed Data Plane もセットで有効化するため、Control Plane より先に Data Plane が展開されてしまうことがないよう、Control Plane の展開が済むまでは FAILED_PRECONDITION で展開が止まるようになっているようですね。
Kubernetes のリコンサイルの仕組みを使って、Control Plane が条件を満たせば(Managed ASM がACTIVE になれば)、自動的に目的の状態(ACTIVE)に収束するよう定義し、展開の順序を制御しているようです。

まとめ

GKE Autopilot + Managed Anthos Service Mesh + Managed Data Plane の構成で GKE, ASM を利用することで、手軽に Kubernetes + Istio の環境を構築できることをご紹介しました。
次回は、この環境における ASM のバージョンコントロールの仕組みについてカスタムリソースなどから調べた情報を交えて共有したいと思います。