在前幾天,我們把 VPC、EKS 與 IRSA 都設定完了,cluster 基礎環境準備好了之後!接下來新的挑戰就會是「怎麼穩定地在這個 cluster 裡部署應用」!
傳統上,我們可能會寫一堆 YAML,然後用 kubectl apply
或 CI/CD pipeline 把它丟進 cluster。這種模式有一個特徵,被稱作「Push-based」,也就是外部工具(例如 Jenkins、GitLab CI)主動「推送」配置到 cluster。
這個 Push-based 的問題是:
kubectl edit
,就會導致第一點不一致的狀況。GitOps 的核心想法剛好反過來,採取的是「Pull-based」的精神,讓Cluster 內部跑一個控制器(例如 ArgoCD),主動去 Git repo 拉設定檔,並且保證 cluster 狀態與 Git 狀態一致。
這樣有幾個好處:
既然 Helm 這麼方便,為什麼我們不直接用 ArgoCD 來部署 ArgoCD 自己呢?因為對我們來說,ArgoCD 本身屬於底層 infra。在我們的分類裡,infra 工具(像是 ArgoCD、External Secrets、CNI plugin)會交給 Terraform 建立;而業務相關或平台元件(像是 LB Controller、Prometheus、Karpenter)才交給 ArgoCD 管理。這樣分層有兩個好處:
Terraform 提供了 helm_release
resource,可以直接安裝 Helm chart。
最重要的是,它可以讀取外部的 values 檔案,讓我們能根據不同環境覆蓋設定。
以下是我們實作的範例:
# https://artifacthub.io/packages/helm/argo/argo-cd/7.8.19
resource "helm_release" "argo_cd" {
repository = "https://argoproj.github.io/argo-helm/"
chart = "argo-cd"
version = "7.8.19"
namespace = "argocd"
name = "argo-cd"
create_namespace = true
dependency_update = true
max_history = 3
values = [
templatefile("${path.module}/helm/argo-cd.yaml", {
roleArn = aws_iam_role.argo.arn
argo_url = var.argo_url
})
]
depends_on = [
module.eks
]
}
在 argo-cd.yaml
這個 value file 裡,我們可以再額外設定 RBAC、ArgoCD 認得的 git repo ssh extra hosts、SSO 登入設定、還有各個元件的 QoS 都可以寫在 value file 中。
在 Kubernetes 裡,Pod 的 QoS (Quality of Service) 會依照資源設定分成三類:Guaranteed 表示所有容器都設定了 requests 與 limits 且數值相等,享有最高資源保障;Burstable 則是有設定 requests 但不完全等於 limits,能確保基本資源並在有餘裕時額外使用;BestEffort 則完全沒設定 requests/limits,沒有任何保障,叢集壓力大時最容易被驅逐。
而這邊的 request/limit 主要是針對 CPU/Memory 這兩項資源進行設定,細節可以參考官方文件。
部署 ArgoCD 時,還有一個「先決條件」:External Secrets。因為 ArgoCD 需要連線到 Git repo 或管理 cluster,這些憑證通常存在 AWS Secret Manager。如果 ArgoCD 需要透過 ExternalSecret 從 Secret Manager 讀 repo key,但它自己還沒起來,就會變成 deadlock。因此,ExternalSecrets Controller 必須在 ArgoCD 前安裝,讓 cluster 能自動把 Secret Manager 的內容同步到 Kubernetes Secret。這也是為什麼 ExternalSecrets 和 ArgoCD 一樣,要歸類在「infra 工具」,透過 Terraform 先裝好。
Terraform 範例:
resource "helm_release" "external_secrets" {
repository = "https://charts.external-secrets.io"
chart = "external-secrets"
version = "0.9.5"
namespace = "kube-system"
name = "external-secrets"
dependency_update = true
max_history = 3
depends_on = [
module.eks
]
values = [
templatefile("${path.module}/helm/external-secrets.yaml", {})
]
}
接著我們會採用 ClusterSecretStore
來作為所有 Secret 的來源,並且處理 IRSA 的設置:
module "external_secrets_irsa_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
#checkov:skip=CKV_TF_1: versioning is easier to manage
version = "5.30.0"
# 這邊官方一樣有提供已經寫好的 policy 可以用,真是貼心 <3
attach_external_secrets_policy = true
role_name_prefix = "external-secrets"
external_secrets_ssm_parameter_arns = ["arn:aws:ssm:*:*:parameter/*"]
external_secrets_secrets_manager_arns = ["arn:aws:secretsmanager:*:*:secret:*"]
assume_role_condition_test = "StringLike"
oidc_providers = {
main = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = [
"*:*",
]
}
}
}
然後會需要設置 Service Account,並且綁定上面所建立的 IRSA role
resource "kubernetes_service_account_v1" "external_secrets" {
metadata {
name = "external-secrets-irsa"
namespace = "kube-system"
annotations = {
"eks.amazonaws.com/role-arn" = module.external_secrets_irsa_role.iam_role_arn
}
}
}
最後是建立 ClusterSecretStore 作為所有 Secret 的來源
resource "kubernetes_manifest" "cluster_secret_store" {
manifest = yamldecode(<<-YAML
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: default
spec:
provider:
aws:
service: SecretsManager
region: ap-northeast-1
auth:
jwt:
serviceAccountRef:
name: ${kubernetes_service_account_v1.external_secrets.metadata[0].name}
namespace: ${kubernetes_service_account_v1.external_secrets.metadata[0].namespace}
YAML
)
}
確認 ArgoCD Pod 是否起來:
kubectl get pods -n argocd
應該要看到 argocd-server
、argocd-repo-server
等 Pod Running。
Port-forward ArgoCD UI from Freelens:
找到 ArgoCD UI Admin user 的 password
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d
打開 https://localhost:8080
登入(密碼是上一步找回的結果),就能看到熟悉的 Dashboard。
理論上會看到全空的畫面(如圖),因為現在還沒有部署任何 Application(但因為現在 ArgoCD 裡面有一些其他專案的 Apps 所以我暫時先切到 Unknown 狀態了、剛裝好的介面和現在的截圖會長一樣)
到這裡,我們已經完成了 GitOps 核心工具 ArgoCD 的部署。
接下來的文章,我會介紹該如何正確地把 repo secret 和 cluster secret 建立到 cluster 內,讓 ArgoCD 可以正確的向 git repo 連線,並且一次管理多個 cluster 中的 menifests。