📎 配套脚本附件正文未内嵌 · 共 15 个 · 点开可在线查看
  • _check_install.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.6 KB
  • _events.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.6 KB
  • _fix_appendices.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 1.9 KB
  • _fix_kubectl_probe.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.9 KB
  • _kill_stuck.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.6 KB
  • _pods.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.4 KB
  • _probe_207.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.7 KB
  • _probe_207_k8s.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.6 KB
  • _probe_dl.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.7 KB
  • _reboot_check.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.9 KB
  • _run_mirror_fix.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.7 KB
  • _status.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.5 KB
  • _verify_urls.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 0.7 KB
  • argocd_01_207部署演示.pyPythonscripts_cursor/基础设施_Argo_CD_原理与部署教程 · 3.5 KB
  • deployment.yamlYAMLpatches_cursor/基础设施_Argo_CD_原理与部署教程/manifests/demo-nginx · 0.8 KB
📂 查看全部 761 个脚本附件 →
⚠️ 脚本内含明文凭据(与本页正文一致),请勿在公网环境直接运行。
基础设施 · GitOps

Argo CD 原理与部署教程

第一次恶补:GitOps 原理、Application/Sync/Health、安装跟读、日常发版与排障;不装机。

基础设施 · Argo CD 原理与部署教程

定位:第一次接触 Argo CD 的恶补专题——讲清 GitOps 原理、核心对象、安装部署、日常工作流、与 GitLab/Harbor 的关系。

207 实战演示:本机可跑 K3s 单点 + Docker GitLab + Argo CD + demo-nginx(见 §6B);与生产 Dify :80 不冲突。

边界:完整企业级多节点 K8s / Harbor / GPU Operator 仍不在本环境装;§6 纸面跟读 + §6B 为 207 可动手案例。

关联:K8s GPU 理论总览 · 单私有化 GPU 集群完整案例 · 作业17 模型路由当发布

清单 / 脚本:patches_cursor/基础设施_Argo_CD_原理与部署教程/ · scripts_cursor/基础设施_Argo_CD_原理与部署教程/

HTML:docs/html_cursor/基础设施_Argo_CD_原理与部署教程/基础设施_Argo_CD_原理与部署教程_cursor.html


目录

  1. 先建立直觉:Argo CD 解决什么
  2. GitOps 与 Argo CD 原理
  3. 核心概念词典
  4. 架构与组件
  5. 一次同步到底发生了什么
  6. 部署教程(实验集群跟读)

6B. 207 实战:K3s + Docker GitLab + Argo CD

  1. 日常工作方式
  2. 与 GitLab · Harbor · GPU 推理的关系
  3. 和本环境「改 LiteLLM config」的对照
  4. 常见坑与排障
  5. 学习路径与自测
  6. 完整配置附录

1. 先建立直觉:Argo CD 解决什么

你可能已经会 kubectl apply -f xxx.yaml,也会 SSH 到 207 改配置再 systemctl restart。问题在于:

老做法痛点
人肉 kubectl apply谁改的、改成啥、集群现在和文件是否一致——说不清
只改集群、不改 Git漂移;换个人接手就懵
CI 里 kubectl apply需要把 kubeconfig 交给 CI,权限难管;失败回滚不直观

Argo CD 做的事一句话: 以 Git 仓库里的 YAML/Helm/Kustomize 为「唯一真相」,持续把 K8s 集群状态对齐到 Git。

text
        ┌─────────────┐
        │   Git 仓库   │  ← 真相(谁 Merge 了啥,有记录)
        └──────┬──────┘
               │  Argo CD 轮询 / Webhook
               ▼
        ┌─────────────┐
        │  K8s 集群    │  ← 实际运行的 Deployment / Service …
        └─────────────┘

它不是:构建镜像(那是 CI + Harbor)、跑单元测试、替代 Kubernetes 本身。 它是:发布与对齐的控制器——「Git 里写了 2 副本,集群就必须是 2 副本」。


2. GitOps 与 Argo CD 原理

2.1 GitOps 三句话

  1. 声明式:描述「期望状态」(YAML),不是写一串 imperative 命令。
  2. Git 为单一事实来源(SSOT):生产长什么样,以 Git 某分支/路径为准。
  3. 自动对齐:控制器发现 Git 与集群不一致 → 执行 Sync(或告警等人批准)。

2.2 Pull vs Push

模式谁主动典型
PushCI 拿着 kubeconfig 往集群推kubectl apply in Jenkins
Pull(GitOps)集群里的 Argo CD 从 Git 拉期望状态Argo CD Application

