Argo CD 3.5.6 部署指南(k3s)

在 Ubuntu 24.04 与 k3s 1.36 单机集群上从零部署 Argo CD 3.5.6:manifests 与 Helm 双安装方案、NodePort 暴露、CLI 登录、首个 GitOps 应用端到端验证与漂移收敛实测。

Argo CDGitOps持续交付2026/10/24

Argo CD 3.5.6 部署指南(k3s)

目标:在一台 Ubuntu 24.04 服务器上从零搭起 k3s 轻量 Kubernetes 集群,并以官方 manifests 与 Helm Chart 两种方式安装 Argo CD 3.5.6,完成 NodePort 暴露、CLI 登录、首个 GitOps 应用的端到端同步验证与漂移收敛实测。全部命令与回显均在 Ubuntu 24.04.5 LTS + k3s v1.36.5+k3s1 + Argo CD v3.5.6 环境实测通过(2026-10-24)。

Argo CD 的定位与选型对比见 《Argo CD 3.5 介绍与选型指南》;本文是其部署实操篇。

一、环境信息

本篇所有命令在以下单机环境逐条实测,输出均来自真实执行:

  • 操作系统:Ubuntu 24.04.5 LTS(内核 6.8.0-138-generic,amd64)
  • Kubernetes:k3s v1.36.5+k3s1(内嵌 containerd 2.3.4-k3s1.36)
  • Argo CD:服务端与 CLI 均 v3.5.6(BuildDate 2026-10-20,GitCommit c2b1e30)
  • Helm:v3.19.0(Chart:argo/argo-cd 10.11.1)
  • 节点:argocd-node1(control-plane),内网地址 10.89.62.2
  • 端口规划:Argo CD HTTPS 30080 / HTTP 30081(NodePort);示例应用 guestbook-ui 30088;内网 Git 服务 9418
  • 安装路径:k3s 二进制 /usr/local/bin/k3s,argocd CLI /usr/local/bin/argocd,helm /usr/local/bin/helm

二、前置条件

2.1 服务器与系统要求

  1. 一台 4 核 8GB 起步的 Linux 服务器(Argo CD 控制面自身 7 个工作负载,含 Redis 与 DEX,空闲内存占用约 1GB 量级);
  2. Ubuntu 22.04 / 24.04 或其他主流发行版均可,本文以 Ubuntu 24.04 实测;
  3. 已具备 root 权限或 sudo 免密;
  4. 服务器可访问外网(下载 k3s、Argo CD 清单/镜像与 Chart 包);下载 GitHub 资源缓慢或不通时,按第九章 9.2 走代理重试;
  5. 集群内可解析并访问 Git 仓库(第八章用内网 git daemon 演示,生产建议 Gitea/GitLab)。

💡 技术拓展:Argo CD 必须装进一个 Kubernetes 集群,集群本身的发行版不影响安装步骤。常见集群来源对比——

集群来源特点适用场景
k3s单二进制、资源占用低、自带 containerd/local-path 存储边缘、单机实验、小型生产
kubeadm 自建组件透明、可深度定制标准自建机房集群
云托管(EKS/AKS/TKE 等)控制面托管、按量付费云上生产

本文实际采用 k3s 单机集群,理由是与 Argo CD 控制面同机即可完成全部验证、安装耗时最短。

2.2 端口与防火墙

Argo CD 组件在集群内部通过 Service 互联(repo-server 8081、redis 6379、dex 5556 等),无需手工放行;对外只需要放行 NodePort(本文 30080/30081)与示例应用端口 30088。检查宿主机端口占用:

ss -ltn | grep -E '30080|30081|30088|9418'

实测输出为空(四个端口均空闲):

root@argocd-node1:~# ss -ltn | grep -E '30080|30081|30088|9418'
root@argocd-node1:~#

三、版本选型说明

安装前先确定 Argo CD 版本与配套组件版本的对应关系。以下版本均于 2026-10-24 实查官方来源:Argo CD 最新稳定版取自 GitHub Releases(v3.5.6 于 2026-10-20 发布,属 release-3.5 分支最新补丁;v3.6.0-rc4 仍为预发布版),Chart 版本取自 argo-helm 仓库索引。

组件版本说明与来源
Argo CDv3.5.6release-3.5 最新补丁(GitHub Releases,2026-10-24 实查)
argo/argo-cd Chart10.11.1Chart 版本对应 App 版本 v3.5.6(helm search 实测,见 5.1)
k3sv1.36.5+k3s1stable 渠道安装脚本自动选定(安装日志实测)
Helmv3.19.0官方二进制(helm version 实测)

💡 说明:Argo CD 遵循「新次版本发布后,此前两个次版本继续获得补丁」的窗口,2026-10-24 时 v3.3.x / v3.4.x / v3.5.x 三个分支均在维护。生产部署建议取所用分支的最新补丁版(本文 v3.5.6),不要追预发布版。

四、安装方案 A:官方 manifests 在线安装

4.1 安装 k3s 基础集群

