新人SREが0から始めるGKE上でのArgoCDによるWordPressデプロイ

Sreake事業部

2024.3.22

はじめに

はじめまして。Sreake事業部インターン生の高島です。2023年10月から長期インターン生としてKubernetes関連技術の習得とSRE技術の調査・検証を行っています。私は、情報系の大学院生で、普段は数値解析に関する研究をしています。このため、長期インターンを始める前はITインフラに関して大学の授業での知識程度でした。

今回は、Sreake事業部に参加する際に最初に行う研修内容についてまとめました。研修は、全5つの課題からなり、1つの記事では長いため、まず前半の3つの課題について説明します。課題の前半では、「GKE上にArgoCDを構築してWordpressを管理」ということがゴールになります。これらの課題を通じて、アプリケーションにおけるSREを意識したモダンなITインフラ構築方法を学習することができます。

研修内容の説明

研修の課題内容は以下です。前半は以下の太字の項目になります。

課題 1Terraformを利用してIaCで管理されたGKEクラスタを作成
課題 2Helmを利用してクラスタ上にWordpressをデプロイ
課題 3クラスタにArgoCDを構築し、WordpressをArgoCDの管理下に置く
課題 4GitLab Runnerを利用してCICDをできるようにする
課題 5クラスタ内の状況を監視できるようにする

これらのタスクに加えて、一貫して必要になってくることとして、「セキュリティや機密情報の取扱いに注意して構築すること」が重要になってきます。例として、以下のようなものがあげられます。

  • 外部公開するリソースやアプリケーションは関係者のみが利用できるように特定のIPアドレス下のアクセスに制限する
  • パスワードや認証情報の設定が必要な場合はハードコードせずに暗号化して保存

以下が今回作成した課題前半の大まかなアーキテクチャ図になります。UserがWordpressアプリケーションの使用者、ArgoCD AdminがArgoCDを利用してアプリケーションをデプロイする開発者、Cloud Developerがクラウド基盤を構築している開発者になります。

※ 以下の図がベストプラクティスというわけではありません。課題の条件に合わせてどうすればよいかを考えていく必要があります。

研修前半で構築したアーキテクチャ図

以下各課題1~3についての説明を、以下の項目でそれぞれしていきます。

  • 学習事項 : 各課題をやることで学習できる内容
  • 実装方法 : 各課題の実装方法や手順
  • つまずいた点 : 各課題をやるうえでつまずく可能性があると考えれる点

前提で必要な知識

本研修を進める上で、前提として以下の知識があると進めやすいです。

  • Linuxの操作方法
  • dockerやVMといった仮想環境
  • ネットワークの基礎
  • Kubernetesの概要
  • クラウドの基礎
  • セキュリティの基礎

これらの知識は、課題を進めていく上でも深めることはできますが、詳しいほどスムーズに進められます。ITインフラ系の開発経験の浅かった私が、研修を進めていくうえで一番大変な点が「各概念を理解すること」であったため、前提知識は重要です。

私は上記の前提知識の項目のうち、Linuxの操作方法、仮想環境の基礎、ネットワークの基礎は多少の理解がありましたが、Kubernetesやクラウド、セキュリティに関してはどういうものなのか雰囲気を知っている程度でした。

GKEクラスタの作成

Google CloudやVPC、GKEなどのアプリケーションを立ち上げるための基盤となる部分を構築します。この際、クラウドリソースをTerraformを利用してIaCで管理します。アーキテクチャ図の以下の赤枠の部分になります。

学習事項

基本的なクラウド上のアプリケーション基盤構築です。

  • Google Cloudの各種サービスの利用方法と基盤の構築方法の理解
  • Terraformを利用したクラウドリソースのIaC管理
  • クラウドリソースの管理時に必要なセキュリティ設定

実装方法

大まかな流れとして、「プロバイダー設定 → VPC → GKE」とアーキテクチャ図の外側の枠から構築していくような流れになります。

1.kubectl、gcloud CLI、Terraform環境の構築

