とことんDevOps | 日本仮想化技術が提供するDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けするとことんDevOpsでは、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果など、DevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、アジャイル開発、コンテナ開発など

開催予定の勉強会

各種SNSのフォローもよろしくお願いいたします。

GCPとArgo CDでかんたんDevOps

前回はAWS上にArgo CDを構築しました。今回はGCPにArgo CDをデプロイしていきたいと思います。

必要なもの

  • Googleアカウント
  • GCPプロジェクト
  • gcloud CLI
  • Terraform
  • Helm
  • kubectl
  • argocd(CLI)

請求先アカウントが設定済みのGCPプロジェクトを用意してください。GKEを動かすためには請求先アカウントを設定しておく必要があります。

gcloud CLI, Terraform, Helm, kubectl, argocdは公式ドキュメントにインストール方法が記載されています。以下のドキュメントを参考にインストールをお願いします。

Terraformのバージョンはv1.3.3を使用しました。

gcloudコマンドでGCPプロジェクトを操作できるように、gcloud auth logingcloud config set project PROJECT_IDで対象のプロジェクトを設定してください。手順は以下です。

GCP

新しいGCPプロジェクトを作って試したところ、TerraformやExternalDNSでGCPのリソースを操作するには以下の権限が必要になりました。

gcloud services enable container.googleapis.com
gcloud services enable dns.googleapis.com

GKE

以下のテキストをmain.tfというファイル名で保存してください。これはGKEクラスターを作るためのコードで、testという名前のGKEクラスターが起動してきます。

variable "project" {}
variable "region" {}

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "4.41.0"
    }
  }
}

provider "google" {
  project = var.project
  region  = var.region
}

resource "random_id" "suffix" {
  byte_length = 4
}

resource "google_service_account" "edns" {
  account_id = "edns-${random_id.suffix.hex}"
}

resource "google_project_iam_member" "edns" {
  project = var.project
  role    = "roles/dns.admin"
  member  = "serviceAccount:${google_service_account.edns.email}"
}

resource "google_service_account_iam_member" "edns" {
  service_account_id = google_service_account.edns.name
  role               = "roles/iam.workloadIdentityUser"
  # kube-system Namespaceに作成されたexternal-dnsサービスアカウントをGCPのサービスアカウントに紐づける
  member = "serviceAccount:${var.project}.svc.id.goog[kube-system/external-dns]"
}

resource "google_service_account" "gke" {
  account_id = "gkesa-${random_id.suffix.hex}"
}

locals {
  gke_roles = [
    "roles/logging.admin",
    "roles/monitoring.admin",
  ]
}

resource "google_project_iam_member" "gke" {
  project = var.project
  count   = length(local.gke_roles)
  role    = element(local.gke_roles, count.index)
  member  = "serviceAccount:${google_service_account.gke.email}"
}

resource "google_container_cluster" "primary" {
  name                     = "test"
  location                 = var.region
  remove_default_node_pool = true
  initial_node_count       = 1

  workload_identity_config {
    workload_pool = "${var.project}.svc.id.goog"
  }
}

resource "google_container_node_pool" "primary" {
  name       = "test-node-pool"
  location   = var.region
  cluster    = google_container_cluster.primary.name
  node_count = 1

  management {
    auto_repair  = true
    auto_upgrade = true
  }

  node_config {
    preemptible  = true
    machine_type = "e2-medium"

    service_account = google_service_account.gke.email
    oauth_scopes = [
      "https://www.googleapis.com/auth/cloud-platform"
    ]

    workload_metadata_config {
      mode = "GKE_METADATA"
    }
  }
}

ExternalDNSがCloud DNSを操作するためにWorkload Identityという機能を使用しています。詳細は以下をご覧ください。

cloud.google.com

以下のテキストをterraform.tfvarsというファイルに保存してください。
REPLACE MEとなっているところに、今回操作するGCPのプロジェクトIDをいれてください。
regionは変更しても構いませんが、この記事ではasia-northeast1という前提で進めていきます。

project = "REPLACE ME"
region  = "asia-northeast1"

main.tfterraform.tfvarsを保存したディレクトリで以下のコマンドを実行してください。

terraform init

現状のインフラとコードの差分をチェックします。

terraform plan

GKEクラスターを作成します。

terraform apply

kubectlが使えるように、今回起動したGKEクラスターをkubeconfigに追加します。

gcloud container clusters get-credentials test --region asia-northeast1

以下のコマンドを実行し、Server Versionが取得できれば成功です。

kubectl version --short

Argo CD

Argo CDをHelmからインストールするので、HelmにArgo CDのリポジトリを追加します。

helm repo add argo https://argoproj.github.io/argo-helm

Argo CDをargocdというネームスペースにインストールします。