Pull 的好处:集群凭证不必散落到每个 CI;权限集中在 Argo;UI 上能看到 Sync 状态与历史。

2.3 和 CI/CD 的分工

flowchart LR
  Dev[开发/运维]
  GL[GitLab 代码仓]
  CI[GitLab CI]
  HB[Harbor 镜像仓]
  MF[GitLab manifests 仓]
  AR[Argo CD]
  K8S[K8s]

  Dev -->|改业务代码| GL
  GL --> CI
  CI -->|docker build push| HB
  CI -->|更新 image tag 提交| MF
  AR -->|读| MF
  AR -->|Sync| K8S
  K8S -->|拉镜像| HB

口诀(与姊妹篇一致):

text
镜像进 Harbor · 声明进 Git · 真相以 Git 为准 · Argo 负责落地

3. 核心概念词典

第一次接触,先把这些词背熟:

概念是什么你要记住的
Application一条「Git 路径 → 某个集群某个 NS」的同步规则最常用的 CRD;一个应用/一套清单通常一个 Application
AppProjectApplication 的「权限边界」:允许哪些 Git 仓、哪些集群、哪些资源类型生产别全用 default
SourceGit 地址、targetRevision(分支/tag/commit)、path 或 Helm 参数改发版 = 改 Git 这里的内容或 revision
Destination同步到哪个集群(server)哪个命名空间多集群时靠不同 Application 或 ApplicationSet
Sync执行一次对齐:把 Git 渲染结果 apply 到集群可手动点 Sync,也可 automated
Sync StatusSynced / OutOfSyncOutOfSync = Git 和集群不一致
Health工作负载是否健康(Deployment 是否 Ready 等)Healthy ≠ Synced;可能已同步但 Pod 起不来
Revision当前同步的 Git commit SHA回滚 = 指回旧 revision 再 Sync
Prune同步时删除 Git 里已不存在的资源开 automated prune 要小心误删
Self-Heal集群被人 kubectl edit 改了 → 自动改回 Git生产常开;调试时可关
DiffUI/CLI 对比 Git vs Live发版前必看

3.1 Application 最小 mental model

yaml
# 逻辑上等价于:
# 「把 git@xxx/manifests/overlays/prod 的内容,应用到 cluster-A 的 gpu-infer 命名空间」
spec:
  source:      # 从哪读
    repoURL: ...
    path: ...
  destination: # 写到哪
    server: ...
    namespace: ...
  syncPolicy:  # 怎么同步(手动/自动、是否自愈)

完整样例见 附录 C · 03-application-demo.yaml。


4. 架构与组件

安装后(官方 manifest / Helm)在 argocd 命名空间大致有:

组件作用
argocd-serverAPI + Web UI
argocd-repo-server拉 Git、渲染 Helm/Kustomize,生成 manifests
argocd-application-controller对比 Git vs 集群,执行 Sync
argocd-dex(可选)SSO / OIDC
argocd-redis缓存与协调
text
  用户 / CLI / CI
        │
        ▼
  argocd-server (UI :443)
        │
        ├─► repo-server ──► GitLab / 公网 Git
        │
        └─► application-controller ──► Kubernetes API

两种常见部署形态:

形态说明
装在业务集群里本教程默认;简单,适合单集群实验
独立管理集群一个 Argo 管多个业务集群;中大公司更常见

5. 一次同步到底发生了什么

以「Git 里把 Deployment 副本从 1 改成 2」为例:

  1. 开发 Merge MR → main 上 commit abc123 含 replicas: 2。
  2. Argo CD 每 3 分钟轮询(或 GitLab Webhook 触发)发现 targetRevision: main 有新 commit。
  3. repo-server checkout 该 commit,若 path 是 Kustomize/Helm 则渲染成纯 YAML。
  4. application-controller 对比 Desired(Git)与 Live(集群)。
  5. 状态变为 OutOfSync;若 automated.selfHeal 或人工点 Sync:
  6. 对 Deployment 执行 apply/update → 集群滚动扩容到 2 副本。
  7. Deployment Ready → Application Health: Healthy,Sync: Synced,记录 Revision: abc123。
text
Git replicas:2   ──compare──►  Live replicas:1   → OutOfSync
       │                                              │
       └──────────────── Sync ────────────────────────┘
                              Live replicas:2 → Synced

重要:Argo CD 不会帮你构建镜像;它只会把 YAML 里的 image: harbor.../vllm:tag 原样 apply。镜像必须已在 Harbor,且节点能拉取。


6. 部署教程(实验集群跟读)

以下在有 kubectl 的实验集群执行;勿在 207/116 生产乱装。