kubectl、Google Cloudのサービス、Terraformを自分の利用する環境下で利用できるようにします。以下のURLを参考にインストールを行います。
kubectl : https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/
gcloud CLI : https://cloud.google.com/sdk/docs/install?hl=ja
Terraform : https://developer.hashicorp.com/terraform/downloads?product_intent=terraform

2.Terraformのクラウドプロバイダー設定

Terraformを利用する際、構築環境の一貫性を持たせるため、Terraformのバージョンとクラウドプロバイダーについてコード中に以下のように設定する必要があります。

terraform {
  required_version = ">=1.3"
  required_providers {
    google = {
      source = "hashicorp/google"
      version = ">= 3.0"
    }
  }
}

provider "google" {
  project = var.gcp_project_id
  region  = var.gcp_region
  zone  = var.gcp_zone
}

この設定はTerraformでクラウドリソースを作成する際の基本的な設定になるので、1つ作成し、以下のディレクトリ構造のようにシンボリックリンクで他のフォルダからでも利用できるようにしておきます。

terraform
├── gke
│   ├── backend.tf
│   ├── gke.tf
│   ├── provider.tf -> ../shared/provider.tf
│   ├── terraform.tfvars
│   ├── variables.tf
│   └── vpc.tf
├── storage
│   ├── storage.tf
│   └── provider.tf -> ../shared/provider.tf
└── shared
    └── provider.tf

3.VPCによるネットワーク基盤構築

Google Cloud内でのネットワーク基盤を作成するために、以下のモジュールを利用して、VPCを構築します。
VPC module : https://registry.terraform.io/modules/terraform-google-modules/network/google/latest

VPCを構築する際に、kubernetesのpodやserviceのIPv4範囲を分け、リソースの管理やセキュリティ管理がしやすいようにしておきます。また、個人情報や変更がある可能性のある値、他での使用できる値などは変数として、variabels.tfterraform.tfvarsなどの別で管理しておくことで柔軟な構築ができるようになります。

module "vpc" {
  source  = "terraform-google-modules/network/google"
  version = "~> 7.5"

  project_id   = var.gcp_project_id
  network_name = var.network
  routing_mode = "GLOBAL"

  subnets = [
    {
      subnet_name   = "subnet-01"
      subnet_ip     = var.subnet_cidr
      subnet_region = var.gcp_region
      description   = "for kubernetes"
    }
  ]

  secondary_ranges = {
    subnet-01 = [
      {
        range_name    = var.ip_range_pods
        ip_cidr_range = var.pods_range_cidr
      },
      {
        range_name    = var.ip_range_services
        ip_cidr_range = var.services_range_cidr
      },
    ]
  }
}

4.GKEクラスタの作成

構築したVPC上にGKEクラスタを以下のモジュールを利用して構築します。
GKE module : https://registry.terraform.io/modules/terraform-google-modules/kubernetes-engine/google/latest

master_authorized_networksを利用して、GKEの各リソースへのアクセスを一部のネットワークのみに制限することで、セキュリティを高めます。

data "google_client_config" "default" {}

provider "kubernetes" {
  host                   = "https://${module.gke.endpoint}"
  token                  = data.google_client_config.default.access_token
  cluster_ca_certificate = base64decode(module.gke.ca_certificate)
}

module "gke" {
  source              = "terraform-google-modules/kubernetes-engine/google"
  project_id          = var.gcp_project_id
  name                = var.cluster_name
  region              = var.gcp_region
  network             = module.vpc.network_name
  subnetwork          = module.vpc.subnets_names[0]
  ip_range_pods       = var.ip_range_pods
  ip_range_services   = var.ip_range_services

  node_pools = [
    {
      name           = var.node_pool
      machine_type   = "e2-medium"
      node_locations = var.gcp_zone
      autoscaling    = true
      min_count      = 1
      max_count      = 4
      disk_size_gb   = 50
    },
  ]

  master_authorized_networks = [
    {
      cidr_block   = var.vpn_cidr
      display_name = var.vpn_name
    },
  ]
}

5.tfstateの格納先のStorageを作成

