Argo CD CLI 实战:argocd app manifests命令完整参考与源码级解析
【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd
导读
argocd app manifests是 Argo CD 命令行工具中用于**打印指定 Application 的清单(manifests)**的核心命令,它允许开发者在终端中直接查看某个应用的目标清单(来自 Git 或本地目录)或当前运行在集群中的实际清单(live 状态)。本篇文章以官方命令参考文档为主体,结合仓库中命令的 Go 源码实现(cmd/argocd/commands/app.go),完整讲解该命令的语法、全部参数、多源(multi-source)应用按修订(revision)查看清单的技巧,以及底层调用链与输出格式,让你能够熟练运用它进行应用清单的调试、审计与 CI 集成。
一、命令概览与使用场景
argocd app manifests命令的作用是"Print manifests of an application",即打印一个应用程序的清单。在实际的 GitOps 工作流中,它常被用于:
- 验证期望状态:查看 Argo CD 认为某应用应部署的清单(默认来自 Git 仓库的
git源); - 对比实时状态:通过
--source live查看集群中当前实际运行的资源清单; - 按版本排查:在回滚或故障定位时,查看某个特定 revision 的清单内容;
- 本地预渲染检查:在提交代码前,用
--local让 CLI 直接从本地目录生成清单,快速核对模板渲染结果; - CI 集成:在流水线中获取应用清单用于静态分析或审计。
该命令隶属于argocd app命令组,在源码中通过command.AddCommand(NewApplicationManifestsCommand(clientOpts))注册(参见 cmd/argocd/commands/app.go)。
基本语法
argocd app manifests APPNAME [flags]其中APPNAME为必填参数,即 Application 的名称。若应用位于非默认命名空间,可通过-N/--app-namespace指定。
二、官方示例详解
文档给出了四组典型示例,覆盖了单源、指定修订、多源按名称、多源按位置四种场景:
# 1. 获取应用的清单(默认使用 git 源、当前目标修订) argocd app manifests my-app # 2. 获取应用在指定修订(revision)下的清单 argocd app manifests my-app --revision 0.0.1 # 3. 多源应用:为指定 source 名称(source-names)分别获取对应修订的清单 argocd app manifests my-app --revisions 0.0.1 --source-names src-base --revisions 0.0.2 --source-names src-values # 4. 多源应用:为指定 source 位置(source-positions)分别获取对应修订的清单 argocd app manifests my-app --revisions 0.0.1 --source-positions 1 --revisions 0.0.2 --source-positions 2示例 1是最常见用法:不附加任何修订参数时,命令取用 Application 当前的目标状态(target state),即 Argo CD 已经为应用计算的、来自清单仓库的期望资源集合。
示例 3 与 4针对的是多源应用(spec.sources中存在多个 source)。两者都需要配合--revisions(stringArray 类型,可重复出现)使用,区别在于定位 source 的方式:
--source-names使用多源中每个 source 的name字段定位;--source-positions使用 source 在spec.sources列表中的从 1 开始计数的位置定位。
两者的底层实现都落在同一套逻辑上:--source-names会被转换为位置后再查询。在 NewApplicationManifestsCommand 中,源码首先从已获取的 Application 对象上调用getSourceNameToPositionMap(app)构建「名称 → 位置」映射,然后把名称一一翻译成位置:
if len(sourceNames) > 0 { sourceNameToPosition := getSourceNameToPositionMap(app) for _, name := range sourceNames { pos, ok := sourceNameToPosition[name] if !ok { log.Fatalf("Unknown source name '%s'", name) } sourcePositions = append(sourcePositions, pos) } }而getSourceNameToPositionMap(cmd/argocd/commands/app.go)的实现非常直观:遍历app.Spec.Sources,跳过未设置name的 source,将name映射为i + 1(位置从 1 开始):
func getSourceNameToPositionMap(app *argoappv1.Application) map[string]int64 { sourceNameToPosition := make(map[string]int64) for i, s := range app.Spec.Sources { if s.Name != "" { sourceNameToPosition[s.Name] = int64(i + 1) } } return sourceNameToPosition }这也解释了为什么文档中--source-positions的说明强调 "Counting start at 1"(计数从 1 开始)。
三、专属选项(Options)全参数说明
以下是该命令自身的全部选项及其含义:
| 选项 | 简写 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
--app-namespace | -N | string | 空 | Application 所在的命名空间 |
--help | -h | bool | - | 显示 manifests 子命令的帮助信息 |
--local | - | string | 空 | 若设置,则展示本地生成的清单。取值为清单仓库中应用清单的绝对路径,例如'/home/username/apps/env/app-1' |
--local-repo-root | - | string | "." | 本地仓库根目录路径。与--local一起使用,用于设定仓库根,例如'/home/username/apps' |
--revision | - | string | 空 | 展示指定修订(revision)下的清单 |
--revisions | - | stringArray | 空数组 | 为--source-positions对应位置上的 source 分别指定修订,可重复传入 |
--source | - | string | "git" | 清单来源,取值为live或git之一 |
--source-names | - | stringArray | 空数组 | source 名称列表 |
--source-positions | - | int64Slice | 空数组 | source 位置列表,计数从 1 开始 |
参数使用要点
--source:选择目标清单还是实时清单
git(默认):展示目标状态(target state),即从 Git 清单仓库渲染出的期望资源;live:展示实时状态(live state),即当前部署在目标集群中的实际资源。
--revision与--revisions的区别
--revision用于单源应用,直接指定一个修订号;--revisions是 stringArray 类型,可以重复出现多次(如示例 3、4 所示),用于多源应用,为不同的 source 指定不同的修订,必须与--source-positions或--source-names数量一一对应。
--local与--local-repo-root
- 两者必须搭配使用:
--local指向应用清单所在目录,--local-repo-root指向本地仓库根。CLI 会在本地直接调用 repo-server 的清单生成逻辑(repository.GenerateManifests,见 cmd/argocd/commands/app_diff.go)渲染清单,而无需先提交代码; - 需要特别注意的是:源码注释明确标注
getLocalObjects为"Deprecated: Prefer server-side generation since local side generation does not support plugins"(已弃用:优先使用服务端生成,因为本地生成不支持插件)。同时,本地生成模式下 Secret 资源会被跳过并输出警告(参见 cmd/argocd/commands/app_diff.go),因为本地 diff 无法可靠地使用服务端配置隐藏 Secret 数据。因此该模式更适合快速的模板渲染检查,生产环境请优先使用默认的服务端生成方式。
四、继承自父命令的全局选项
argocd app manifests还继承了argocd根命令的全部全局选项,常见于连接与认证配置:
| 选项 | 说明 |
|---|---|
--argocd-context | 要使用的 Argo CD server 上下文名称 |
--auth-token | 认证令牌;设置此参数或ARGOCD_AUTH_TOKEN环境变量 |
--client-crt/--client-crt-key | 客户端证书文件及密钥文件 |
--config | Argo CD 配置文件路径,默认"/home/user/.config/argocd/config" |
--controller-name | Application controller 名称(安装 Helm chart 时名称可能与默认不同),默认argocd-application-controller,也支持ARGOCD_APPLICATION_CONTROLLER_NAME环境变量 |
--core | 若为 true,CLI 直接与 Kubernetes 通信,而不经过 Argo CD API server |
--grpc-web | 启用 gRPC-web 协议(当 Argo CD server 位于不支持 HTTP2 的代理之后时有用) |
--grpc-web-root-path | 启用 gRPC-web 协议并设置 web 根路径 |
-H, --header | 为所有 Argo CD CLI 请求附加额外的 header(可重复添加,也支持逗号分隔的多个 header) |
--http-retry-max | 建立到 Argo CD server 的 HTTP 连接的最大重试次数 |
--insecure | 跳过服务器证书与域名验证 |
--kube-context | 指定命令使用的 kube-context |
--logformat | 日志格式,json或text,默认json |
--loglevel | 日志级别,debug、info、warn或error,默认info |
--plaintext | 禁用 TLS |
--port-forward | 使用端口转发连接一个随机 argocd-server 端口 |
--port-forward-namespace | 端口转发使用的命名空间名称 |
--prompts-enabled | 强制启用/禁用可选交互提示,覆盖本地配置;未指定时使用本地配置值(默认 false) |
--redis-compress | 当 Application controller 启用了 Redis 压缩时启用,可选gzip、none,默认gzip |
--redis-haproxy-name | Redis HA Proxy 名称(HA Proxy 名称标签与默认不同时设置),默认argocd-redis-ha-haproxy,也支持ARGOCD_REDIS_HAPROXY_NAME |
--redis-name | Redis deployment 名称,默认argocd-redis,也支持ARGOCD_REDIS_NAME |
--repo-server-name | Repo server 名称,默认argocd-repo-server,也支持ARGOCD_REPO_SERVER_NAME |
--server | Argo CD server 地址 |
--server-crt/--server-name | 服务器证书文件 / API server 名称,--server-name默认argocd-server,也支持ARGOCD_SERVER_NAME |
实际使用示例
# 使用 core 模式直接与 Kubernetes 通信(无需 argocd-server) argocd app manifests my-app --core # 通过端口转发连接服务器 argocd app manifests my-app --port-forward # 使用 token 认证并指定服务器地址 argocd app manifests my-app --server argocd.example.com:443 --auth-token "$ARGOCD_AUTH_TOKEN"五、源码级原理:命令的执行流程
理解了参数后,我们深入 NewApplicationManifestsCommand 的实现,梳理整条执行链路。命令的Run逻辑大致分为五个阶段:
阶段 1:参数校验
if len(args) != 1 { c.HelpFunc()(c, args) os.Exit(1) } if len(sourceNames) > 0 && len(sourcePositions) > 0 { errors.Fatal(errors.ErrorGeneric, "Only one of source-positions and source-names can be specified.") } if len(sourcePositions) > 0 && len(revisions) != len(sourcePositions) { errors.Fatal(errors.ErrorGeneric, "While using --revisions and --source-positions, length of values for both flags should be same.") } if len(sourceNames) > 0 && len(revisions) != len(sourceNames) { errors.Fatal(errors.ErrorGeneric, "While using --revisions and --source-names, length of values for both flags should be same.") } for _, pos := range sourcePositions { if pos <= 0 { log.Fatal("source-position cannot be less than or equal to 0, Counting starts at 1") } }从源码可以确认以下三条硬性校验规则:
--source-names与--source-positions不能同时使用,否则直接报错退出;- 使用
--revisions时,其数量必须与--source-positions或--source-names的数量严格相等,即一一配对; --source-positions中的每个位置必须> 0,计数从 1 开始。
阶段 2:解析应用名称并建立客户端连接
appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) clientset := headless.NewClientOrDie(clientOpts, c) conn, appIf := clientset.NewApplicationClientOrDieWithContext(ctx)应用名称支持namespace/name形式的限定名,-N指定的命名空间作为兜底。随后建立与 Argo CD API server 的 gRPC 连接,获取 ApplicationService 客户端,并调用appIf.Get拉取 Application 对象。
阶段 3:获取受管资源(ManagedResources)
resources, err := appIf.ManagedResources(ctx, &application.ResourcesQuery{ ApplicationName: &appName, AppNamespace: &appNs, })这一步从 server 端取回应用当前管理(managed)的所有资源的ResourceDiff列表——每个ResourceDiff中同时携带了该资源的 target state(目标状态)与 live state(实时状态)的 JSON 快照。这正是后续git源(默认分支)与live源能够直接打印的基础数据。
阶段 4:按--source分支生成 unstructured 对象
源码中switch source分两大分支:
git分支(默认)又分三种子情形:
--local已设置:进入本地生成流程。代码会依次获取 Argo CD 设置(settings)、目标集群信息(cluster)与项目(project),再调用getLocalObjects(ctx, app, proj.Project, local, localRepoRoot, argoSettings, &cluster.Info)(实现见 cmd/argocd/commands/app_diff.go),最终经由repository.GenerateManifests在本地渲染清单;--revisions+--source-positions已设置(多源指定修订):构造application.ApplicationManifestQuery,一次性传入Revisions与SourcePositions,调用appIf.GetManifests(ctx, &q)由 server 端渲染,返回的每个清单字符串通过argoappv1.UnmarshalToUnstructured反序列化为 unstructured 对象;--revision已设置(单源指定修订):构造仅含Revision的ApplicationManifestQuery并调用appIf.GetManifests;- 默认(无修订参数):直接复用阶段 3 拉回的
resources,通过targetObjects(resources.Items)(cmd/argocd/commands/app.go)把每个ResourceDiff的target状态反序列化为 unstructured 对象:
func targetObjects(resources []*argoappv1.ResourceDiff) ([]*unstructured.Unstructured, error) { objs := make([]*unstructured.Unstructured, len(resources)) for i, resState := range resources { obj, err := resState.TargetObject() ... } return objs, nil }live分支:调用cmdutil.LiveObjects(resources.Items)(cmd/util/app.go),逻辑与targetObjects对称,反序列化每个ResourceDiff的live状态:
func LiveObjects(resources []*argoappv1.ResourceDiff) ([]*unstructured.Unstructured, error) { objs := make([]*unstructured.Unstructured, len(resources)) for i, resState := range resources { obj, err := resState.LiveObject() ... } return objs, nil }其他--source取值会被拒绝并报错:log.Fatalf("Unknown source type '%s'", source)。
阶段 5:序列化输出
for _, obj := range unstructureds { fmt.Println("---") yamlBytes, err := yaml.Marshal(obj) errors.CheckError(err) fmt.Printf("%s\n", yamlBytes) }最终每个对象以YAML 文档形式打印,对象之间用---分隔符隔开——这与kubectl get -o yaml的输出风格一致,便于直接 pipe 给kubectl apply -f -或yq等工具继续处理。整个对象集合经过 yaml.Marshal 序列化,输出的是 Kubernetes 资源的完整 YAML(含 apiVersion、kind、metadata 等)。
一条调用链小结
argocd app manifests my-app └─ NewApplicationManifestsCommand (cmd/argocd/commands/app.go) ├─ appIf.Get → 获取 Application 对象 ├─ appIf.ManagedResources → 获取 ResourceDiff 列表(target + live 快照) ├─ targetObjects / LiveObjects → 反序列化为 unstructured 对象 │ (或 GetManifests 走 server 端渲染;或 getLocalObjects 走本地渲染) └─ yaml.Marshal + "---" 分隔 → 输出 YAML 文档流六、进阶实战场景
场景一:审计指定 revision 的期望清单
回滚前核对某次提交到底会部署什么:
argocd app manifests my-app --revision 0.0.1 > expected-v0.0.1.yaml场景二:对比目标与实时清单
先导出目标清单,再导出实时清单,用diff快速找出漂移:
argocd app manifests my-app --source git > target.yaml argocd app manifests my-app --source live > live.yaml diff target.yaml live.yaml注意:
git与live两个分支的数据来源不同——git默认分支直接来自ManagedResources中的 target 快照(未带修订参数时),而live分支始终来自同一批ResourceDiff中的 live 快照,两者天然对齐可比。
场景三:多源应用的修订级清单
假设应用my-app有src-base和src-values两个 source:
# 按 source 名称指定不同修订 argocd app manifests my-app \ --revisions v1.0.0 --source-names src-base \ --revisions v2.0.0 --source-names src-values # 等价写法:按 source 位置指定(位置从 1 开始) argocd app manifests my-app \ --revisions v1.0.0 --source-positions 1 \ --revisions v2.0.0 --source-positions 2场景四:本地快速渲染检查
在提交代码前验证本地 Helm/Kustomize 渲染结果(注意插件不可用、Secret 会被跳过):
argocd app manifests my-app \ --local /home/username/apps/env/app-1 \ --local-repo-root /home/username/apps场景五:在脚本/CI 中消费输出
由于输出是标准 YAML 文档流,可直接与 Kubernetes 工具链串联:
# 统计应用期望清单中的资源数量 argocd app manifests my-app | grep -c '^kind:' # 抽取所有 Deployment 的镜像 argocd app manifests my-app | yq eval-all '.spec.template.spec.containers[].image' - 2>/dev/null || true七、相关命令与进一步阅读
argocd app manifests是argocd app命令族的一员。在 cmd/argocd/commands/app.go 中可以看到它与其他子命令并列注册,其中与该命令功能最相近的是:
argocd app get:获取应用整体详情(状态、同步状态、参数等),见 argocd app 命令参考;argocd app diff:对比目标清单与实时清单的差异,其底层同样复用了targetObjects/LiveObjects与本地生成逻辑(getLocalObjects),实现于 cmd/argocd/commands/app_diff.go;argocd app sync:将应用同步到目标状态,manifests输出的 YAML 可以帮助你在执行同步前确认将要 apply 的内容。
若需要了解 Application 多源(multi-source)的配置方式、spec.sources的字段定义,可查阅仓库中对应的 API 类型定义 pkg/apis/application/v1alpha1 下的 Application 结构体,以及官方操作手册中关于多源应用的章节。
结语
argocd app manifests虽然参数不多,但通过--source、--revision/--revisions、--local的组合,覆盖了「目标/实时/指定修订/本地渲染」四种清单查看维度,是多源应用与 CI 审计场景下的高频命令。理解其背后的ManagedResources→ResourceDiff→ YAML 序列化的调用链(cmd/argocd/commands/app.go),能帮助你在排查部署问题时更准确地判断清单数据的来源与可信度。建议在实际环境中动手运行几次示例命令,结合--source live与--source git的输出差异,建立对 Argo CD 目标状态与实时状态模型的直观认识。
【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考