實戰安裝 ArgoCD 並與 GitHub 建立安全連結。
安裝本身出乎意料地簡單:開一個專屬 Namespace,套用官方安裝檔。
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml --server-side
提醒:ArgoCD 的 CRD 大到會超過 annotation 的長度限制,
--server-side這個參數不加的話,apply 會直接失敗,錯誤訊息是metadata.annotations: Too long。原因是 client-side apply 會把整份原始 YAML 塞進last-applied-configuration這個 annotation 裡,而 annotation 有 256KB 上限。
還有一件事上線前要先想清楚:stable 這個標籤是浮動的。上面那行安裝指令抓的是「當下最新的穩定版」,代表你今天裝的跟三個月後同事裝的可能是不同版本。真的要進 production,把它換成明確的版本號:
kubectl apply -n argocd --server-side \
-f https://raw.githubusercontent.com/argoproj/argo-cd/v3.3.9/manifests/install.yaml
畢竟我們整個系列都在講「Git 是唯一真理」,結果連 GitOps 工具自己都用浮動版本安裝,那就有點好笑了。
kubectl apply 沒報錯不等於裝好了——這句話等一下會用一個真實案例打我自己的臉。先看三個檢查:

▲ 安裝驗證:七個元件、三張 CRD、以及 UI 走的那個 Service
檢查一:七個元件都要 Running
ArgoCD 不是一個服務,是一組各司其職的 controller:
| 元件 | 負責什麼 |
|---|---|
application-controller |
核心。持續比對期望狀態與實際狀態、執行同步、評估健康度。selfHeal 就是它在動手 |
repo-server |
把 Git clone 下來、把 Helm Chart 或 Kustomize 渲染成純 YAML。Day 20 會提到的「ArgoCD 底下沒有 Helm release」就是因為它只做 helm template |
server |
API Server + 那個章魚 UI,也負責認證授權。它不參與同步決策 |
redis |
快取渲染結果與資源樹。掛掉不會弄壞叢集,只是每次都要重算,UI 會變慢 |
dex-server |
SSO 的轉接頭,要接 GitHub / Google / LDAP 登入才需要它 |
notifications-controller |
依 App 狀態變化送通知(Slack、Webhook、Email) |
applicationset-controller |
用產生器批次生出 Application,管很多環境時才會用到 |
搞懂這張表最實際的好處是:出事時知道要看哪個 Pod 的日誌。同步卡住看 application-controller,Git 拉不下來或 Helm 渲染失敗看 repo-server,UI 進不去看 server。
檢查二:CRD 要齊
ArgoCD 靠三張 CRD 擴充 K8S 的 API:applications(部署單位)、appprojects(權限邊界)、applicationsets(批次產生器)。少一張,對應的 controller 就活不了。
檢查三:確認 UI 走哪個 Service
argocd-server 同時開了 80 和 443。443 是自簽憑證的 HTTPS——第 5 節那個坑就是從這裡長出來的。
上面那張圖是修好之後拍的。實際上我第一次認真跑這套驗證時,看到的是這樣:
argocd-applicationset-controller-7878b5cc9f-pkqzl 0/1 CrashLoopBackOff 4181 (68s ago) 96d
重啟四千一百八十一次,持續九十六天。 我完全不知道,因為 ArgoCD 該做的事它都在做——同步正常、UI 正常、部署正常。
照 Day 29 的排查順序,直接看日誌:
kubectl logs -n argocd deploy/argocd-applicationset-controller --tail=5
"error":"failed to get restmapping: no matches for kind \"ApplicationSet\" in version \"argoproj.io/v1alpha1\"",
"msg":"if kind is a CRD, it should be installed before calling Start"
原因如下:applicationsets.argoproj.io 這張 CRD 根本不在叢集裡。controller 啟動、找不到自己要管的資源類型、超時、死掉、重啟,循環了九十六天。回頭對照檢查二,kubectl get crd 的清單裡確實只有 applications 和 appprojects 兩張。
補上那張 CRD 就好了:
kubectl apply --server-side \
-f https://raw.githubusercontent.com/argoproj/argo-cd/v3.3.9/manifests/crds/applicationset-crd.yaml
kubectl -n argocd rollout restart deploy/argocd-applicationset-controller
這件事有兩個教訓。第一個是技術面的:CRD 和使用它的 controller 是兩份東西,--server-side 的分批 apply 有可能只成功一半,而 K8S 不會為此報錯。第二個更重要——壞掉的元件如果剛好沒人用,它可以壞很久很久。這跟 Day 29 會講的那種「沒有任何 Pod 在哭」的故障是同一個家族:不是沒有訊號,是沒有人在看。
所以裝完真的要驗,而且要照著清單一項一項對,不能只看「apply 沒報錯」。
UI 很好看,但很多操作用指令快得多,而且能寫進腳本。CLI 不是必要的,但我會建議裝:
# macOS
brew install argocd
# Windows
winget install argoproj.argocd
# Linux
curl -sSL -o /usr/local/bin/argocd \
https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
之後常用的大概就這幾個:
argocd login localhost:8443 --insecure # 自簽憑證,本機測試加 --insecure
argocd app list # 所有 App 的狀態一覽
argocd app get wafer-bi-platform # 單一 App 的細節與資源清單
argocd app diff wafer-bi-platform # Git 與叢集的差異(Day 17 §5-2)
argocd app sync wafer-bi-platform # 手動觸發同步
argocd app history wafer-bi-platform # 同步歷史
順帶一提:這些事情用 kubectl 也做得到,因為 Application 本身就是 CRD。像我後來要在腳本裡觸發同步,就直接 patch 資源,連 CLI 都不用裝:
kubectl patch app wafer-bi-platform -n argocd --type merge \
-p '{"operation":{"sync":{"revision":"main"}}}'
這也是 Day 17 說的「ArgoCD 用 CRD 擴充 K8S API」的好處:原本會的工具就能操作它。
先用 port-forward 存取(正式對外的做法在下一節):
kubectl -n argocd port-forward svc/argocd-server 8443:443
初始密碼藏在一個 Secret 裡:
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d
打開 https://localhost:8443,迎接你的是那隻著名的太空章魚:

