基础设施 · 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
目录
6B. 207 实战:K3s + Docker GitLab + Argo CD
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。
┌─────────────┐
│ Git 仓库 │ ← 真相(谁 Merge 了啥,有记录)
└──────┬──────┘
│ Argo CD 轮询 / Webhook
▼
┌─────────────┐
│ K8s 集群 │ ← 实际运行的 Deployment / Service …
└─────────────┘它不是:构建镜像(那是 CI + Harbor)、跑单元测试、替代 Kubernetes 本身。 它是:发布与对齐的控制器——「Git 里写了 2 副本,集群就必须是 2 副本」。
2. GitOps 与 Argo CD 原理
2.1 GitOps 三句话
- 声明式:描述「期望状态」(YAML),不是写一串 imperative 命令。
- Git 为单一事实来源(SSOT):生产长什么样,以 Git 某分支/路径为准。
- 自动对齐:控制器发现 Git 与集群不一致 → 执行 Sync(或告警等人批准)。
2.2 Pull vs Push
| 模式 | 谁主动 | 典型 |
|---|---|---|
| Push | CI 拿着 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
口诀(与姊妹篇一致):
镜像进 Harbor · 声明进 Git · 真相以 Git 为准 · Argo 负责落地3. 核心概念词典
第一次接触,先把这些词背熟:
| 概念 | 是什么 | 你要记住的 |
|---|---|---|
| Application | 一条「Git 路径 → 某个集群某个 NS」的同步规则 | 最常用的 CRD;一个应用/一套清单通常一个 Application |
| AppProject | Application 的「权限边界」:允许哪些 Git 仓、哪些集群、哪些资源类型 | 生产别全用 default |
| Source | Git 地址、targetRevision(分支/tag/commit)、path 或 Helm 参数 | 改发版 = 改 Git 这里的内容或 revision |
| Destination | 同步到哪个集群(server)哪个命名空间 | 多集群时靠不同 Application 或 ApplicationSet |
| Sync | 执行一次对齐:把 Git 渲染结果 apply 到集群 | 可手动点 Sync,也可 automated |
| Sync Status | Synced / OutOfSync | OutOfSync = Git 和集群不一致 |
| Health | 工作负载是否健康(Deployment 是否 Ready 等) | Healthy ≠ Synced;可能已同步但 Pod 起不来 |
| Revision | 当前同步的 Git commit SHA | 回滚 = 指回旧 revision 再 Sync |
| Prune | 同步时删除 Git 里已不存在的资源 | 开 automated prune 要小心误删 |
| Self-Heal | 集群被人 kubectl edit 改了 → 自动改回 Git | 生产常开;调试时可关 |
| Diff | UI/CLI 对比 Git vs Live | 发版前必看 |
3.1 Application 最小 mental model
# 逻辑上等价于:
# 「把 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-server | API + Web UI |
| argocd-repo-server | 拉 Git、渲染 Helm/Kustomize,生成 manifests |
| argocd-application-controller | 对比 Git vs 集群,执行 Sync |
| argocd-dex(可选) | SSO / OIDC |
| argocd-redis | 缓存与协调 |
用户 / CLI / CI
│
▼
argocd-server (UI :443)
│
├─► repo-server ──► GitLab / 公网 Git
│
└─► application-controller ──► Kubernetes API两种常见部署形态:
| 形态 | 说明 |
|---|---|
| 装在业务集群里 | 本教程默认;简单,适合单集群实验 |
| 独立管理集群 | 一个 Argo 管多个业务集群;中大公司更常见 |
5. 一次同步到底发生了什么
以「Git 里把 Deployment 副本从 1 改成 2」为例:
- 开发 Merge MR →
main上 commitabc123含replicas: 2。 - Argo CD 每 3 分钟轮询(或 GitLab Webhook 触发)发现
targetRevision: main有新 commit。 - repo-server checkout 该 commit,若 path 是 Kustomize/Helm 则渲染成纯 YAML。
- application-controller 对比 Desired(Git)与 Live(集群)。
- 状态变为 OutOfSync;若
automated.selfHeal或人工点 Sync: - 对 Deployment 执行 apply/update → 集群滚动扩容到 2 副本。
- Deployment Ready → Application Health: Healthy,Sync: Synced,记录 Revision: abc123。
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 前置
- Kubernetes 1.24+(已 Ready)
kubectl能访问集群- 集群可拉取镜像(或已配 Harbor)
- 建议先建业务 NS:
gpu-infer(见附录 A)
6.2 安装 Argo CD(官方稳定 manifest)
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 首次登录
# 取初始 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(可选但推荐)
# 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 version6.5 把 Git 仓库交给 Argo CD
方式 A — UI:Settings → Repositories → Connect repo → HTTPS + deploy token / SSH key。
方式 B — CLI:
argocd repo add https://gitlab.example.local/ai-platform/gpu-infer-manifests.git \
--username gitlab-ci-token --password '<token>'仓库需包含 Kubernetes 清单(见附录 B 示例目录结构)。
建议 Git 布局:
gpu-infer-manifests/
base/
deployment.yaml
service.yaml
kustomization.yaml
overlays/
lab/
kustomization.yaml # 实验:副本 1
prod/
kustomization.yaml # 生产:副本 2、image tag6.6 创建第一个 Application
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验收:
kubectl -n gpu-infer get deploy,po
argocd app list
# SYNC STATUS = Synced, HEALTH = Healthy6.7 故意制造 OutOfSync(理解 Self-Heal)
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 拓扑
浏览器
├─ 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-demo6B.2 一键部署(Windows)
# 先同步脚本与 patches 到 207
python scripts_cursor/00_部署_workbuddy到207.py
# 安装演示环境(首次含拉 GitLab 镜像,可能 15~30 分钟)
python scripts_cursor/基础设施_Argo_CD_原理与部署教程/argocd_01_207部署演示.py207 上也可:
bash /opt/workbuddy/patches_cursor/基础设施_Argo_CD_原理与部署教程/install_207_demo.sh安装日志:/opt/argocd-demo/install.log 访问说明:/opt/argocd-demo/访问说明.txt
6B.3 账号与入口(默认)
| 入口 | URL / 命令 | 账号 |
|---|---|---|
| GitLab | http://192.168.110.207:8929 | root / ArgoDemo207! |
| 清单仓 | http://192.168.110.207:8929/root/argocd-manifests | 同上 |
| Argo CD | http://192.168.110.207:30080 | admin / 见 访问说明.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。安装脚本会跳过覆盖:
Skipping /usr/local/bin/kubectl symlink to k3s, command exists in PATH at /usr/bin/kubectl因此你直接执行:
kubectl get nodes常见报错:
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 挂了。集群本身用下面命令验证:
# 推荐:永远用 k3s 自带客户端 + 官方 kubeconfig
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
k3s kubectl get nodes
k3s kubectl get pods -A和本演示相关:
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
k3s kubectl -n argocd get applications
k3s kubectl -n argocd-demo get deploy,po,svc若仍想敲短命令 kubectl:
# 写入登录环境(推荐)
echo 'export KUBECONFIG=/etc/rancher/k3s/k3s.yaml' >> ~/.bashrc
echo "alias kubectl='k3s kubectl'" >> ~/.bashrc
source ~/.bashrc
# 验证
kubectl get nodes或(更狠,慎用):把旧二进制挪开再链到 k3s:
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服务状态:
systemctl status k3s
# 配置文件:/etc/rancher/k3s/k3s.yaml
# 卸载(慎用):/usr/local/bin/k3s-uninstall.sh6B.4 怎么玩(推荐顺序)
玩法 A — 改 Git,看 Argo 自动对齐
- 打开 GitLab →
root/argocd-manifests→demo-nginx/deployment.yaml - 把
replicas: 1改成replicas: 2→ Commit 到main - 打开 Argo CD → Application
demo-nginx:先 OutOfSync,片刻变 Synced(automated) - 207 上验证:
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
k3s kubectl -n argocd-demo get deploy,po
# Ready 应为 2/2玩法 B — 人肉改集群,看 Self-Heal
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部署演示.py | Windows 触发安装 |
patches_cursor/…/install_207_demo.sh | 207 安装主脚本(全文见附录 F) |
patches_cursor/…/manifests/demo-nginx/deployment.yaml | 推入 GitLab 的工作负载(附录 G) |
patches_cursor/…/manifests/argocd-application-demo-nginx.yaml | Argo 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 |
| 2 | CI | build 镜像 → push Harbor tag:20260901 |
| 3 | 开发/运维 | 改 manifests 仓里 image.tag 或 kustomize edit set image → MR |
| 4 | Reviewer | 看 Diff(Git MR + Argo UI Diff) |
| 5 | Merge | 合入 main |
| 6 | Argo | 自动或手动 Sync → 滚动更新 |
| 7 | 值班 | 看 Health;异常则 Rollback 到上一 Git revision |
7.2 常用 CLI
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 applications7.3 什么时候手动 Sync / 什么时候 automated
| 场景 | 建议 |
|---|---|
| 实验 / lab | automated: { prune: false, selfHeal: true } |
| 生产 GPU 推理 | 常用手动 Sync 或 automated 但不 prune;重大变更走 MR + 人工点 Sync |
| 多集群 | 同一 manifests 不同 overlay;每集群一个 Application |
7.4 回滚怎么做
- 推荐:Git revert 那个改 image tag 的 commit → Argo 同步旧状态(可追溯)。
- 应急:
argocd app rollback <app> <history-id>(仍基于 Argo 记录的 revision)。 - 不要:只
kubectl rollout undo却不改 Git——下次 Sync 又会被改回去(若 selfHeal)。
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.yaml | Git manifests 仓 |
| 发布动作 | 拷贝 + systemctl restart litellm | Sync Application |
| 回滚 | git checkout 旧 config + restart | Git 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 写 |
# 排障三板斧
argocd app get <app> --refresh
argocd app diff <app>
kubectl -n argocd logs deploy/argocd-application-controller --tail=10011. 学习路径与自测
11.1 建议阅读顺序
- 本文(概念 + 装一个 demo Application)
- K8s GPU 理论 §6(Argo 在整条链的位置)
- 单私有化 GPU 集群完整案例 §6(真实 vLLM Application)
- 官方:Argo CD Getting Started
11.2 自测题
- GitOps 的「单一事实来源」是什么?Argo CD 是 Push 还是 Pull?
- Application 的
source和destination各表示什么? - Synced 和 Healthy 有什么区别?
- 为什么改镜像 tag 要提交 Git,而不是只
kubectl set image? - 本环境 LiteLLM 路由发布,对应 Argo 里的哪一步?
12. 完整配置附录
下列正文与
patches_cursor/基础设施_Argo_CD_原理与部署教程/下同名文件全文一致。
附录 A · 01-namespace.yaml
路径:patches_cursor/基础设施_Argo_CD_原理与部署教程/01-namespace.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
# 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
# 最小 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
# 生产建议:用 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
# 可选:内网暴露 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
#!/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
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
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 全文 |