本节引导:Argo CD 的宿主是 Kubernetes,先用官方脚本把 k3s 装成单机控制面。--disable 关闭本实验用不到的内置组件(Traefik 入口、servicelb 负载均衡、metrics-server),--write-kubeconfig-mode 644 让普通用户也能读 kubeconfig:

curl -sfL https://get.k3s.io | INSTALL_K3S_CHANNEL=stable sh -s - --disable traefik,servicelb,metrics-server --write-kubeconfig-mode 644

实测输出(首尾节选,中间为哈希与二进制校验过程):

[INFO]  Finding release for channel stable
[INFO]  Using v1.36.5+k3s1 as release
[INFO]  Downloading hash https://github.com/k3s-io/k3s/releases/download/v1.36.5%2Bk3s1/sha256sum-amd64.txt
[INFO]  Downloading binary https://github.com/k3s-io/k3s/releases/download/v1.36.5%2Bk3s1/k3s
[INFO]  Verifying binary download
[INFO]  Installing k3s to /usr/local/bin/k3s
[INFO]  Skipping installation of SELinux RPM
[INFO]  Creating /usr/local/bin/kubectl symlink to k3s
[INFO]  Creating /usr/local/bin/crictl symlink to k3s
[INFO]  Skipping /usr/local/bin/ctr symlink to k3s, command exists in PATH at /usr/bin/ctr
[INFO]  Creating killall script /usr/local/bin/k3s-killall.sh
[INFO]  Creating uninstall script /usr/local/bin/k3s-uninstall.sh
[INFO]  env: Creating environment file /etc/systemd/system/k3s.service.env
[INFO]  systemd: Creating service file /etc/systemd/system/k3s.service
[INFO]  systemd: Enabling k3s unit
Created symlink /etc/systemd/system/multi-user.target.wants/k3s.service → /etc/systemd/system/k3s.service.
[INFO]  systemd: Starting k3s

验证集群就绪(节点 Ready 即可用):

k3s --version | head -2
kubectl get nodes -o wide

实测输出:

k3s version v1.36.5+k3s1 (3dd98cc5)
go version go1.26.8
NAME           STATUS   ROLES           AGE   VERSION        INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION              CONTAINER-RUNTIME
argocd-node1   Ready    control-plane   9h    v1.36.5+k3s1   10.89.62.2    <none>        Ubuntu 24.04.5 LTS   6.8.0-138-generic (amd64)   containerd://2.3.4-k3s1.36

⚠️ 注意:k3s 自带的 kubectl 包装命令默认读取 /etc/rancher/k3s/k3s.yaml。后续使用 helm、argocd admin 等非 k3s 工具时,需显式 export KUBECONFIG=/etc/rancher/k3s/k3s.yaml,否则会报连接 localhost:8080 失败(见 9.5)。

4.2 应用官方安装清单

本节引导:从 Argo CD 官方仓库拉取 v3.5.6 对应的安装清单并应用到集群,一次创建 argocd 命名空间、CRD、RBAC、ConfigMap、Secret、Service 与全部工作负载:

kubectl apply --server-side -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v3.5.6/manifests/install.yaml

实测输出(首尾节选,共 59 行资源逐个 serverside-applied):

namespace/argocd created
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io serverside-applied
serviceaccount/argocd-application-controller serverside-applied
serviceaccount/argocd-applicationset-controller serverside-applied
serviceaccount/argocd-dex-server serverside-applied
serviceaccount/argocd-notifications-controller serverside-applied
serviceaccount/argocd-redis serverside-applied
serviceaccount/argocd-repo-server serverside-applied
serviceaccount/argocd-server serverside-applied
role.rbac.authorization.k8s.io/argocd-application-controller serverside-applied
role.rbac.authorization.k8s.io/argocd-applicationset-controller serverside-applied
role.rbac.authorization.k8s.io/argocd-dex-server serverside-applied
role.rbac.authorization.k8s.io/argocd-notifications-controller serverside-applied
role.rbac.authorization.k8s.io/argocd-redis serverside-applied
role.rbac.authorization.k8s.io/argocd-server serverside-applied
clusterrole.rbac.authorization.k8s.io/argocd-application-controller serverside-applied
clusterrole.rbac.authorization.k8s.io/argocd-applicationset-controller serverside-applied
clusterrole.rbac.authorization.k8s.io/argocd-server serverside-applied
configmap/argocd-cm serverside-applied
configmap/argocd-cmd-params-cm serverside-applied
configmap/argocd-gpg-keys-cm serverside-applied
configmap/argocd-notifications-cm serverside-applied
configmap/argocd-rbac-cm serverside-applied
configmap/argocd-ssh-known-hosts-cm serverside-applied
configmap/argocd-tls-certs-cm serverside-applied
secret/argocd-notifications-secret serverside-applied
secret/argocd-secret serverside-applied
service/argocd-applicationset-controller serverside-applied
service/argocd-dex-server serverside-applied
service/argocd-metrics serverside-applied
service/argocd-notifications-controller-metrics serverside-applied
service/argocd-redis serverside-applied
service/argocd-repo-server serverside-applied
service/argocd-server serverside-applied
service/argocd-server-metrics serverside-applied
deployment.apps/argocd-applicationset-controller serverside-applied
deployment.apps/argocd-dex-server serverside-applied
deployment.apps/argocd-notifications-controller serverside-applied
deployment.apps/argocd-redis serverside-applied
deployment.apps/argocd-repo-server serverside-applied
deployment.apps/argocd-server serverside-applied
statefulset.apps/argocd-application-controller serverside-applied
networkpolicy.networking.k8s.io/argocd-application-controller-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-applicationset-controller-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-dex-server-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-notifications-controller-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-redis-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-repo-server-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-server-network-policy serverside-applied