共同開発とtfstateの関係 Terraformを利用してクラウドリソースを構築する際、tfstateファイルというTerraformが管理しているリソースの現在の状態を記憶するためのファイルが生成されます。上記に示すように、共同で開発している場合tfstateを他の人もアクセスできる場所で一元管理する必要があり、開発者同士での同時変更などが起こらないようにlockできるようにします。

また、tfstateファイルは、各リソースのパスワード、APIキー、IPアドレスなどの機密情報も保持するため、管理にはセキュリティ的に厳重な注意が必要なファイルです。このため、tfstateファイルは、安全なリモートストレージ下で管理する必要があります。

今回は、tfstateを格納するためのGoogle CloudのCloud Storageを用意し、以下のようにBackendでtfstateファイルの格納先を決定します。

terraform {
  backend "gcs" {
    bucket = var.bucket_name
    prefix = "terraform/state"
  }
}

6.Terraformでapply

最後に以下のコマンドから今まで作成してきたGKEの設定をGoogle Cloudにapplyさせます。

$ cd terraform/gke
$ terraform plan            # 設定内容に不備がないか静的に確認
$ yes yes | terraform apply # 設定を適応

つまずいた点

  • 各サービスやアプリ間の繋がり
    ITインフラ経験の浅い私からすると、TerraformやGoogle Cloudの各種サービス(Cloud Storage, GKE, VPC etc)、kubectlなど課題1から必要なものが多く困惑してしまいました。
    解決方法として、ChatGPTに概要を教えてもらうといいと思いました。詳細な設定でなければ、かなり細かく教えてくれます。また、公式ページでの売り文句を調べて何に使うのか調べたりするのも案外有効でした。
  • Google Cloudの利用
    初めてGoogle Cloudを利用する場合、Terraformでリソースを管理しようとしても何を書くことで実装ができるのかがわかりませんでした。
    解決方法として、最初からTerraformでやろうとせずにコンソール上などのGUIで実装してみることで何の情報があればクラウドリソースが立ち上げられるのかが理解できました。

HelmでのWordpressのデプロイ

作成したGKE基盤上にHelmを利用してWordpressをデプロイします。この際、パスワードなどの機密情報の管理や通信が安全に行えるようにセキュリティを配慮して構築します。アーキテクチャ図の以下の赤枠の部分になります。

学習事項

初めの課題に比べてやや複雑で、実装方法の選択肢も多いです。

  • Kubernetesでのアプリケーション管理をする際に利用されるHelmの利用方法
  • GKEから他のGoogle Cloudリソースへのアクセス方法
  • GKE内のアプリケーションの外部公開方法およびFirewallの設定
  • パスワードなどの機密情報の安全な管理方法

実装方法

大まかな流れとして、Wordpressが動くデフォルトの機能のPodを作ってから、データベース、セキュリティ設定、暗号化と機能を追加変更していくような形で実装していきます。

1.Helmのインストール

Helmを自分の利用する環境下で利用できるようにします。Helmはkubectlを利用するため、前課題でのkubectlのインストールが前提です。以下のURLを参考にインストールを行います。
Helm Install : https://helm.sh/ja/docs/intro/install/

2.Wordpressのデプロイ

Helmを用いて、Wordpressをデプロイします。まず、WordpressのHelm Charがあるリポジトリを取得し、Wordpressをデプロイします。標準だと、作成されたPodはdefaultという名前空間にあります。

$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm upgrade --install my-release bitnami/wordpress
$ helm list
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
my-release      default         1               2024-01-15 14:24:15.925275748 +0900 JST deployed        wordpress-18.1.20       6.4.1

この段階で自動的にLoadBalancerを利用して、Public IPが割り当てられてブラウザ上でWordpressの画面を確認できるようになるはずです。割り当てられたIPは以下のコマンドのEXTERNAL-IPで確認できます。

$ kubectl get svc

3.Wordpress用のデータベースの構築

Cloud SQLでデータベースを作成し、そのデータベースを利用したWordpressを実装をします。以下の図は、この工程の実装の流れを示した図です。