6.1 前置

6.2 安装 Argo CD(官方稳定 manifest)

bash
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# 等待就绪
kubectl -n argocd get pods -w
# 期望 argocd-server / application-controller / repo-server 等 Running

高可用或生产参数:改用 官方 Helm chart 并配置 values.yaml(资源、Ingress、SSO)。

6.3 首次登录

bash
# 取初始 admin 密码(仅首次)
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d && echo

# 本机临时访问 UI(另开终端)
kubectl -n argocd port-forward svc/argocd-server 8443:443
# 浏览器 https://localhost:8443  用户 admin

内网长期访问:Ingress 见 附录 E;生产务必 HTTPS + 改密 + SSO。

6.4 安装 CLI(可选但推荐)

bash
# Linux 示例
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x argocd && sudo mv argocd /usr/local/bin/

argocd login localhost:8443 --username admin --password '<上一步密码>' --insecure
argocd version

6.5 把 Git 仓库交给 Argo CD

方式 A — UI:Settings → Repositories → Connect repo → HTTPS + deploy token / SSH key。

方式 B — CLI:

bash
argocd repo add https://gitlab.example.local/ai-platform/gpu-infer-manifests.git \
  --username gitlab-ci-token --password '<token>'

仓库需包含 Kubernetes 清单(见附录 B 示例目录结构)。

建议 Git 布局:

text
gpu-infer-manifests/
  base/
    deployment.yaml
    service.yaml
    kustomization.yaml
  overlays/
    lab/
      kustomization.yaml   # 实验:副本 1
    prod/
      kustomization.yaml   # 生产:副本 2、image tag

6.6 创建第一个 Application

bash
kubectl apply -f patches_cursor/基础设施_Argo_CD_原理与部署教程/03-application-demo.yaml

# 或 CLI
argocd app create demo-gpu-infer \
  --repo https://gitlab.example.local/ai-platform/gpu-infer-manifests.git \
  --path overlays/lab \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace gpu-infer \
  --sync-policy automated --self-heal

argocd app get demo-gpu-infer
argocd app sync demo-gpu-infer
argocd app wait demo-gpu-infer --health

验收:

bash
kubectl -n gpu-infer get deploy,po
argocd app list
# SYNC STATUS = Synced, HEALTH = Healthy

6.7 故意制造 OutOfSync(理解 Self-Heal)

bash
kubectl -n gpu-infer scale deploy demo-nginx --replicas=3
argocd app get demo-gpu-infer
# 应显示 OutOfSync;若 selfHeal=true,稍等会回到 Git 中的副本数

这一步能帮你建立「集群被人改了,Argo 会拉回去」的肌肉记忆。


6B. 207 实战:K3s + Docker GitLab + Argo CD

目标:在 192.168.110.207 上跑通「改 Git → Argo Sync → 集群变了」的最小闭环。

组件:单点 K3s(关 Traefik,不抢 Dify :80)+ Docker GitLab CE :8929 + Argo CD NodePort :30080 + demo-nginx :30088。

6B.1 拓扑

text
浏览器
  ├─ GitLab UI     http://192.168.110.207:8929     (Docker)
  ├─ Argo CD UI    http://192.168.110.207:30080    (K3s NodePort)
  └─ demo-nginx    http://192.168.110.207:30088    (K3s NodePort)

GitLab 仓 root/argocd-manifests
        │  path: demo-nginx/
        ▼
Argo CD Application demo-nginx  ──Sync──►  NS argocd-demo

6B.2 一键部署(Windows)

bash
# 先同步脚本与 patches 到 207
python scripts_cursor/00_部署_workbuddy到207.py

# 安装演示环境(首次含拉 GitLab 镜像,可能 15~30 分钟)
python scripts_cursor/基础设施_Argo_CD_原理与部署教程/argocd_01_207部署演示.py

207 上也可:

bash
bash /opt/workbuddy/patches_cursor/基础设施_Argo_CD_原理与部署教程/install_207_demo.sh

安装日志:/opt/argocd-demo/install.log 访问说明:/opt/argocd-demo/访问说明.txt

6B.3 账号与入口(默认)

入口URL / 命令账号
GitLabhttp://192.168.110.207:8929root / ArgoDemo207!
清单仓http://192.168.110.207:8929/root/argocd-manifests同上
Argo CDhttp://192.168.110.207:30080admin / 见 访问说明.txt(初始密码)
demo 页http://192.168.110.207:30088无登录,应看到 nginx 欢迎页
kubectl见下节 §6B.3.1请用 k3s kubectl,不要直接敲裸 kubectl