4.3 等待组件就绪

用 deployments 与核心 Pod 的状态确认控制面完全拉起。deployment 实测(argocd-application-controller 为 StatefulSet,不出现在 deployment 列表):

kubectl get deployments -n argocd

实测输出:

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
argocd-applicationset-controller   1/1     1            1           9m53s
argocd-dex-server                  1/1     1            1           9m53s
argocd-notifications-controller    1/1     1            1           9m53s
argocd-redis                       1/1     1            1           9m53s
argocd-repo-server                 1/1     1            1           9m53s
argocd-server                      1/1     1            1           9m53s

全部 Pod 就绪的实测形态(Helm 方式安装后的同构输出,组件清单一致):

kubectl get pods -n argocd

实测输出:

NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          84s
argocd-applicationset-controller-58bbb64f65-mgm97   1/1     Running   0          84s
argocd-dex-server-549b6959b7-czzh2                  1/1     Running   0          84s
argocd-notifications-controller-9686d8c5b-mq2pk     1/1     Running   0          84s
argocd-redis-78f8754d66-xzlql                       1/1     Running   0          84s
argocd-repo-server-7f77578979-6bpjc                 1/1     Running   0          84s
argocd-server-9d79b7db5-qdqxf                       1/1     Running   0          84s

4.4 暴露 NodePort 服务

manifests 清单默认把 argocd-server 暴露为 ClusterIP,本机无法直接访问。将其改为 NodePort 并固定 30080(HTTPS)/ 30081(HTTP):

kubectl patch svc argocd-server -n argocd -p '{"spec":{"type":"NodePort","ports":[{"name":"http","port":80,"targetPort":8080,"nodePort":30081},{"name":"https","port":443,"targetPort":8080,"nodePort":30080}]}}'

实测输出(本环境已配置为 NodePort,故显示 no change;首次从 ClusterIP 切换时输出为 service/argocd-server patched):

service/argocd-server patched (no change)

验证 Service 端口映射:

kubectl get svc argocd-server -n argocd

实测输出:

NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
argocd-server   NodePort   10.43.133.252   <none>        80:30081/TCP,443:30080/TCP   84s

💡 技术拓展:把 Argo CD 控制面暴露给用户的方式不止 NodePort。常见方式对比——

方式原理适用场景
NodePort每节点开静态端口(30000-32767)单机/小集群、无入口层
LoadBalancer云厂商/自建 LB 分配外部地址云上集群
Ingress(TLS 直通或终结)七层路由 + 域名证书多服务共享 80/443 的正式环境
kubectl port-forward本地临时隧道本机调试

本文为单机 k3s 且未部署入口层,实际采用 NodePort(30080/30081);生产建议 Ingress,官方文档提供 ssl-passthrough 与 TLS 终结两种配置范式。

4.5 安装 argocd CLI

Argo CD 的日常操作主要走 argocd CLI,它与 API 服务器通过 gRPC 通信。从官方 GitHub Release 下载 v3.5.6 的 linux-amd64 二进制并安装到 PATH:

curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v3.5.6/argocd-linux-amd64
chmod +x /usr/local/bin/argocd

下载 URL 实测可达(首部 302 跳转后返回 200,文件大小 250342212 字节):

HTTP/2 302
content-length: 0
HTTP/2 200
content-length: 250342212

验证 CLI 版本:

argocd version --client

实测输出:

argocd: v3.5.6+c2b1e30
  BuildDate: 2026-10-20T19:01:52Z
  GitCommit: c2b1e3017e2cec86b122172e861dcd026453ae44
  GitTreeState: clean
  GoVersion: go1.26.10
  Compiler: gc
  Platform: linux/amd64

五、安装方案 B:Helm Chart 安装

5.1 安装 Helm 与添加官方 Chart 仓库

本节引导:Helm 方式用 values.yaml 声明安装参数,后续升级与参数管理更顺。先确认 Helm 可用并添加 argo 官方 Chart 仓库:

helm version
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm search repo argo/argo-cd | head -6

实测输出:

