GKE Connection GatewayとArgoCD ApplicationSetによるアプリケーションデプロイ

GKE に欠かせない CD ツールの一つである ArgoCD。

クラスターが一台の時はいいのですが、これが複数台になった時にどのように管理しようか悩みました。

耐障害性観点から複数台に分けてインストールするのもありですが、一台にプロジェクト間を跨いだクラスター管理をして管理コストを下げたらいいなとも思いました。

調べる前は VPC のピアリングなど修正する必要があるなーと思いましたが、GCP で提供している Connection Gateway を参考にネットワーク依存せずに一括にクラスター管理ができそうだったのでこちらを試してた時の備忘録です。

Terraform で GKE リソースの作成

下記内容で GKE リソースを作成します。※Autopilot です。

locals {
  name_prefix = "test"
  project_id  = "your-project"
}

data "google_client_config" "default" {}

data "google_project" "project" {
  project_id = local.project_id
}


resource "google_container_cluster" "test-1" {
  provider                 = google-beta

  project = local.project_id
  name                     = "test-1"
  location                 = "asia-northeast1"


  # Enable Autopilot for this cluster
  enable_autopilot = true

  ip_allocation_policy {}

  release_channel {
    channel = "REGULAR"
  }
}


resource "google_container_cluster" "test-2" {
  provider                 = google-beta

  project = local.project_id
  name                     = "test-2"
  location                 = "asia-northeast2"


  # Enable Autopilot for this cluster
  enable_autopilot = true

  ip_allocation_policy {}

  release_channel {
    channel = "REGULAR"
  }
}

# Register to Fleet
resource "google_gke_hub_membership" "fleet-1" {

  membership_id = "test11-fleet"
  project       = local.project_id

  authority {
    issuer = "https://container.googleapis.com/v1/${resource.google_container_cluster.test-1.id}"
  }

  endpoint {
    gke_cluster {
      resource_link = "//container.googleapis.com/${resource.google_container_cluster.test-1.id}"
    }
  }
}

resource "google_gke_hub_membership" "fleet-2" {

  membership_id = "test12-fleet"
  project       = local.project_id

  authority {
    issuer = "https://container.googleapis.com/v1/${resource.google_container_cluster.test-2.id}"
  }

  endpoint {
    gke_cluster {
      resource_link = "//container.googleapis.com/${resource.google_container_cluster.test-2.id}"
    }
  }
}

クラスター、fleet の存在を確認する。

gcloud container clusters list
gcloud container hub memberships list

ArgoCD のインストール

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

ConnectionGateway の設定

Connection Gateway 用の Service Account,Workload Identity のリソース追加

module "sa_cluster_argocd_admin" {
  source = "./modules/service_account"

  project_id   = local.project_id
  account_id   = "argocd-fleet"
  display_name = "argocd-fleet"
  description  = "Argocd cluster"
  roles        = ["container.admin", "gkehub.gatewayEditor"]
}

module "workload_identity_argocd_server" {
  source = "./modules/workload_identity_iam"

  project_id             = local.project_id
  gcp_service_account_id = module.sa_cluster_argocd_admin.name

  k8s_service_accounts = [
    "argocd/argocd-server",
    "argocd/argocd-application-controller"
  ]
}

modules/resource の内容

resource "google_service_account" "service_account" {
  project = var.project_id

  account_id   = var.account_id
  display_name = var.display_name
  description = var.description
  disabled = var.disabled
}

resource "google_project_iam_member" "service_account_iam" {
  project = var.project_id

  for_each = toset(var.roles)

  role    = "roles/${each.key}"
  member  = "serviceAccount:${google_service_account.service_account.email}"
}

locals {
  annotations = formatlist(
    "serviceAccount:${var.project_id}.svc.id.goog[%s]",
    var.k8s_service_accounts,
  )
}

data "google_service_account" "serviceaccount" {
  account_id = var.gcp_service_account_id
}

resource "google_service_account_iam_binding" "wi_iam_binding" {
  service_account_id = data.google_service_account.serviceaccount.name
  role               = "roles/iam.workloadIdentityUser"
  members            = local.annotations
}

Google Service Account の追加が確認できたら、Kubernetes Service Account リソースを追加します。

---
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    iam.gke.io/gcp-service-account: argocd-fleet@$PROJECT_ID.iam.gserviceaccount.com
  name: argocd-application-controller
---
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    iam.gke.io/gcp-service-account: argocd-fleet@$PROJECT_ID.iam.gserviceaccount.com
  name: argocd-server

ArgoCD で管理したいクラスター secret を記載します。

apiVersion: v1
kind: Secret
metadata:
  name: test2-gke
  labels:
    argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
  name: test2-gke
  server: https://connectgateway.googleapis.com/v1beta1/projects/$PROJECT_ID/locations/global/gkeMemberships/$FLEET_NAME
  config: |
    {
      "execProviderConfig": {
        "command": "argocd-k8s-auth",
        "args": ["gcp"],
        "apiVersion": "client.authentication.k8s.io/v1beta1"
      },
      "tlsClientConfig": {
        "insecure": false,
        "caData": ""
      }
    }

内容に問題がなければkubectl applyをします。

アプリケーションリソースと ApplicationSet の作成

アプリケーションリソースは Nginx コンテナ利用しています。

ディレクトリ構成はクラスタ別に分けて Kustomize で管理していることを前提にして、ApplicationSet を作成します。

※アプリケーションリソース省略

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: dev-backend
spec:
  generators:
    - list:
        elements:
          - cluster: test1-cluster
            url: https://kubernetes.default.svc
          - cluster: test2-cluster
            url: https://connectgateway.googleapis.com/v1beta1/projects/$PROJECT_ID/locations/global/gkeMemberships/$FLEET_NAME
  template:
    metadata:
      name: "-nginx"
    spec:
      project: default
      source:
        repoURL: https://github.com/$GITHUB_USERNAME/REPO_NAME.git
        targetRevision: HEAD
        path: "nginx//overlays/dev"
      destination:
        server: ""
        namespace: default

問題なければkubectl applyをします。

apply を行うと ArgoCD のダッシュボード UI にアプリケーションが二つ登録されていることが確認できます。

念のため、各クラスターからアプリケーションが作成されてるか確認しましょう。

kubectl config use-context test-1

➜ kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           6m29s
kubectl config use-context test-2

➜ kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           4m46s

Connection Gateway を利用してネットワークの設定いじらず、簡単に ArgoCD でプロジェク間クラスターの管理ができるようになりました。

この他にも手動 fleet 登録を活用することによって EKS,オンプレ K8s の管理もできるようになったので、積極的に活用していきたいですね。