6B.3.1 k3s 用法:为何 kubectl get nodes 会报错

207 上装 k3s 前,系统里往往已有旧的 /usr/bin/kubectl。安装脚本会跳过覆盖:

text
Skipping /usr/local/bin/kubectl symlink to k3s, command exists in PATH at /usr/bin/kubectl

因此你直接执行:

bash
kubectl get nodes

常见报错:

text
couldn't get current server API group list: the server could not find the requested resource
Error from server (NotFound): the server could not find the requested resource

原因:旧 kubectl / 错误 kubeconfig,不是 k3s 挂了。集群本身用下面命令验证:

bash
# 推荐:永远用 k3s 自带客户端 + 官方 kubeconfig
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
k3s kubectl get nodes
k3s kubectl get pods -A

和本演示相关:

bash
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
k3s kubectl -n argocd get applications
k3s kubectl -n argocd-demo get deploy,po,svc

若仍想敲短命令 kubectl:

bash
# 写入登录环境(推荐)
echo 'export KUBECONFIG=/etc/rancher/k3s/k3s.yaml' >> ~/.bashrc
echo "alias kubectl='k3s kubectl'" >> ~/.bashrc
source ~/.bashrc

# 验证
kubectl get nodes

或(更狠,慎用):把旧二进制挪开再链到 k3s:

bash
mv /usr/bin/kubectl /usr/bin/kubectl.bak.old
ln -sfn /usr/local/bin/k3s /usr/local/bin/kubectl
# 确认 which kubectl → /usr/local/bin/kubectl

服务状态:

bash
systemctl status k3s
# 配置文件:/etc/rancher/k3s/k3s.yaml
# 卸载(慎用):/usr/local/bin/k3s-uninstall.sh

6B.4 怎么玩(推荐顺序)

玩法 A — 改 Git,看 Argo 自动对齐

  1. 打开 GitLab → root/argocd-manifests → demo-nginx/deployment.yaml
  2. 把 replicas: 1 改成 replicas: 2 → Commit 到 main
  3. 打开 Argo CD → Application demo-nginx:先 OutOfSync,片刻变 Synced(automated)
  4. 207 上验证:
bash
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
k3s kubectl -n argocd-demo get deploy,po
# Ready 应为 2/2

玩法 B — 人肉改集群,看 Self-Heal

bash
k3s kubectl -n argocd-demo scale deploy/demo-nginx --replicas=5
k3s kubectl -n argocd-demo get deploy -w
# 稍等:Self-Heal 会把副本拉回 Git 里的数字

玩法 C — UI Diff / Sync

Argo → demo-nginx → DIFF 看 Git vs Live;关掉 automated 时可点 SYNC 手动对齐。

6B.5 关键文件

路径作用
scripts_cursor/基础设施_Argo_CD_原理与部署教程/argocd_01_207部署演示.pyWindows 触发安装
patches_cursor/…/install_207_demo.sh207 安装主脚本(全文见附录 F)
patches_cursor/…/manifests/demo-nginx/deployment.yaml推入 GitLab 的工作负载(附录 G)
patches_cursor/…/manifests/argocd-application-demo-nginx.yamlArgo Application(附录 H)

6B.6 资源与注意

项说明
内存GitLab CE 较吃内存(约 3~4G+);207 约 31G,与现有 Dify/Langfuse/Higress 并存需观察 free -h
端口8929 GitLab · 2224 GitLab SSH · 30080 Argo · 30088 demo · 不占用 :80
卸载(慎用)docker rm -f gitlab-argocd-demo;/usr/local/bin/k3s-uninstall.sh;rm -rf /opt/argocd-demo

7. 日常工作方式

7.1 标准发版流(推荐)

步骤谁做什么
1开发改代码 → MR
2CIbuild 镜像 → push Harbor tag:20260901
3开发/运维改 manifests 仓里 image.tag 或 kustomize edit set image → MR
4Reviewer看 Diff(Git MR + Argo UI Diff)
5Merge合入 main
6Argo自动或手动 Sync → 滚动更新
7值班看 Health;异常则 Rollback 到上一 Git revision

7.2 常用 CLI

bash
argocd app list
argocd app get <app>
argocd app diff <app>
argocd app sync <app>
argocd app history <app>
argocd app rollback <app> <id>
kubectl -n argocd get applications

7.3 什么时候手动 Sync / 什么时候 automated

场景建议
实验 / labautomated: { prune: false, selfHeal: true }
生产 GPU 推理常用手动 Sync 或 automated 但不 prune;重大变更走 MR + 人工点 Sync
多集群同一 manifests 不同 overlay;每集群一个 Application