a. Cloud SQLのTerraform moduleを利用して、Cloud SQLのインスタンスおよびMySQLのデータベースを作成します。

b. 作成したデータベースをWordpressをデプロイするVPC内からでもアクセスができるようにしていきます。VPC内に新たに外部のリソースを割り当てるためのプライベートIPアドレスを確保します。

resource "google_compute_global_address" "private_ip_address" {
  project       = var.gcp_project_id
  name          = "private-ip"
  purpose       = "VPC_PEERING"
  address_type  = "INTERNAL"
  prefix_length = 16
  network       = module.vpc.network_id
}

resource "google_service_networking_connection" "default" {
  network                 = module.vpc.network_id
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [google_compute_global_address.private_ip_address.name]
}

c. 先ほどのCloud SQL module内で以下のようなネットワークの設定を加え、VPC内からアクセスができるようにします。

module "sql-db_mysql" {
	...
  module_depends_on = [google_service_networking_connection.default]
  ip_configuration = {
    ipv4_enabled    = false
    private_network = module.vpc.network_id
  }
	...
}

d. このままだと、データベースのIPアドレスがDHCPにより動的に割り当てられてしまい、管理しにくくなってしまうため、Cloud DNSを利用してデータベースに内部ドメイン名をつけて一意なホスト名でのアクセスができるようにします。

e. 以上でドメイン名経由でデータベースにアクセスできるので、以下のようにWordpressに対する設定ファイルvalues.yamlを作成し、データベースに関する設定を行います。

mariadb:
  enabled: false

externalDatabase:
  host: db.example.com # データベースに対して設定したドメイン名
  port: 3306           # MySQLのデフォルトポート

作成次第、ファイルを指定し、デプロイをし直して完了です。

$ helm upgrade --install my-release bitnami/wordpress -f values.yaml

4.Cloud Armorによるセキュリティポリシーの作成

デプロイしたWordpressへのアクセスに対するFirewallについて、Cloud Armorを利用して設定します。どのようなルール、ポリシーでセキュリティ設定をするかを、Terraformのgoogle_compute_security_policyリソースを用いることで以下のように設定することができます。

