cloud

為 GitOps 啟動新的 RKE 叢集

在 Argo CD 能安全接手 Kubernetes 叢集前,我會完成的檢查清單。

English繁中
為 GitOps 啟動新的 RKE 叢集

Argo CD 接手新的 RKE 叢集前,要先完成 Git 存取、Vault 驗證與節點前置設定。少了這些條件,第一次同步就可能出現 ExternalSecret 讀不到 Vault、workload 缺少 Secret,或 PVC 等不到儲存空間的情況。

範例使用 Git repository ssh://[email protected]/platform/k8s-infra.git、API server https://rke-api.example.internal:6443 與 Vault https://vault.example.internal:8200example-apiexample-worker 有公開入口,example-admin 維持內部使用。

Argo CD 接手後的同步順序

手動套用 clusters/root-app.yaml 後,Argo CD 從 clusters/apps 建立 child Applications,再管理 apps/ 與基礎設施設定。

這份 bootstrap 範例的 waves 如下:

  • -40:Gateway API CRDs。
  • -30:Istio base。
  • -20:Istio control plane。
  • -10:Istio CNI 與 ESO。
  • -5:ztunnel。
  • 0:Redis 與 Longhorn。
  • 5:application ExternalSecrets。
  • 10:application workloads 與 monitoring。
  • 15:Istio observability 與 Kiali。
  • 182030:admin、worker、API services。
  • 40:shared infrastructure 與 ingresses。

Wave 控制套用順序,不能單憑編號判定其他 controller 產生的物件已就緒。

第一次同步前的人工檢查

  1. kubectl 能連線 RKE cluster。
  2. Argo CD 已安裝在 argocd namespace,並可讀取私有 Git repository。
  3. Pods 可以連線 Vault。
  4. Vault Kubernetes auth、ESO policies 與 roles 已建立。
  5. 必要資料已存在 Vault KV v2。
  6. Longhorn 的 node 與 storage 前置條件已完成。
  7. Istio ambient 所需的 node 設定已完成。
  8. 公開服務有可用的 ingress 路徑。

安裝 Argo CD

這裡的 lab 範例使用 stable manifest;需要可重現的重建流程時,應固定到審查過的 release:

kubectl create namespace argocd
kubectl apply -n argocd --server-side --force-conflicts \
  -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

提供 Git credential 與 host trust

先取得 Git host key,從可信任管道核對 fingerprint,再將它加入 Argo CD 的 known hosts。ssh-keyscan 只能取回網路上的 key,不能證明 server 身分。

Repository credential 直接建立在 cluster:

ssh-keyscan git.example.com > /tmp/argocd_known_hosts
ssh-keygen -lf /tmp/argocd_known_hosts

kubectl -n argocd create configmap argocd-ssh-known-hosts-cm \
  --from-file=ssh_known_hosts=/tmp/argocd_known_hosts \
  --dry-run=client -o yaml | kubectl apply -f -

kubectl -n argocd create secret generic k8s-infra-repo \
  --from-literal=type=git \
  --from-literal=url=ssh://[email protected]/platform/k8s-infra.git \
  --from-file=sshPrivateKey=/home/user/.ssh/k8s_infra \
  --dry-run=client -o yaml | kubectl apply -f -

kubectl -n argocd label secret k8s-infra-repo \
  argocd.argoproj.io/secret-type=repository --overwrite

建立 Vault 的 reviewer 身分

ESO 使用 Kubernetes ServiceAccount 向 Vault 驗證;Vault 需要有權呼叫 TokenReview 的 reviewer:

kubectl create namespace vault-auth --dry-run=client -o yaml | kubectl apply -f -
kubectl -n vault-auth create serviceaccount vault-auth
kubectl create clusterrolebinding vault-auth-tokenreview \
  --clusterrole=system:auth-delegator \
  --serviceaccount=vault-auth:vault-auth

將以下內容存成 vault-auth-token.yaml

apiVersion: v1
kind: Secret
metadata:
  name: vault-auth-token
  namespace: vault-auth
  annotations:
    kubernetes.io/service-account.name: vault-auth
type: kubernetes.io/service-account-token

先等待 token controller 填入 Secret;若等待失敗,先停止後續步驟。再從目標 cluster 的 kubeconfig context 取得 JWT 與 CA;--flatten 會納入以檔案路徑引用的 CA:

kubectl apply -f vault-auth-token.yaml
kubectl -n vault-auth wait --for=jsonpath='{.data.token}' secret/vault-auth-token --timeout=60s
TOKEN_REVIEWER_JWT=$(kubectl -n vault-auth get secret vault-auth-token -o jsonpath='{.data.token}' | base64 -d)
kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > ca.crt

在 Vault 設定 Kubernetes auth:

export VAULT_ADDR=https://vault.example.internal:8200
vault login

vault auth enable kubernetes

vault write auth/kubernetes/config \
  kubernetes_host="https://rke-api.example.internal:6443" \
  kubernetes_ca_cert=@ca.crt \
  token_reviewer_jwt="$TOKEN_REVIEWER_JWT"

Auth mount 若已存在,只更新 config。Vault 1.9 起,新建 Kubernetes auth mount 預設使用 disable_iss_validation=true,由 Kubernetes 在 TokenReview 時驗證 issuer;舊 mount 可能保留先前設定。遇到 issuer mismatch 時,先查現有 mount 的設定,參考 Vault Kubernetes auth 文件

保存應用程式資料與 policy

真正的值先放進 Vault,Git 只保留對應關係:

vault kv put secret/example-api/env-file dotenv=@.env
vault kv put secret/example-worker/config-file config.json=@config.json
vault kv put secret/example-admin/config-file config=@config.yml

Policy 要使用 KV v2 API path,例如:

path "secret/data/example-api/*" {
  capabilities = ["read"]
}

還須將 policy 綁到 ESO 使用的 role,並建立信任 Vault CA 的 ClusterSecretStore。完整的 policy、role、Store 與 ExternalSecret 範例見 Vault 與 External Secrets

啟動 root Application 並檢查首輪同步

kubectl apply -f clusters/root-app.yaml
kubectl -n argocd get applications

先查 controller 與它產生的 Secrets,再查平台元件:

kubectl -n external-secrets get pods
kubectl get clustersecretstore
kubectl -n example-api get secret example-api-env-file
kubectl -n example-worker get secret example-worker-config-file
kubectl -n example-admin get secret example-admin-config-file
kubectl -n longhorn-system get pods
kubectl -n istio-system get pods
kubectl -n istio-system get daemonset istio-cni-node ztunnel
kubectl -n monitoring get podmonitor

最後看 workloads:

kubectl -n redis get pods
kubectl -n example-admin get pods
kubectl -n example-worker get pods
kubectl -n example-api get pods

從最早失敗的依賴排查

ClusterSecretStore 不健康時,先查 Vault auth 與 ESO logs:

kubectl describe clustersecretstore vault-example-api
kubectl -n external-secrets logs deploy/external-secrets --tail=120

ExternalSecret 讀不到資料時,核對 role、ServiceAccount 綁定、KV v2 policy path,以及 remote key/property。Redis 或其他 PVC 使用者無法啟動時,先查 Longhorn。

Pods 沒有加入 ambient 時,確認 namespace label、CNI 與 ztunnel 健康。Enrollment 本身不需要 restart;由 sidecar 遷移時才需要移除 injection 設定並重建受影響的 Pods。參考 Istio enrollment