7.4 回滚怎么做


8. 与 GitLab · Harbor · GPU 推理的关系

在本仓库「单私有化 GPU 集群」案例里,分工是:

组件负责
GitLab存 gpu-infer-manifests(Deployment、Service、Ingress、副本数、image 名)
Harbor存 vllm-openai:v0.8.5 等镜像
Argo CD把 manifests 同步到 gpu-infer NS → 调度 nvidia.com/gpu
LiteLLM(207)仍可能在集群外;只改 upstream 指向 Ingress(见完整案例 §7)

Argo 不管 LiteLLM 的 config.yaml(除非你把 LiteLLM 也容器化进集群并纳入 Git——中大公司常见,见姊妹讨论)。


9. 和本环境「改 LiteLLM config」的对照

维度本环境作业17(207 LiteLLM)Argo CD(K8s manifests)
真相来源patches_cursor/LiteLLM部署/config.yamlGit manifests 仓
发布动作拷贝 + systemctl restart litellmSync Application
回滚git checkout 旧 config + restartGit revert 或 argocd app rollback
漂移检测无自动;靠纪律OutOfSync / Self-heal
适用对象网关配置、路由Deployment、Service、Ingress、ConfigMap…

演进路径:先把 LiteLLM 路由 Git 化 + Runbook(你们已在做)→ 实验集群练 Argo → GPU 工作负载进 Git → 再考虑 LiteLLM 进集群。


10. 常见坑与排障

现象原因处理
Application Unknown / repo 连接失败Git 凭证、防火墙、自签证书argocd repo list;为 repo-server 配 CA 或 insecure(仅实验)
OutOfSync 一直存在集群里有默认 mutation(如 sidecar 注入)导致 Diff 永远不同ignoreDifferences;或把 mutating 写进 Git
Sync 成功但 Degraded镜像拉不到、GPU 不够、探针失败kubectl describe po;与 GPU Operator 专题一起查
开了 prune 误删资源Git 里删了 YAML → Sync 删集群对象生产慎用 prune;用 Resource finalizer 前先理解
人肉 kubectl edit 后「改不回去」没开 selfHeal 或 sync 失败开 selfHeal 或手动 Sync
和 CI kubectl apply 混用两套真相打架约定:生产业务 NS 只允许 Argo 写
bash
# 排障三板斧
argocd app get <app> --refresh
argocd app diff <app>
kubectl -n argocd logs deploy/argocd-application-controller --tail=100

11. 学习路径与自测

11.1 建议阅读顺序

  1. 本文(概念 + 装一个 demo Application)
  2. K8s GPU 理论 §6(Argo 在整条链的位置)
  3. 单私有化 GPU 集群完整案例 §6(真实 vLLM Application)
  4. 官方:Argo CD Getting Started

11.2 自测题

  1. GitOps 的「单一事实来源」是什么?Argo CD 是 Push 还是 Pull?
  2. Application 的 source 和 destination 各表示什么?
  3. Synced 和 Healthy 有什么区别?
  4. 为什么改镜像 tag 要提交 Git,而不是只 kubectl set image?
  5. 本环境 LiteLLM 路由发布,对应 Argo 里的哪一步?

12. 完整配置附录

下列正文与 patches_cursor/基础设施_Argo_CD_原理与部署教程/ 下同名文件全文一致。

附录 A · 01-namespace.yaml

路径:patches_cursor/基础设施_Argo_CD_原理与部署教程/01-namespace.yaml

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: argocd
  labels:
  # 生产可单独拆管理集群;本教程装在被管集群内 argocd NS
    app.kubernetes.io/part-of: argocd

附录 B · 02-git-manifests-demo.yaml

路径:patches_cursor/基础设施_Argo_CD_原理与部署教程/02-git-manifests-demo.yaml

yaml
# Git 仓里应存的清单示例(路径:gpu-infer-manifests/base/deployment.yaml)
# Argo CD 只读 Git,不在这里 build 镜像
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-nginx
  namespace: gpu-infer
  labels:
    app: demo-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo-nginx
  template:
    metadata:
      labels:
        app: demo-nginx
    spec:
      containers:
        - name: nginx
          image: harbor.example.local/library/nginx:1.27-alpine
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: demo-nginx
  namespace: gpu-infer
spec:
  selector:
    app: demo-nginx
  ports:
    - port: 80
      targetPort: 80

附录 C · 03-application-demo.yaml

路径:patches_cursor/基础设施_Argo_CD_原理与部署教程/03-application-demo.yaml