resource "google_compute_security_policy" "policy" {
  name = "wordpress-sec-policy"
  project = var.gcp_project_id
  type = "CLOUD_ARMOR"
  
  rule {
	  action = "allow"
	...
}

ただし、この設定だけではセキュリティポリシーというセキュリティルールに関する設計書ができただけなので、適応されていません。設定方法は次の項目で説明します。

5.Ingressでの外部公開とCloud Armorポリシーの設定

既にLoadBalancerを用いて、外部公開がされている状態になっていますが、このままだとセキュリティポリシーの適応や権限に関する設定などができないため、Ingressを利用した外部公開を行います。

a. Ingressに接続するため、Wordpressへの設定ファイルvalues.yamlで以下のように記載し、Serviceを設定し直します。この際、以下のannotationを加えて、ingressおよびバックエンド設定が行えるようにします。

service:
  type: NodePort
  annotations:
    cloud.google.com/backend-config: '{"ports": {"80":"backend-config"}}'
    cloud.google.com/neg: '{"ingress": true}'

b. 以下のようにIngressリソースを作成します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: wordpress-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "gce"
spec:
  defaultBackend:
    service:
      name: my-release-wordpress # 先ほど作成したServiceの名前
      port:
        number: 80

c. 最後に以下のようにBackendConfigリソースでセキュリティポリシーを設定し、作成したリソースをapplyすることでアクセス制限をすることが可能です。

apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: backend-config
spec:
  securityPolicy:
    name: wordpress-sec-policy

6.WordpressへのHTTPSによるアクセス

HTTPS通信によるセキュアな通信ができるようにします。

a. HTTPS通信を行うためのSSL証明書を発行するために、以下のように外部通信用のPublic IP取得します。

resource "google_compute_global_address" "wordpress_ssl_public_ip" {
  project      = var.gcp_project_id
  name         = "wordpress-ssl-public-ip"
  address_type = "EXTERNAL"
}

b. 取得したPublic IPに対して、Cloud DNSを利用してドメイン名を設定します。

c. ドメイン名に対して、SSL証明書を発行する。

apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: wordpress-managed-cert
spec:
  domains:
  - wordpress.external-example.com # 設定したドメイン名

d. Ingressに以下のannotationsを追加し、リソースをapplyし直すことでHTTPS通信ができるようになります。SSL証明書の発行には、やや時間がかかります

annotations:
  kubernetes.io/ingress.global-static-ip-name: wordpress-ssl-public-ip
  networking.gke.io/managed-certificates: wordpress-managed-cert

以下のように、指定したドメイン名でHTTPS通信でアクセスして接続できれば成功です。

7.helm-secretsを利用した機密情報の暗号化と復号化

WordPressの設定を行う際、Wordpressのadmin権限やデータベースへのアクセス時に利用するユーザ名およびパスワードなどの機密情報を設定する必要があります。これらの情報が書かれたvalues.yamlを記載したファイルを共有リポジトリで管理する際、機密情報を平文で保持することはセキュリティ上の問題があります。

そこで機密情報の管理について、暗号化や安全な場所に保管してデプロイする際にのみデータを取得などする必要があります。今回は、helm-secretsを利用して機密情報を暗号化して保持する方法で実装します。

a. helm-secretsをインストールします。helm-secretsはsopsという暗号化ツールを利用するため、sopsをインストールします。sopsはgoを利用するため、go langのインストールからやっていきます。

sudo apt install golang -y
mkdir -p $HOME/go/bin
echo "export PATH=\"$HOME/go/bin:$PATH\"" >> ~/.profile # goのパスを通す
source .profile
mkdir -p $HOME/go/src/github.com/getsops/sops/
cd $HOME/go/src/github.com/getsops/sops/
git clone https://github.com/getsops/sops.git .
make install

sopsコマンドが利用できれば、インストール完了です。その後、helm-secretsをインストールします。

$ helm plugin install https://github.com/jkroepke/helm-secrets

b. Cloud KMSを利用して、以下のように暗号化用の鍵を作成します。この鍵は、GKEなどとはライフサイクルが異なるため、GKEなどとは異なる場所でリソースをapplyするようにします。

resource "google_kms_key_ring" "sops_key_ring" {
  name = "sops"
  location = "global"
}

resource "google_kms_crypto_key" "sops_key" {
  name = "sops-key"
  key_ring = google_kms_key_ring.sops_key_ring.id
  rotation_period = "100000s"
}

c. helm-secretsで暗号化する際に利用する鍵を設定します。ファイル名を.sops.yamlとし、以下のように書き込み、暗号化するファイルと同じディレクトリに配置します。

---
creation_rules:
- gcp_kms: projects/project-name/locations/global/keyRings/sops/cryptoKeys/sops-key

d. WordPress設定をするためのvalues.yamlのうち、機密情報を別のファイルに分けます。今回は機密情報用のファイルをsecrets.yamlとします。平文のsecrets.yaml内の情報を一旦、secrets.yaml.plainとし、以下のようにhelm-secretsにより暗号化します。

$ helm secrets encrypt secrets.yaml.plain > secrets.yaml # 暗号化
$ rm secrets.yaml.plain # 平文を削除

以下のようにコマンドを実行することで、暗号化されたファイルを一時的に復号化してsecrets.yamlを利用しつつ、Wordpressをデプロイすることができます。

$ helm secrets upgrade --install my-release bitnami/wordpress -f secrets.yaml -f values.yaml

つまずいた点

  • 複数ある実装方法がある中の採用
    同じようなことを他の方法でも実装可能ということが多々あります。例として、Wordpressをデプロイする際のCloud SQLのリソースを利用について、本実装ではCloud SQLのInstanceを同VPC内で使えるようにし、Private DNSを定義してアクセスできるようにしました。しかし、方法はこれだけではなく、GKEがGoogle Cloudリソースを利用するためにWorkload Identityを利用する方法などがあげられます。
    解決方法として、それぞれの利点を知ることが重要だと考えます。管理のしやすさ、実装の容易さ、柔軟性など色々な方面から考慮することができます。データベースの例ですと、VPC内で利用できるようにすることで他のアプリケーションでデータベースが必要になった場合に容易に利用することができるようになります。また、Workload Identityの場合だと、アプリケーションとGoogle Cloud側でそれぞれService Accountを作成して繋げるだけでよいので、実装がしやすいです。
  • Ingressとは何か
    Ingressという言葉を聞いたのが初めてだったため、何のためのものなのかの理解に時間がかかりました。特に、外部との通信で利用するという観点からは、LoadBalancerなどとも役割が似ています。
    Ingressは、L7(HTTPSなどのアプリケーション層)で動作し、複雑なトラフィック管理ができるという特徴があります。このため、ホスト名やURLパスでの制御が可能です。複雑な設定ができる反面、IngressリソースだけでなくIngressコントローラー必要となり、Serviceを用いた外部接続方法に比べて複雑です。

ArgoCDの構築

GKE基盤上にArgoCDを構築し、WordpressアプリケーションをArgoCDの管理下におきます。この際、今まで設定した機能は維持したまま構築します。このため、Wordpressの実装方法(特に、機密情報の管理方法)によって以下のアーキテクチャ図は異なります。完成次第、最初に記載したアーキテクチャ図の全体を構築したことになります。

学習事項

ArgoCDの仕組みを理解することがメインになります。

  • ArgoCDの構築
  • ArgoCDによる自動認証および復号化

実装方法

大まかな流れとして、ArgoCDのインストールが完了後にデフォルト機能のWordpressのApplicationをデプロイします。次に、前課題で設定した機能をArgoCD管理下でも同様に動くようにしていきます。最後にログインや編集権限などのセキュリティ設定をします。

1.ArgoCDのインストールとargo-serverへのアクセス

ArgoCDのHelm Chartを取得し、デフォルトの設定でデプロイします。

$ helm repo add argo https://argoproj.github.io/argo-helm
$ helm upgrade --install -n argocd argocd argo/argo-cd

ArgoCDも公式ページを参考にvalues.yamlを記載して、デプロイすることで設定することが可能です。デプロイすると以下のように一通りArgoCDに必要なリソースが作られます。

$ kubectl get pod -n argocd
NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          36m
argocd-applicationset-controller-58dff45cbd-wvfmt   1/1     Running   0          3h51m
argocd-dex-server-6b9c44b8df-6crzq                  1/1     Running   0          3h51m
argocd-notifications-controller-966f6ccbc-vnjbr     1/1     Running   0          3h51m
argocd-redis-859f7d4df-mrr4v                        1/1     Running   0          3h51m
argocd-repo-server-85b5667f7c-74ld4                 2/2     Running   0          36m
argocd-server-6f5484bc6c-n8598                      1/1     Running   0          36m

ArgoCDを操作するダッシュボード部分にあたるArgoCDサーバにアクセスをして、GUIでの確認や操作ができるようにします。今後の拡張性を考慮し、ingressを利用したアクセスができるようにします。接続できると以下のように表示されます。

2.Applicationのデプロイ

HelmでApplication管理するためのChartは上記のArgoCDをインストールするのに利用したリポジトリ内に入っています。ここのvalues.yamlを参考に、applicationを設定することができます。sources部分に、以下のように今回デプロイしたいWordpressのhelmリポジトリを入れることで対象のコードを参照します。ここでは、Wordpressはデフォルト設定でデプロイされます。

applications:
- name: wordpress
  ...
  sources:
  - repoURL: https://charts.bitnami.com/bitnami
    chart: wordpress
    targetRevision: 18.1.20
    helm:
      releaseName: my-release-wordpress
	- repoURL: 
	...

上記のapp.yamlを参考に以下のコマンドからArgoCDの管理下でデプロイします。

$ helm upgrade --install my-app argo/argocd-apps -f app.yaml 

デプロイが完了すると以下のようにダッシュボードに表示されます。

3.Sync Policyの設定

ArgoCDで管理しているアプリケーションについて、どのように更新するか、どのタイミングで更新するかを制御するためのSync Policyを定義します。Applicationの設定時に以下のようにSync Policyを書きます。

syncPolicy:
  automated:
    prune: false
    selfHeal: true
  syncOptions:
  - CreateNamespace=true
  • prune : trueの場合、applicationのソースリポジトリからあるリソースに関する定義がなくなっていることを検出すると、リソースも同様に削除します。falseにしておくと、本番環境ではリポジトリのリソース削除による自動プルーニングがなくなり、故意的に操作する以外で動作環境の変化を防ぐことができます。
  • selfHeal : クラスタの状態がリポジトリで定義されている状態から乖離した場合に自動的に修復する機能です。trueにしておくと、本番環境で意図せぬ変化やエラーなどに迅速に修復できます。

4.ArgoCDから認証が必要なリポジトリへのアクセス

WordPressのデプロイに使用するvalues.yamlなどのパラメータが記載されるファイルは、GitHubやGitLabなどの認証が必要なリポジトリ内に保管されます。こういった情報へのアクセスを実装します。

a. GitLabやGitHubにてアクセスに利用するTokenを作成します。この際、スコープとして read_repository の権限をつけると内部の情報を見ることができるようになります。

b. 作成したTokenをSecretリソースで管理します。ArgoCDの設定時に利用するvalues.yamlの設定で、以下のようにTokenの情報を登録します。

configs:
    credentialTemplates:
        https-creds:
            url: https://repository.com # リポジトリのURL
            username: user              # tokenを作成したユーザ
            password: token-number12345678901122 # token

上記の情報はvalues.yamlとは別に機密情報管理用のファイルとして分けて管理をした方がセキュアです。 これにより、GitLabに保存したWordpressのvalues.yamlsecrets.yamlへのアクセスが可能になるため、Applicationをデプロイした際に記載したsourcesと同様に利用できます。

5.ArgoCDでの機密情報の自動復号化

前の項目でリポジトリ内から取り出したsecrets.yamlのように情報を暗号化して管理している場合があります。この場合、ArgoCD内で情報を復号化する必要があります。Wordpressをデプロイした際、helm-secretsを利用して情報を暗号化し、鍵はCloud KMSにて保管したので、これに対する自動復号化を実装します。

a. helm-secretsの公式ページを参考に、repo server内にinitContainerを利用して、helm secretsが使えるようにします。

b. ConfigMapによりConfigManagementPluginでのプラグインの処理内容を以下のように定義します。

cmp:
  create: true
  plugins:
    helm-secrets:
      generate:
        command:
          - /bin/bash
          - -c
        args:
          - |
            set -o pipefail
            helm secrets template -f $ARGOCD_ENV_SECRETS -f $ARGOCD_ENV_VALUES -n $ARGOCD_APP_NAMESPACE $ARGOCD_APP_NAME .

c. サイドカーに必要なファイルをマウントし、プラグインを実行するサイドカーを作成します。

cmp:
  create: true
  plugins:
    helm-secrets:
      generate:
        command:
          - /bin/bash
          - -c
        args:
          - |
            set -o pipefail
            helm secrets template -f $ARGOCD_ENV_SECRETS -f $ARGOCD_ENV_VALUES -n $ARGOCD_APP_NAMESPACE $ARGOCD_APP_NAME .

d. Google Cloudとrepo serverにそれぞれServiceAccountを作成します。これらをWorkload Identityで繋げ、repo serverがCloud KMSサービスを利用できるようにします。以下、Terraform moduleを利用して実装します。

module "my-app-workload-identity" {
  source     = "terraform-google-modules/kubernetes-engine/google//modules/workload-identity"
  use_existing_k8s_sa = true
  cluster_name = var.cluster_name
  location = var.gcp_region
  name       = "argocd-repo-server"
  namespace  = "argocd"
  project_id = var.gcp_project_id
  roles      = ["roles/cloudkms.cryptoKeyDecrypter"]
}

設定内容を、repo-serverにも適応させることでKMSから鍵を取得できます。

serviceAccount:
  create: true
  name: "argocd-repo-server"
  annotations:
    iam.gke.io/gcp-service-account: argocd-repo-server@sreake-intern.iam.gserviceaccount.com
  automountServiceAccountToken: true

e. Applicationでサイドカーをコールし、helm secretsでリポジトリ内の暗号化されているファイルを復号化します。

applications:
- name: wordpress
	...
	plugin:
		name: helm-secrets

設定が完了すると、Wordpressアプリケーションについて今まで設定した機能は維持したままArgoCDでの管理下での管理ができるようになります。

6.ログイン方法の変更とApplicationへの編集権限設定

初期設定では、パスワード認証が可能です。今回は、利便性の向上やセキュリティ強化のためにGitLabによるSSO認証に対応させます。dex-serverというSSOを行う際に利用するサーバをConfigMapを利用して設定していきます。また、ArgoCDやApplicationの編集権限を設定することが可能です。これにより、ログインしたユーザの所属するグループや組織によって、権限を付与することができます。

a. GitLabをOAuthプロバイダーとして利用できるように、アカウント内のAppicationsを設定します。この際、read_user,openidの権限が必要になります。

b. ConfigMapに以下のように設定し、dex serverで認証できるようにします。ただし、Sercretをそのまま書き込むのはセキュリティ的に問題があるため、別で機密情報管理用のファイルとして分けて保存します。

url: argocd.sample.com # ArgoCD URL
dex.config: |
  connectors:
    - type: gitlab
      id: gitlab
      name: Gitlab SSO
      config:
        clientID: abcdefghij123456789 # GitLabで作成したID
        clientSecret: $dex.gitlab.clientSecret

c. clientSecretの情報を以下のようにSecretリソース管理および別のファイルで保存し、helm-secretsで暗号化するなど、機密情報として管理します。

configs:
  secret:
    extra:
      dex.gitlab.clientSercret: 123456789abcdefghijk # GitLabで作成したSercret

d. RBACにより、各グループのアクセス権限を設定します。読み取り権限のreadonlyロールと管理者権限のadminロールはデフォルトであり、細かい設定がしたい場合は自身でロールを作成することも可能です。

rbac:
  create: true
  policy.default: role:readonly
  policy.csv: |
    p, role:org-admin, applications, *, */*, allow
    g, my-group, role:org-admin

上記の設定後、パスワード認証を無効化した結果以下のようになります。

つまずいた点

  • ArgoCDの内部構造の理解
    ArgoCDは様々な構成要素から作られるツールです。このため、何らかの機能を実装しようとする際に各要素の持つ役割を理解していないといけませんでした。
    やりたいことを切り分けて考えていくしかありませんでした。構成要素が分かれている分、各Podが何の機能を担っているのかが比較的にわかりやすいです。このため、目当てのPodを探して、そのPodに対してどのように適応させればよいかを考えていく形になります。また、Podに対して、環境固有の設定を行えるConfigMapやSecretリソースについて知っておくとわかりやすいと思いました。
    以下の記事は、同所属の長谷川さんによるArgoCDに関する記事です。ArgoCDについて非常にわかりやすく書かれており、おすすめです。
    https://hiroki-hasegawa.hatenablog.jp/entry/2023/05/02/145115#04-application-controllerredis-server

おわりに

GKE上にArgoCDを構築し、Wordpressの管理を行う方法を説明してきました。また、この研修を通じて、Google Cloudによる基礎的なクラウド基盤からアプリケーションのデプロイ状況の管理ツールであるArgoCDの構築まで、ITインフラに関する幅広い構築方法を学ぶことができました。

ここまでで、Continuous Delivery & Deploymentができるようになったため、次の課題でContinuos Integrationを出来るようにし、CI/CDが一通りできるようにしていきたいと考えています。また、最終的にクラスタの状態監視を追加し、一通りの開発ができるインフラ基盤を構築していこうと思います。

ブログ一覧へ戻る

お気軽にお問い合わせください

SREの設計・技術支援から、
SRE運用内で使用する
ツールの導入など、
SRE全般についてご支援しています。

資料請求・お問い合わせ