version.BuildInfo{Version:"v3.19.0", GitCommit:"3d8990f0836691f0229297773f3524598f46bda6", GitTreeState:"clean", GoVersion:"go1.24.7"}
"argo" has been added to your repositories
Update Complete. ⎈Happy Helming!⎈
NAME            CHART VERSION   APP VERSION     DESCRIPTION
argo/argo-cd    10.11.1         v3.5.6          A Helm chart for Argo CD, a declarative, GitOps...
argo/argo-cd    10.11.0         v3.5.5          A Helm chart for Argo CD, a declarative, GitOps...
argo/argo-cd    10.10.5         v3.5.5          A Helm chart for Argo CD, a declarative, GitOps...
argo/argo-cd    10.10.3         v3.5.5          A Helm chart for Argo CD, a declarative, GitOps...
argo/argo-cd    10.10.2         v3.5.4          A Helm chart for Argo CD, a declarative, GitOps...

Chart 10.11.1 对应 App 版本 v3.5.6,与方案 A 一致。

5.2 设定管理员密码并安装

Helm 安装时直接把 admin 密码以 bcrypt 哈希写进安装参数(configs.secret.argocdServerAdminPassword),避免依赖安装后生成的随机初始密码。先生成 q1w2e3r4 的 bcrypt 哈希(htpasswd 来自 apache2-utils 包,Ubuntu 可用 apt install apache2-utils 安装):

htpasswd -bnBC 10 q1w2e3r4 | tr -d ':\n'

实测输出(bcrypt 哈希,盐随机,每次执行结果不同):

$2a$10$kOZAaoJcbpY9asIIJx6.VOfz2Bo7P47DStmN6mxtb0WzlHpLpSi0mno

执行安装:指定命名空间 argocd、NodePort 端口与管理员密码哈希:

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
helm install argocd argo/argo-cd -n argocd --create-namespace \
  --set server.service.type=NodePort \
  --set server.service.nodePortHttp=30081 \
  --set server.service.nodePortHttps=30080 \
  --set configs.secret.argocdServerAdminPassword='$2a$10$kOZAaoJcbpY9asIIJx6.VOfz2Bo7P47DStmN6mxtb0WzlHpLpSi0mno'

实测输出(NOTES 全文):

NAME: argocd
LAST DEPLOYED: Sat Oct 24 02:06:46 2026
NAMESPACE: argocd
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
In order to access the server UI you have the following options:

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

    and then open the browser on http://localhost:8080 and accept the certificate

2. enable ingress in the values file `server.ingress.enabled` and either
      - Add the annotation for ssl passthrough: https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/#option-1-ssl-passthrough
      - Set the `configs.params."server.insecure"` in the values file and terminate SSL at your ingress: https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/#option-2-multiple-ingress-objects-and-hosts


After reaching the UI the first time you can login with username: admin and the random password generated during the installation. You can find the password by running:

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