yaml
# 最小 Application:把 Git 某路径同步到本集群 gpu-infer 命名空间
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: demo-gpu-infer
  namespace: argocd
  # 建议加 finalizer,删 Application 时可级联清资源(生产慎用 prune)
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://gitlab.example.local/ai-platform/gpu-infer-manifests.git
    targetRevision: main
    path: overlays/lab
    # Helm 时改用:
    # helm:
    #   valueFiles:
    #     - values-lab.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: gpu-infer
  syncPolicy:
    automated:
      prune: false
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ApplyOutOfSyncOnly=true

附录 D · 04-appproject-gpu-infer.yaml

路径:patches_cursor/基础设施_Argo_CD_原理与部署教程/04-appproject-gpu-infer.yaml

yaml
# 生产建议:用 AppProject 限制「能同步哪些 Git 仓 / 哪些集群 / 哪些 NS」
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: gpu-infer
  namespace: argocd
spec:
  description: GPU 推理工作负载 GitOps 项目
  sourceRepos:
    - https://gitlab.example.local/ai-platform/*
    - https://gitlab.example.local/ai-platform/gpu-infer-manifests.git
  destinations:
    - namespace: gpu-infer
      server: https://kubernetes.default.svc
    - namespace: gpu-infer-*
      server: https://kubernetes.default.svc
  clusterResourceWhitelist:
    - group: ""
      kind: Namespace
  namespaceResourceWhitelist:
    - group: apps
      kind: Deployment
    - group: ""
      kind: Service
    - group: networking.k8s.io
      kind: Ingress

附录 E · 05-ingress-argocd-ui.yaml

路径:patches_cursor/基础设施_Argo_CD_原理与部署教程/05-ingress-argocd-ui.yaml

yaml
# 可选:内网暴露 Argo CD UI(生产务必 HTTPS + SSO)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server
  namespace: argocd
  annotations:
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
  ingressClassName: nginx
  rules:
    - host: argocd.gpu-k8s.example.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: argocd-server
                port:
                  number: 443

附录 F · install_207_demo.sh(207 一键安装)

路径:patches_cursor/基础设施_Argo_CD_原理与部署教程/install_207_demo.sh

bash
#!/bin/bash
# 207 单点 K3s + Docker GitLab + Argo CD 演示(可重复执行,尽量幂等)
set -euo pipefail

DEMO_ROOT=/opt/argocd-demo
GITLAB_NAME=gitlab-argocd-demo
GITLAB_URL=http://192.168.110.207:8929
GITLAB_ROOT_PASSWORD="${GITLAB_ROOT_PASSWORD:-ArgoDemo207!}"
MANIFESTS_REPO=argocd-manifests
KUBECONFIG=/etc/rancher/k3s/k3s.yaml
export KUBECONFIG
KC="k3s kubectl"

log() { echo "[$(date '+%H:%M:%S')] $*"; }

install_k3s() {
  if command -v k3s >/dev/null 2>&1 && [ -f "$KUBECONFIG" ]; then
    log "k3s 已存在,跳过安装"
    $KC get nodes || true
    return
  fi
  log "安装 k3s(国内镜像;禁用 traefik,避免占用 80 与 Dify 冲突)"
  curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
    INSTALL_K3S_MIRROR=cn \
    INSTALL_K3S_EXEC="server --disable traefik --write-kubeconfig-mode 644" sh -
  sleep 10
  $KC wait --for=condition=Ready node --all --timeout=180s
  $KC get nodes
}

start_gitlab() {
  mkdir -p "$DEMO_ROOT/gitlab/config" "$DEMO_ROOT/gitlab/logs" "$DEMO_ROOT/gitlab/data"
  if docker ps -a --format '{{.Names}}' | grep -qx "$GITLAB_NAME"; then
    if ! docker ps --format '{{.Names}}' | grep -qx "$GITLAB_NAME"; then
      log "启动已有 GitLab 容器"
      docker start "$GITLAB_NAME"
    else
      log "GitLab 容器已在运行"
    fi
  else
    log "拉取并启动 GitLab CE(优先国内镜像代理)"
    local IMG="gitlab/gitlab-ce:16.11.10-ce.0"
    local MIRROR_IMG="docker.m.daocloud.io/gitlab/gitlab-ce:16.11.10-ce.0"
    if ! docker image inspect "$IMG" >/dev/null 2>&1; then
      if docker pull "$MIRROR_IMG"; then
        docker tag "$MIRROR_IMG" "$IMG"
      else
        log "国内镜像失败,再试 Docker Hub…"
        docker pull "$IMG"
      fi
    fi
    docker run -d --name "$GITLAB_NAME" \
      --hostname 192.168.110.207 \
      --restart unless-stopped \
      -p 8929:8929 -p 2224:22 \
      -v "$DEMO_ROOT/gitlab/config:/etc/gitlab" \
      -v "$DEMO_ROOT/gitlab/logs:/var/log/gitlab" \
      -v "$DEMO_ROOT/gitlab/data:/var/opt/gitlab" \
      --shm-size 256m \
      -e GITLAB_ROOT_PASSWORD="$GITLAB_ROOT_PASSWORD" \
      -e GITLAB_OMNIBUS_CONFIG="external_url '${GITLAB_URL}'; nginx['listen_port'] = 8929; gitlab_rails['gitlab_shell_ssh_port'] = 2224;" \
      "$IMG"
  fi
}