▲ ArgoCD 登入頁:Let's get stuff deployed!
「Let's get stuff deployed!」——嗯,氣勢先給滿分 哈哈。
登入後第一件事是改密碼,然後把那個 Secret 刪掉:
argocd account update-password
kubectl -n argocd delete secret argocd-initial-admin-secret
為什麼要刪?因為 argocd-initial-admin-secret 是明文可解的初始密碼,任何拿得到那個 namespace 讀取權限的人都能拿它登入 ArgoCD——而 ArgoCD 的 admin 等於整座叢集的部署權限。改完密碼之後這個 Secret 就只是個沒必要留著的風險,ArgoCD 官方也建議刪掉。
本機用 port-forward 就夠了,但要給團隊用就得走 Ingress。這裡有一個幾乎每個人都會撞一次的問題:argocd-server 預設自己就是 HTTPS,而且用的是自簽憑證。
我自己在做這系列的截圖時就活生生撞到:拿瀏覽器自動化工具連上去,直接被 ERR_CERT_AUTHORITY_INVALID 擋掉;改連 HTTP 的 port,回我一個 307 重導向到 HTTPS。也就是說 HTTP 進不去、HTTPS 憑證不被信任,兩條路都不通。
這個問題有兩種解法,方向完全相反:
解法 A:讓 Ingress 不要拆封,直接轉給 ArgoCD(我們專案用的)
helm/wafer-bi/templates/argocd-ingress.yaml 的關鍵三行:
annotations:
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true" # TLS 不在 nginx 拆
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" # 後端講 HTTPS
TLS 連線一路穿過 nginx,由 argocd-server 自己終結。但有個前提很多人不知道:Nginx Ingress Controller 的 --enable-ssl-passthrough 預設是關的,沒開的話這個 annotation 完全不會生效,你會得到一個看起來設定正確、實際上沒作用的 Ingress。
解法 B:讓 ArgoCD 不要自己做 TLS
kubectl -n argocd patch cm argocd-cmd-params-cm --type merge \
-p '{"data":{"server.insecure":"true"}}'
kubectl -n argocd rollout restart deploy/argocd-server
argocd-server 改成純 HTTP,TLS 交給 Ingress 終結(正式環境搭 cert-manager 簽的憑證,就是 Day 11 做的事)。這樣就不會有自簽憑證的問題,設定也單純很多。
要注意 insecure 這個字容易誤導:它指的是「argocd-server 這一段不加密」,不是「整條連線不加密」。只要 Ingress 有正確終結 TLS,使用者到叢集之間依然是 HTTPS,裸露的只有叢集內部那一段。但如果你沒有 Ingress 就開這個參數,那就真的是明文了。
Application 是 ArgoCD 的核心資源:「哪個 Git repo 的哪個路徑,部署到哪個叢集的哪個 namespace」。可以在 UI 點 New App,但既然都 GitOps 了,我們用 YAML 宣告(k8s/argocd-app.yaml):
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: wafer-bi-platform
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/DarkSchneider1024/wafer-bi.git
targetRevision: main
path: helm/wafer-bi # ← ArgoCD 直接吃 Helm Chart
helm:
valueFiles:
- values.yaml
- values-production.yaml # production 覆寫(replicas、HPA…)
destination:
server: https://kubernetes.default.svc
namespace: k8sdemo
syncPolicy:
automated:
prune: true # Git 裡刪掉的資源,叢集也自動刪
selfHeal: true # 有人手動改叢集?自動改回來
syncOptions:
- CreateNamespace=true
這份 YAML 有以下幾個地方要說明:
path: helm/wafer-bi:ArgoCD 原生支援 Helm,會自動 helm template 渲染再比對,Day 10 的 Chart 直接無縫接軌automated + prune + selfHeal:production 開全自動;本機示範時我刻意拿掉 automated 改手動 sync,才能親眼看到 Day 17 講的那個 OutOfSync → Synced 的對比過程apply 下去之後回到 UI,點進 App 看資源樹——Day 17 看的是清單頁的狀態,這裡才是真正發生了什麼:

▲ 剛建立:Git 說要有 jaeger(deploy)和 jaeger-service(svc),叢集裡兩個都還是幽靈狀態
(這裡示範用的是一個輕量的 Application,指向 repo 的 k8s/base/observability,資源少、看得清楚。換成 helm/wafer-bi 的話樹會長成三十幾個節點,截圖上什麼都看不到。)
這裡有以下兩個細節要注意:
from main (6bdc539)——ArgoCD 明確告訴你比對的基準是哪一個 commit,底下還帶出作者和 commit 訊息。這裡的作者是 github-actions[bot],正是明天要講的 CI 自動回填留下的痕跡Auto sync is not enabled——這個 demo 我刻意關掉自動同步,才拍得到「Git 有、叢集還沒有」的中間狀態按下 SYNC:

▲ 同步完成:Sync OK,資源樹從 App 一路長到 Pod,全部亮綠
樹的形狀是這張圖最值得看的地方:Git 裡只寫了 2 個資源,樹上卻長出 4 個節點——多出來的 ReplicaSet 和 Pod 不在 Git 裡,是 K8S 自己派生的。ArgoCD 分得清楚這件事:它只對「Git 裡有的」做同步判定,但把「因此產生的」全部顯示出來讓你追蹤健康狀態。
這也解釋了 Day 17 說的那兩個獨立維度為什麼會分開:Pod 掛掉時 Health 變 Degraded,但 Sync Status 依然是 Synced——因為 Git 跟叢集確實一致,只是那個一致的版本跑不起來。
而且這棵樹是可以互動的:點任何一個節點都能直接看它的 Events、Logs、YAML,甚至直接刪掉它(然後看 ArgoCD 把它長回來)。對不熟 kubectl 的團隊成員來說滿方便的。
上面那份 YAML 有一行很容易被跳過:project: default。
AppProject 是 ArgoCD 的權限邊界。預設的 default project 幾乎沒有任何限制——它允許來源是任何 repo、目的地是任何叢集的任何 namespace、可以部署任何種類的資源。一個人只要能建 Application,就能把任意 Git repo 的內容部署到你叢集的任何角落。
自己一個人玩沒差,但只要開始有第二個人碰它,就該建自己的 project:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: wafer-bi
namespace: argocd
spec:
sourceRepos: # 只准從我們自己的 repo 部署
- https://github.com/DarkSchneider1024/wafer-bi.git
destinations: # 只准部署到這個 namespace
- server: https://kubernetes.default.svc
namespace: k8sdemo
clusterResourceWhitelist: [] # 不准碰叢集層級資源(如 ClusterRole)
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota
搭配 argocd-rbac-cm 這張 ConfigMap,還能做到「A 團隊只能 sync 自己的 App、看不到別人的」。這是那種「出事之後才會後悔沒設」的東西——GitOps 把部署權限從人手上收走交給 controller,但如果 controller 本身無所不能,你只是換了一個單點風險。
我們的 repo 是 public,ArgoCD 匿名就能拉。如果是私有 repo,在 Settings → Repositories 加一組 Deploy Key(唯讀 SSH key)或 GitHub App 憑證即可。
這一頁也是安裝驗證的最後一塊:它會告訴你 ArgoCD 到底連不連得到你的 Git。

▲ Settings → Repositories:CONNECTION STATUS 顯示 Successful,代表 repo-server 真的拉得到這個 repo
那個 Successful 是實際去連過的結果,不是設定填完就給你的樂觀顯示。如果憑證錯了、網路不通、或 repo 路徑打錯,這裡會直接顯示 Failed 並附上錯誤訊息——比等到建完 Application 才發現 ComparisonError 快多了。私有 repo 接不上時,第一個該看的就是這一頁。
實務上有以下三件事情要注意:
GitOps 中心開張了。今天最想強調的其實不是安裝——安裝真的只有兩行——而是安裝之後的那些事:
insecure 到底不安全在哪一段、知道 project: default 是一張沒有上限的信用卡但目前為止 CI 跟 ArgoCD 還是兩條平行線——CI 產 image,ArgoCD 看 Git,中間差一個「誰去把新版本號寫進 Git」。明天就來把這最後一哩路接起來,完成全自動閉環。