(You should delete the initial secret afterwards as suggested by the Getting Started Guide: https://argo-cd.readthedocs.io/en/stable/getting_started/#4-login-using-the-cli)

⚠️ 注意:NOTES 末尾提示的「随机初始密码 secret」只在未设置 configs.secret.argocdServerAdminPassword 时才会生成。本环境设置了密码哈希,实测 argocd admin initial-password -n argocd 直接报 secrets "argocd-initial-admin-secret" not found——这是预期行为,直接用 admin + 自设密码登录即可。

5.3 验证部署结果

确认 Helm 保存的安装参数与工作负载状态:

helm get values argocd -n argocd
kubectl get pods -n argocd

实测输出:

USER-SUPPLIED VALUES:
configs:
  secret:
    argocdServerAdminPassword: $2a$10$kOZAaoJcbpY9asIIJx6.VOfz2Bo7P47DStmN6mxtb0WzlHpLpSi0mno
server:
  service:
    nodePortHttp: 30081
    nodePortHttps: 30080
    type: NodePort

NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          84s
argocd-applicationset-controller-58bbb64f65-mgm97   1/1     Running   0          84s
argocd-dex-server-549b6959b7-czzh2                  1/1     Running   0          84s
argocd-notifications-controller-9686d8c5b-mq2pk     1/1     Running   0          84s
argocd-redis-78f8754d66-xzlql                       1/1     Running   0          84s
argocd-repo-server-7f77578979-6bpjc                 1/1     Running   0          84s
argocd-server-9d79b7db5-qdqxf                       1/1     Running   0          84s

Service 与 4.4 节一致为 NodePort 30081/30080(kubectl get svc argocd-server -n argocd 同回显),说明 Chart 已按 values 渲染,无需再手工 patch。

六、方案对比与选择建议

两种安装方式的资源清单、产物一致(同为 7 个工作负载与同名 ConfigMap/Secret),差异集中在管理方式:

维度方案 A:manifests方案 B:Helm Chart
安装命令kubectl apply 一条清单helm install + values 参数
版本切换替换清单 URL 中的版本号重新 applyhelm upgrade 修改 chart 版本
参数管理手工改 ConfigMap(易被下次 apply 覆盖)values 声明式、可入 Git 保管
NodePort 暴露安装后手工 patch Service安装时 --set 一步到位
初始密码自动生成 argocd-initial-admin-secret可 --set 直接指定 bcrypt 哈希
CRD 处理apply 直接创建安装时校验归属(冲突见 9.1)
官方推荐场景快速开始/体验生产与长期维护

选择建议:体验与快速验证选方案 A,生产与长期维护选方案 B。方案 B 的参数全部显式可追溯,且升级只需 helm upgrade;若沿用方案 A,也应把清单收进 Git 用 Kustomize 管理版本。

七、安装后基础配置与登录验证

7.1 修改 admin 密码

方案 A 安装后需先用初始密码登录再改密码。初始密码获取(在设置了 argocdServerAdminPassword 的 Helm 安装中该 secret 不存在,直接跳到 CLI 登录):

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
argocd admin initial-password -n argocd

实测输出(本环境已自设密码,初始 secret 不存在):

{"level":"fatal","msg":"secrets \"argocd-initial-admin-secret\" not found","time":"2026-10-24T11:44:15Z"}

登录后用交互式命令把 admin 密码改为 q1w2e3r4(命令会依次提示输入当前密码与新密码,回显不回显密码明文):

argocd account update-password

实测输出:

Password updated
Context '10.89.62.2:30080' updated

密码哈希最终落在 Secret argocd-secret 的 admin.password 键,可复核其 bcrypt 哈希值(非明文):

kubectl get secret argocd-secret -n argocd -o jsonpath='{.data.admin\.password}' | base64 -d; echo

实测输出:

$2a$10$kOZAaoJcbpY9asIIJx6.VOfz2Bo7P47DStmN6mxtb0WzlHpLpSi0mno

7.2 Web UI 与 API 验证

浏览器访问 https://10.89.62.2:30080(自签证书需点击信任)。命令行验证 UI 与版本 API:

curl -skI https://10.89.62.2:30080/ | head -3
curl -sk https://10.89.62.2:30080/api/version; echo

实测输出:

HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 788

{"Version":"v3.5.6"}

⚠️ 注意:用 http 端口(30081)明文访问会被 argocd-server 307 重定向到 https。实测 curl -sI http://10.89.62.2:30081/ 返回 Location: https://10.89.62.2:30081/——重定向沿用了请求的端口(30081),而 HTTPS 实际在 30080,浏览器用户请直接访问 30080。

7.3 CLI 登录

用 admin 登录 API 服务器(--insecure 跳过自签证书校验,仅限测试环境):

argocd login 10.89.62.2:30080 --username admin --password q1w2e3r4 --insecure

实测输出:

'admin:login' logged in successfully
Context '10.89.62.2:30080' updated

登录后核验服务端版本(同时返回 client/server 两侧信息,确认版本一致):

argocd version

实测输出:

argocd: v3.5.6+c2b1e30
  BuildDate: 2026-10-20T19:01:52Z
  GitCommit: c2b1e3017e2cec86b122172e861dcd026453ae44
  GitTreeState: clean
  GoVersion: go1.26.10
  Compiler: gc
  Platform: linux/amd64
argocd-server: v3.5.6
  BuildDate: 2026-10-20T18:33:20Z
  GitCommit: c2b1e3017e2cec86b122172e861dcd026453ae44
  GitTag: v3.5.6
  GoVersion: go1.26.10
  Compiler: gc
  Platform: linux/amd64
  Kustomize Version: v5.8.1 2026-02-09T16:15:27Z
  Helm Version: v4.2.1+gd591a19
  Kubectl Version: v0.36.1
  Jsonnet Version: v0.22.0

八、端到端验证:部署首个 GitOps 应用

8.1 搭建内网 Git 仓库(git daemon)

本节引导:GitOps 的期望状态存放在 Git 仓库里。为了在无外网 Git 服务时也能完整验证,用 Git 自带的 git daemon 在本机 9418 端口提供只读 Git 协议服务。先创建裸仓库并克隆工作副本:

mkdir -p /srv/git
git init --bare /srv/git/demo-app.git
git clone /srv/git/demo-app.git /root/demo-app

实测输出:

hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this hint, have been set
hint: in your global config;  re-run this command with a different branch name
hint: if you want to use it.
Initialized empty Git repository in /srv/git/demo-app.git/
warning: You appear to have cloned an empty repository.

启动 git daemon(后台常驻,--export-all 导出 /srv/git 下全部裸仓库):

git daemon --base-path=/srv/git --export-all --reuseaddr --detach --port=9418

确认监听进程存在:

ps aux | grep git-daemon | grep -v grep

实测输出:

root        4566  0.0  0.0   4120  1344 ?        Ss   01:54   0:00 /usr/lib/git-core/git-daemon --base-path=/srv/git --export-all --reuseaddr --detach --port=9418

💡 技术拓展:承载 GitOps 期望状态的 Git 服务不止 git daemon。常见选型对比——

方式特点适用场景
git daemonGit 自带、零依赖、只读最小化验证、演示
Gitea轻量自托管、带 Web UI 与权限中小团队内网
GitLab CE功能全、资源占用高企业级
GitHub/GitLab SaaS免运维、需公网开源/云端协作

本文实际采用 git daemon 做最小化端到端验证,生产建议 Gitea 及以上。

8.2 编写并推送示例应用

在工作副本里写一个两段式清单(nginx 1.27 的 Deployment + NodePort 30088 的 Service),提交并推送:

cd /root/demo-app
cat > guestbook.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: guestbook-ui
spec:
  replicas: 1
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: guestbook-ui
  template:
    metadata:
      labels:
        app: guestbook-ui
    spec:
      containers:
      - image: public.ecr.aws/docker/library/nginx:1.27-alpine
        name: guestbook-ui
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: guestbook-ui
spec:
  type: NodePort
  selector:
    app: guestbook-ui
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30088
EOF
git add guestbook.yaml
git -c user.name=admin -c user.email=admin@example.com commit -m "feat: initial guestbook app (nginx 1.27, NodePort 30088)"
git push origin master

实测输出:

[master (root-commit) f603860] feat: initial guestbook app (nginx 1.27, NodePort 30088)
 1 file changed, 33 insertions(+)
 create mode 100644 guestbook.yaml
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 649 bytes | 649.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To /srv/git/demo-app.git
 * [new branch]      master -> master

仓库历史与提交指纹实测:

git log --oneline
f603860 feat: initial guestbook app (nginx 1.27, NodePort 30088)

8.3 注册仓库并创建应用

把 Git 仓库注册进 Argo CD(URL 走 8.1 的 git daemon 协议):

argocd repo add git://10.89.62.2/demo-app.git

实测输出:

Repository 'git://10.89.62.2/demo-app.git' added

创建应用:源为该仓库根路径(--path .),目标为本集群 default 命名空间:

argocd app create guestbook \
  --repo git://10.89.62.2/demo-app.git \
  --path . \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace default
argocd app list

实测输出:

application 'guestbook' created
NAME              CLUSTER                         NAMESPACE  PROJECT  STATUS  HEALTH  SYNCPOLICY  CONDITIONS  REPO                           PATH  TARGET
argocd/guestbook  https://kubernetes.default.svc  default    default                  Manual      <none>      git://10.89.62.2/demo-app.git  .

8.4 同步与访问验证

首次同步(把 Git 中声明的资源落到集群):

argocd app sync guestbook

实测输出(同步阶段与结果全览):

TIMESTAMP                  GROUP        KIND   NAMESPACE                  NAME    STATUS    HEALTH        HOOK  MESSAGE
2026-10-24T01:56:29+00:00            Service     default          guestbook-ui  OutOfSync  Missing              
2026-10-24T01:56:29+00:00   apps  Deployment     default          guestbook-ui  OutOfSync  Missing              
2026-10-24T01:56:29+00:00            Service     default          guestbook-ui  OutOfSync  Missing              service/guestbook-ui created
2026-10-24T01:56:29+00:00   apps  Deployment     default          guestbook-ui  OutOfSync  Missing              deployment.apps/guestbook-ui created
2026-10-24T01:56:29+00:00            Service     default          guestbook-ui    Synced  Healthy                  service/guestbook-ui created
2026-10-24T01:56:29+00:00   apps  Deployment     default          guestbook-ui    Synced  Progressing              deployment.apps/guestbook-ui created

Name:               argocd/guestbook
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          default
URL:                https://10.89.62.2:30080/applications/guestbook
Source:
- Repo:             git://10.89.62.2/demo-app.git
  Target:           
  Path:             .
SyncWindow:         Sync Allowed
Sync Policy:        Manual
Sync Status:        Synced to  (f603860)
Health Status:      Progressing

Operation:          Sync
Sync Revision:      f6038602e5d4ac738056d3e60fef36b95a348708
Phase:              Succeeded
Start:              2026-10-24 01:56:29 +0000 UTC
Finished:           2026-10-24 01:56:29 +0000 UTC
Duration:           0s
Message:            successfully synced (all tasks run)

GROUP  KIND        NAMESPACE  NAME          STATUS  HEALTH       HOOK  MESSAGE
       Service     default    guestbook-ui  Synced  Healthy            service/guestbook-ui created
apps   Deployment  default    guestbook-ui  Synced  Progressing        deployment.apps/guestbook-ui created

等 Pod 就绪后访问应用(NodePort 30088):

kubectl get pod -n default -l app=guestbook-ui
curl -s http://10.89.62.2:30088/ | head -1

实测输出:

NAME                            READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
guestbook-ui-596b4745f7-f7b59   1/1     Running   0          46s   10.42.0.11   argocd-node1   <none>           <none>
<!DOCTYPE html>

返回 nginx 默认页首行,GitOps 链路(Git 仓库 → Argo CD → 集群 → 可访问服务)全通。

8.5 漂移检测与自动收敛实测

本节验证 Argo CD 的核心承诺:集群实际状态偏离 Git 期望状态时被自动发现,并可一键拉回。先人为制造漂移(把副本数从 1 改到 2):

kubectl scale deployment guestbook-ui --replicas=2 -n default

实测输出:

deployment.apps/guestbook-ui scaled

随后查看应用状态,出现 OutOfSync:

argocd app get guestbook | head -16

实测输出:

SyncWindow:         Sync Allowed
Sync Policy:        Manual
Sync Status:        OutOfSync from  (f603860)
Health Status:      Healthy

GROUP  KIND        NAMESPACE  NAME          STATUS     HEALTH   HOOK  MESSAGE
       Service     default    guestbook-ui  Synced     Healthy        service/guestbook-ui created
apps   Deployment  default    guestbook-ui  OutOfSync  Healthy        deployment.apps/guestbook-ui created

用 diff 看漂移明细(Git 期望 replicas 1,集群实际 2):

argocd app diff guestbook

实测输出:


===== apps/Deployment default/guestbook-ui ======
107c107
<   replicas: 2
---
>   replicas: 1

执行同步收敛(集群被拉回 Git 声明的 1 副本):

argocd app sync guestbook

实测输出(节选):

Start:              2026-10-24 01:57:50 +0000 UTC
Finished:           2026-10-24 01:57:50 +0000 UTC
Duration:           0s
Message:            successfully synced (all tasks run)

GROUP  KIND        NAMESPACE  NAME          STATUS  HEALTH   HOOK  MESSAGE
       Service     default    guestbook-ui  Synced  Healthy        service/guestbook-ui unchanged
apps   Deployment  default    guestbook-ui  Synced  Healthy        deployment.apps/guestbook-ui configured

应用回到 Synced / Healthy,漂移闭环完成。

九、常见问题(FAQ)

9.1 Helm 安装报 CRD/ClusterRole 归属校验失败

现象:集群里先用方案 A(manifests)装过再切方案 B 时,helm install 报错(实测):

Error: INSTALLATION FAILED: Unable to continue with install: CustomResourceDefinition "applications.argoproj.io" in namespace "" exists and cannot be imported into the current release: invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "argocd"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "argocd"

清理 manifests 安装残留后仍可能命中 ClusterRole(实测):

Error: INSTALLATION FAILED: Unable to continue with install: ClusterRole "argocd-application-controller" in namespace "" exists and cannot be imported into the current release: invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "argocd"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "argocd"

定位:Helm 要求接管已存在的集群级资源(CRD、ClusterRole)时,资源必须带 Helm 归属标签与注解;manifests 装出来的资源没有。

解决:二选一。

  • 方案一:给三个 CRD 补上归属标签注解(实测输出):
kubectl label crd applications.argoproj.io app.kubernetes.io/managed-by=Helm --overwrite
kubectl annotate crd applications.argoproj.io meta.helm.sh/release-name=argocd meta.helm.sh/release-namespace=argocd --overwrite
kubectl label crd applicationsets.argoproj.io app.kubernetes.io/managed-by=Helm --overwrite
kubectl annotate crd applicationsets.argoproj.io meta.helm.sh/release-name=argocd meta.helm.sh/release-namespace=argocd --overwrite
kubectl label crd appprojects.argoproj.io app.kubernetes.io/managed-by=Helm --overwrite
kubectl annotate crd appprojects.argoproj.io meta.helm.sh/release-name=argocd meta.helm.sh/release-namespace=argocd --overwrite
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io labeled
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io annotated
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io labeled
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io annotated
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io labeled
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io annotated
  • 方案二(干净环境推荐):彻底删除 CRD 与集群角色后重装(实测输出):
kubectl delete crd applications.argoproj.io applicationsets.argoproj.io appprojects.argoproj.io
kubectl delete clusterrole argocd-application-controller argocd-applicationset-controller argocd-server
kubectl delete clusterrolebinding argocd-application-controller argocd-applicationset-controller argocd-server
customresourcedefinition.apiextensions.k8s.io "applications.argoproj.io" deleted
customresourcedefinition.apiextensions.k8s.io "applicationsets.argoproj.io" deleted
customresourcedefinition.apiextensions.k8s.io "appprojects.argoproj.io" deleted
clusterrole.rbac.authorization.k8s.io "argocd-application-controller" deleted
clusterrole.rbac.authorization.k8s.io "argocd-applicationset-controller" deleted
clusterrole.rbac.authorization.k8s.io "argocd-server" deleted
clusterrolebinding.rbac.authorization.k8s.io "argocd-application-controller" deleted
clusterrolebinding.rbac.authorization.k8s.io "argocd-applicationset-controller" deleted
clusterrolebinding.rbac.authorization.k8s.io "argocd-server" deleted

9.2 下载 Chart 包连接被拒/重置

现象:helm install 拉取 chart 归档时实测报过两种网络错误:

Error: INSTALLATION FAILED: Get "https://github.com/argoproj/argo-helm/releases/download/argo-cd-10.11.1/argo-cd-10.11.1.tgz": dial tcp 20.205.243.166:443: connect: connection refused
Error: INSTALLATION FAILED: Get "https://github.com/argoproj/argo-helm/releases/download/argo-cd-10.11.1/argo-cd-10.11.1.tgz": read tcp 10.89.62.2:59472->20.205.243.166:443: read: connection reset by peer

解决:为当前 shell 配置代理后重试(代理地址按实际环境替换;本实验环境为 http://192.168.1.62:7897):

export http_proxy=http://192.168.1.62:7897
export https_proxy=http://192.168.1.62:7897
helm repo update && helm install argocd argo/argo-cd -n argocd --create-namespace

重试后安装成功(NOTES 见 5.2)。

9.3 安装报 NodePort 30080 already allocated

现象:重复安装或残留未清时,helm install 报(实测):

Error: INSTALLATION FAILED: 1 error occurred:
        * Service "argocd-server" is invalid: spec.ports[1].nodePort: Invalid value: 30080: provided port is already allocated

定位:目标 NodePort 被其他 Service(多为上一轮没删干净的 argocd-server)占用。

解决:清理残留命名空间与 Service 后再装。实测先确认 argocd 命名空间是否还在:

kubectl get ns argocd
Error from server (NotFound): namespaces "argocd" not found

若仍有残留 Service,删除后重试安装即可成功(成功输出见 5.2)。

9.4 登录报 Invalid username or password 或 token signature is invalid

现象:重装后沿用旧凭据登录,实测报:

{"level":"fatal","msg":"rpc error: code = Unauthenticated desc = Invalid username or password","time":"2026-10-24T04:28:24Z"}
{"level":"fatal","msg":"rpc error: code = Unauthenticated desc = invalid session: token signature is invalid: signature is invalid","time":"2026-10-24T04:28:24Z"}

定位:前者是密码与服务端 admin.password 哈希不匹配;后者是 CLI 本地缓存的旧 token 签名密钥(server.secretkey 随重装轮换)失效。

解决:重新获取有效凭据——未自设密码的安装用 argocd admin initial-password -n argocd 取初始密码(本环境自设后该 secret 不存在,见 7.1 实测);随后重新 argocd login 刷新本地会话,再执行 argocd account update-password 统一口令。

9.5 argocd admin 子命令报 no configuration has been provided

现象:argocd admin settings rbac can ... 等直连 Kubernetes 的管理命令实测报:

{"level":"fatal","msg":"could not create k8s client: invalid configuration: no configuration has been provided, try setting KUBERNETES_MASTER environment variable","time":"2026-10-24T11:37:30Z"}

定位:argocd admin 走 kubectl 的 kubeconfig 加载规则,k3s 的 kubeconfig 在 /etc/rancher/k3s/k3s.yaml,不在默认搜索路径。

解决:显式导出后重试:

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml

9.6 git daemon 连接报 repository not found

现象:注册不存在或未导出的仓库时,repo add 的连通性预检实测报:

{"level":"fatal","msg":"rpc error: code = Unknown desc = error testing repository connectivity: unable to ls-remote HEAD on repository: failed to list refs: repository not found","time":"2026-10-24T11:43:42Z"}

定位:git daemon 按请求路径在 --base-path 下找同名裸仓库;路径拼错、仓库未 init --bare 或 daemon 未带 --export-all 都会报 not found。

解决:核对 /srv/git/<仓库名>.git 存在且 git daemon 进程在跑(ps 命令见 8.1),再重新 argocd repo add。

十、卸载与清理

10.1 卸载 Helm 安装的 Argo CD

helm uninstall argocd -n argocd
kubectl delete ns argocd

实测输出(三个 CRD 因带资源策略被保留,属正常现象):

These resources were kept due to the resource policy:
[CustomResourceDefinition] applications.argoproj.io
[CustomResourceDefinition] applicationsets.argoproj.io
[CustomResourceDefinition] appprojects.argoproj.io

release "argocd" uninstalled
namespace "argocd" deleted

残留 CRD 如确认无其他组件使用,可按 9.1 的删除命令清理。

10.2 卸载 manifests 安装的 Argo CD

kubectl delete -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v3.5.6/manifests/install.yaml

实测输出(清单内资源逐个 deleted,此处为首尾节选):

namespace "argocd" deleted

10.3 停止内网 Git 服务与卸载 k3s

停止 git daemon(进程级清理,实测停止后 grep 计数为 0):

pkill -f '[g]it-daemon'
ps aux | grep '[g]it-daemon' | wc -l

实测输出:

0

k3s 提供一键卸载脚本(4.1 安装时已生成 /usr/local/bin/k3s-uninstall.sh,会同时清理 systemd 单元、二进制与数据目录):

/usr/local/bin/k3s-uninstall.sh

⚠️ 注意:该脚本会删除 k3s 全部数据(含集群内所有工作负载),执行前确认无其他业务共用该集群。

十一、参考链接