wait_gitlab() {
  log "等待 GitLab HTTP 就绪(最长 25 分钟)"
  for i in $(seq 1 150); do
    if curl -sf -o /dev/null "$GITLAB_URL/users/sign_in" 2>/dev/null; then
      log "GitLab Web 已响应 (${i}*10s)"
      # 再等 rails 完全可用
      sleep 30
      return 0
    fi
    if (( i % 6 == 0 )); then
      log "仍在等待 GitLab… ${i}*10s  docker: $(docker inspect -f '{{.State.Health.Status}}' "$GITLAB_NAME" 2>/dev/null || docker inspect -f '{{.State.Status}}' "$GITLAB_NAME")"
    fi
    sleep 10
  done
  log "ERROR: GitLab 超时未就绪"; docker logs "$GITLAB_NAME" --tail 40; exit 1
}

ensure_gitlab_project() {
  log "创建 GitLab 公开项目 root/${MANIFESTS_REPO}"
  docker exec "$GITLAB_NAME" bash -lc "gitlab-rails runner \"
u = User.find_by_username('root') || User.find_by(username: 'root')
raise 'no root user' unless u
p = Project.find_by_full_path('root/${MANIFESTS_REPO}')
unless p
  p = Projects::CreateService.new(u, {
    name: '${MANIFESTS_REPO}',
    path: '${MANIFESTS_REPO}',
    namespace_id: u.namespace.id,
    visibility_level: Gitlab::VisibilityLevel::PUBLIC
  }).execute
  raise (p.respond_to?(:errors) ? p.errors.full_messages.join(', ') : p.inspect) unless p.is_a?(Project) && p.persisted?
end
puts 'project_ok id=' + p.id.to_s
\"" || log "WARN: rails runner 创建项目失败,若仓库已存在可忽略"
}

push_manifests() {
  command -v git >/dev/null || apt-get install -y git
  local src="$DEMO_ROOT/manifests-src"
  local work="$DEMO_ROOT/manifests-git"
  rm -rf "$work"
  mkdir -p "$work"
  # 只把 demo-nginx 清单放进 Git(Application YAML 由 kubectl 单独 apply)
  cp -a "$src/demo-nginx" "$work/"
  cd "$work"
  git init -b main
  git config user.email "argocd-demo@207.local"
  git config user.name "argocd-demo"
  git add -A
  git commit -m "argocd demo manifests $(date '+%Y%m%d_%H%M%S')" || true
  git remote add origin "http://root:${GITLAB_ROOT_PASSWORD}@192.168.110.207:8929/root/${MANIFESTS_REPO}.git"
  # 首次 push 可能遇到空仓延迟,重试几次
  for i in 1 2 3 4 5; do
    if git push -u origin main --force; then
      log "manifests 已 push 到 GitLab"
      return 0
    fi
    log "push 失败,重试 $i …"
    sleep 10
  done
  exit 1
}