helm upgrade --install argocd argo/argo-cd --namespace argocd --create-namespace

ポートフォワードで接続できるようにします。後ほどALB経由で接続できるようにするので、これは一時的なものです。

kubectl port-forward service/argocd-server -n argocd 8080:443

Argo CDのadminパスワードを取得します。

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

argocdコマンドでログインします。UsernameにはadminPasswordには先ほど取得したadminパスワードを入力してください。

argocd login localhost:8080 --insecure

http://localhost:8080 にアクセスするとWEB UIからログインすることもできます。

ExternalDNS

ExternalDNSは、Kubernetesリソースを介して動的にCloud DNSにDNSレコードを追加、削除します。

Argo CDにアプリケーションとして追加します。

REPLACE MEはCloud DNSで管理している実在のドメインにしてください。

domain=REPLACE ME
txtownerid=test
gsa=$(gcloud iam service-accounts list --filter='email:(edns-*)' --format='value(email)')
argocd app create external-dns \
  --repo https://kubernetes-sigs.github.io/external-dns/ \
  --helm-chart external-dns \
  --revision 1.11.0 \
  --dest-namespace kube-system \
  --dest-server https://kubernetes.default.svc \
  --helm-set "domainFilters[0]=$domain" \
  --helm-set "txtOwnerId=$txtownerid" \
  --helm-set policy=sync \
  --helm-set serviceAccount.create=true \
  --helm-set serviceAccount.name=external-dns \
  --helm-set "serviceAccount.annotations.iam\.gke\.io/gcp-service-account=$gsa" \
  --helm-set provider=google

デプロイします。

argocd app sync external-dns

Argo CDをCloud Load Balancing経由でアクセスできるようにする

Argo CDで使うSSL証明書を発行します。REPLACE MEの部分は、Argo CDに設定するドメインに置き換えて、managed-certificate.yamlというファイルに保存してください。

apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: argocd-cert
spec:
  domains:
    - REPLACE ME

デプロイします。

kubectl apply -f managed-certificate.yaml -n argocd

Argo CDで使うLBの設定を行います。以下のテキストをfrontend-config.yamlというファイルに保存してください。

apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
  name: argocd-frontend-config
spec:
  redirectToHttps:
    enabled: true

デプロイします。

kubectl apply -f frontend-config.yaml -n argocd

Argo CDのIngressを有効にします。

domain={{SUBDOMAIN}}
helm upgrade -i argocd argo/argo-cd \
  -n argocd --create-namespace \
  --set 'server.service.type=NodePort' \
  --set 'server.service.annotations.cloud\.google\.com/neg={"ingress": true}' \
  --set 'server.ingress.enabled=true' \
  --set "server.ingress.hosts[0]=$domain" \
  --set "server.ingress.annotations.external-dns\.alpha\.kubernetes\.io/hostname=$domain" \
  --set "server.ingress.annotations.kubernetes\.io/ingress\.class=gce" \
  --set "server.ingress.annotations.networking\.gke\.io/managed-certificates=argocd-cert" \
  --set "server.ingress.annotations.networking\.gke\.io/v1beta1\.FrontendConfig=argocd-frontend-config" \
  --set 'server.extraArgs[0]=--insecure'

IngressからGCPのLBを起動するにはIngressのAnnotationsに設定を追加します。詳細は以下です。

https://cloud.google.com/kubernetes-engine/docs/how-to/load-balance-ingress?hl=ja

SSLのプロビジョニングに1時間程度かかりますので気長にお待ちください。

片付け

片付けをするには少し順序があります。これはArgo CDで管理しているExternalDNSがArgo CDのドメインを管理しており、かつ、Argo CDのログイン先がLBの方に向いているからです。Argo CDを先にアンインストールするとExternalDNSが残ってしまいますし、アプリの方を先にアンインストールするとargocdコマンドが使えなくなってしまいます。

以下の手順に沿って、片付けを進めてください。

IngressをOFFにしてLBとサブドメインを解放します。

helm upgrade --install argocd argo/argo-cd --namespace argocd --create-namespace --set 'server.service.type=NodePort' --set 'server.ingress.enabled=false'

LBとドメインが削除されたのを確認してください。どちらもなくなっていればargocdコマンドが使えなくなっているので、ポートフォワードに切り替えます。

kubectl port-forward service/argocd-server -n argocd 8080:443

argocdコマンドのログイン先も変更します。

argocd login --insecure localhost:8080

アプリを削除します。

argocd app delete external-dns

SSLやFrontendConfigを削除します。

kubectl delete -f managed-certificate.yaml -n argocd
kubectl delete -f frontend-config.yaml -n argocd

Argo CDをアンインストールします。

helm uninstall --namespace argocd argocd

GKEを削除します。

terraform destroy

以上で片付けは完了です。