install_argocd() {
  log "安装 Argo CD"
  $KC create namespace argocd --dry-run=client -o yaml | $KC apply -f -
  local ARGO_YAML="$DEMO_ROOT/argocd-install.yaml"
  if [ ! -s "$ARGO_YAML" ]; then
    log "下载 Argo CD install.yaml(优先 ghproxy)"
    curl -sfL -o "$ARGO_YAML" \
      https://ghproxy.net/https://raw.githubusercontent.com/argoproj/argo-cd/v2.12.3/manifests/install.yaml \
      || curl -sfL -o "$ARGO_YAML" \
      https://cdn.jsdelivr.net/gh/argoproj/argo-cd@v2.12.3/manifests/install.yaml \
      || curl -sfL -o "$ARGO_YAML" \
      https://raw.githubusercontent.com/argoproj/argo-cd/v2.12.3/manifests/install.yaml
  fi
  $KC apply -n argocd -f "$ARGO_YAML"
  $KC wait --for=condition=available deployment/argocd-server -n argocd --timeout=900s
  $KC wait --for=condition=available deployment/argocd-repo-server -n argocd --timeout=900s
  $KC wait --for=condition=available statefulset/argocd-application-controller -n argocd --timeout=900s 2>/dev/null \
    || $KC wait --for=condition=available deployment/argocd-application-controller -n argocd --timeout=900s 2>/dev/null \
    || true
  $KC patch configmap argocd-cmd-params-cm -n argocd --type merge -p '{"data":{"server.insecure":"true"}}' 2>/dev/null || \
    $KC create configmap argocd-cmd-params-cm -n argocd --from-literal=server.insecure=true --dry-run=client -o yaml | $KC apply -f -
  $KC patch svc argocd-server -n argocd -p '{"spec":{"type":"NodePort","ports":[{"name":"http","port":80,"protocol":"TCP","targetPort":8080,"nodePort":30080},{"name":"https","port":443,"protocol":"TCP","targetPort":8080,"nodePort":30443}]}}'
  $KC rollout restart deployment/argocd-server -n argocd
  $KC wait --for=condition=available deployment/argocd-server -n argocd --timeout=300s
}

configure_argocd_repo_and_app() {
  log "注册 GitLab 仓库并创建 Application"
  $KC -n argocd delete secret gitlab-argocd-manifests --ignore-not-found
  $KC apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: gitlab-argocd-manifests
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
stringData:
  type: git
  url: ${GITLAB_URL}/root/${MANIFESTS_REPO}.git
  username: root
  password: ${GITLAB_ROOT_PASSWORD}
  insecure: "true"
EOF
  $KC apply -f "$DEMO_ROOT/argocd-application-demo-nginx.yaml"
  sleep 20
  $KC -n argocd get applications -o wide
  $KC -n argocd-demo get deploy,po,svc 2>/dev/null || true
}

print_summary() {
  local admin_pw
  admin_pw=$($KC -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' 2>/dev/null | base64 -d || echo "(已改过密码)")
  cat > "$DEMO_ROOT/访问说明.txt" <<EOF
=== 207 Argo CD + GitLab 演示 ===
GitLab:    ${GITLAB_URL}  用户 root  密码 ${GITLAB_ROOT_PASSWORD}
           项目: ${GITLAB_URL}/root/${MANIFESTS_REPO}
Argo CD:   http://192.168.110.207:30080  用户 admin  初始密码 ${admin_pw}
Demo 应用: http://192.168.110.207:30088  (demo-nginx NodePort)
kubeconfig: export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
玩法:
  1) 打开 GitLab 改 demo-nginx/deployment.yaml 的 replicas(如 1→2)-> Commit
  2) Argo UI 看 OutOfSync -> Sync(或等 automated selfHeal)
  3) k3s kubectl -n argocd-demo get po
  4) 人肉改副本: k3s kubectl -n argocd-demo scale deploy/demo-nginx --replicas=5
     稍等看 Self-Heal 拉回 Git 中的副本数
EOF
  cat "$DEMO_ROOT/访问说明.txt"
}

main() {
  install_k3s
  start_gitlab
  wait_gitlab
  ensure_gitlab_project
  push_manifests
  install_argocd
  configure_argocd_repo_and_app
  print_summary
  log "DONE"
}

main "$@"

附录 G · demo-nginx Deployment(推入 GitLab)

路径:patches_cursor/基础设施_Argo_CD_原理与部署教程/manifests/demo-nginx/deployment.yaml

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-nginx
  labels:
    app: demo-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo-nginx
  template:
    metadata:
      labels:
        app: demo-nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.27-alpine
          ports:
            - containerPort: 80
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 3
            periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: demo-nginx
  labels:
    app: demo-nginx
spec:
  type: NodePort
  selector:
    app: demo-nginx
  ports:
    - name: http
      port: 80
      targetPort: 80
      nodePort: 30088

附录 H · Argo Application(207 演示)

路径:patches_cursor/基础设施_Argo_CD_原理与部署教程/manifests/argocd-application-demo-nginx.yaml

yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: demo-nginx
  namespace: argocd
spec:
  project: default
  source:
    repoURL: http://192.168.110.207:8929/root/argocd-manifests.git
    targetRevision: main
    path: demo-nginx
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd-demo
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

修订记录

日期说明
2026-09-01首版:Argo CD 原理、部署跟读、日常工作流、与 GitLab/Harbor/本环境对照
2026-09-02新增 §6B:207 实战 K3s + Docker GitLab + Argo CD;附录 F/G/H 全文