Argo CD ApplicationSet Cluster Generator 完整指南:基于集群 Secret 自动生成跨集群 Application
【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd
本篇技术指南围绕 Argo CD 的 ApplicationSet Cluster Generator 展开,深入讲解它如何以 Argo CD 命名空间中的集群 Secret 为唯一真相来源(source of truth),自动为每个已注册集群生成参数并渲染出对应的 Application 资源。读完本文,你将掌握 Cluster Generator 的自动参数模型、标签选择器(label selector)、本地集群(in-cluster)处理、基于 Kubernetes 版本选集群、values字段扩展以及flatList扁平化输出等完整实战能力,并了解其底层源码实现与测试验证方式。
Cluster Generator 工作原理:集群 Secret 即真相来源
在 Argo CD 中,被纳管的集群与仓库、仓库凭据一样,都是以 Kubernetes Secret 的形式存储在 Argo CD 命名空间中的。每个集群 Secret 必须带有标签argocd.argoproj.io/secret-type: cluster,用于标识其类型(参见 声明式集群配置)。
ApplicationSet Controller 中的 Cluster Generator 正是读取这些 Secret,将其中携带的集群信息转换成一组参数,并交给 Application 模板渲染,从而为每个匹配的集群生成一个对应的 Application 资源。
从源码实现来看(applicationset/generators/cluster.go),ClusterGenerator实现了Generator接口,其核心逻辑在GenerateParams方法中:它会通过缓存好的 controller-runtime client 列出所有带argocd.argoproj.io/secret-type: cluster标签的 Secret,然后为每个 Secret 调用getClusterParameters提取参数(见 cluster.go#L48-L108)。特别值得一提的是,GetRequeueAfter始终返回NoRequeueAfter,因为集群 Secret 一旦发生变化,clusterSecretEventHandler事件处理器会自动触发相关 ApplicationSet 的重新入队(见 cluster.go#L38-L42),无需周期轮询。
自动提供的参数
对于 Argo CD 中注册的每一个集群,Cluster Generator 会自动向 Application 模板提供以下参数:
| 参数 | 含义 |
|---|---|
name | 集群名称,取自集群 Secret 的name数据字段 |
nameNormalized | name的规范化版本,仅包含小写字母数字字符、-或. |
server | 集群 API Server 地址,取自 Secret 的server数据字段 |
project | Secret 中的project字段;若不存在则默认为空字符串'' |
metadata.labels.<key> | Secret 上每一个标签(label)都会映射为对应的参数 |
metadata.annotations.<key> | Secret 上每一个注解(annotation)都会映射为对应的参数 |
注意:如果集群名称包含 Kubernetes 资源名不支持的字符(如下划线
_),请使用nameNormalized参数。例如名为my_cluster的集群,直接渲染会得到非法的资源名my_cluster-app1,而使用nameNormalized会将其转换为合法的my-cluster-app1。
在源码层面(见 cluster.go#L128-L163),getClusterParameters负责组装这些参数:nameNormalized由utils.SanitizeName对name清洗得到。清洗规则(见 applicationset/utils/template_functions.go#L14-L29)包括:全部转为小写、用-替换非法字符、总长度不超过 253 个字符、并以字母数字字符开头和结尾。测试用例TestSanitizeClusterName(见 applicationset/generators/cluster_test.go#L859-L867)验证了-.--CLUSTER/name -./.-会被清洗为cluster-name。
另外要注意 GoTemplate 模式与非 GoTemplate 模式下metadata的暴露形式不同:开启goTemplate: true时,metadata以嵌套 map 形式提供(如{{index .metadata.annotations "my-annotation"}});未开启时则展平为metadata.labels.<key>、metadata.annotations.<key>这样的扁平键。本文示例均基于 GoTemplate 模式。
基础用法:为每个集群部署一套应用
集群 Secret 中的name和server数据字段描述了一个集群,Cluster Generator 会自动识别 Argo CD 中定义的集群并将其数据提取为参数。以下是最基础的完整示例,它会对所有注册集群分别渲染一个名为<集群名>-guestbook的 Application:
apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: guestbook namespace: argocd spec: goTemplate: true goTemplateOptions: ["missingkey=error"] generators: - clusters: {} # 自动使用 Argo CD 内定义的全部集群 template: metadata: name: '{{.name}}-guestbook' # 使用集群 Secret 的 'name' 字段 spec: project: "my-project" source: repoURL: https://github.com/argoproj/argocd-example-apps/ targetRevision: HEAD path: guestbook destination: server: '{{.server}}' # 使用集群 Secret 的 'server' 字段 namespace: guestbook在这个例子中,集群 Secret 的name和server字段被用来填充 Application 资源的metadata.name和spec.destination.server,从而让生成的 Application 精确指向它对应的集群。仓库中提供了可直接运行的完整示例:cluster-example.yaml(GoTemplate 风格)与 cluster-example-fasttemplate.yaml(快速模板风格)。
对应的集群 Secret 形态如下(Kubernetes 中data字段实际是 Base64 编码,此处为便于阅读已解码;Cluster Generator 传入参数时同样会先解码):
kind: Secret data: config: "{'tlsClientConfig':{'insecure':false}}" name: "in-cluster2" server: "https://kubernetes.default.svc" metadata: labels: argocd.argoproj.io/secret-type: cluster # (...)关于集群 Secret 支持的全部数据字段,可参见 声明式集群配置:其中name、server为必填,project可选(用于将集群限定到某个 Project),namespaces、clusterResources可选,config必填且为 JSON 结构,内含 basic auth(username/password)、bearer token、awsAuthConfig、execProviderConfig、proxyUrl、tlsClientConfig等认证配置。
使用 Label Selector 精准选择目标集群
当集群数量变多时,通常不希望把应用部署到所有集群。可以使用标签选择器(label selector)将目标集群范围收窄到匹配特定标签的集群:
apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: guestbook namespace: argocd spec: goTemplate: true goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: matchLabels: staging: "true" # Cluster generator 同样支持 matchExpressions: #matchExpressions: # - key: staging # operator: In # values: # - "true" template: # (...)上述选择器会匹配带有如下标签的集群 Secret:
apiVersion: v1 kind: Secret data: # (... 字段同上 ...) metadata: labels: argocd.argoproj.io/secret-type: cluster staging: "true" # (...)标签选择器同样支持基于集合(set-based)的需求表达式,例如operator: In、NotIn、Exists、DoesNotExist等。
从源码看(见 cluster.go#L165-L188),getSecretsByClusterName会把用户配置的 selector 与argocd.argoproj.io/secret-type: cluster标签合并(metav1.AddLabelToSelector),因此无论是否显式配置,集群 Secret 的必备标签都会被自动加上。测试用例(见 applicationset/generators/cluster_test.go)覆盖了「production-only」「production or staging(matchExpressions)」「matchExpressions + matchLabels 组合」等多种选择器场景,可对照验证行为。
部署到本地集群(in-cluster)
在 Argo CD 语境中,「本地集群」(local cluster)指的是 Argo CD 及 ApplicationSet Controller 自身运行所在的那个集群,用来与通过声明式配置(见 声明式集群配置)或 Argo CD CLI(argocd cluster add)添加的「远程集群」相区分。
Cluster Generator 会对所有匹配集群选择器的本地集群与远程集群一视同仁地自动生成参数。源码层面(见 cluster.go#L90-L105)的处理逻辑是:当没有配置 selector 时,如果集群 Secret 列表中不包含 in-cluster 凭据,则自动为本地集群补充一组参数——name为in-cluster、nameNormalized为in-cluster、server为https://kubernetes.default.svc、project为空字符串(这两个常量定义于 pkg/apis/application/v1alpha1/application_defaults.go#L30-L34)。
只想部署到远程集群
如果希望生成的 Application 只面向远程集群(例如要排除本地集群),可以配置带标签的选择器:
spec: goTemplate: true goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: matchLabels: argocd.argoproj.io/secret-type: cluster # Cluster generator 同样支持 matchExpressions: #matchExpressions: # - key: staging # operator: In # values: # - "true"这个选择器不会匹配默认的本地集群,因为默认的本地集群没有对应的 Secret(自然也没有argocd.argoproj.io/secret-type标签)。因此,任何基于该标签进行选择的 selector 都会自动排除默认本地集群。这一点与源码中ignoreLocalClusters的判断一致:只要配置了非空的MatchExpressions或MatchLabels,就会忽略本地集群(见 cluster.go#L58-L60)。
既想包含本地集群,又要使用标签匹配
如果既想使用标签匹配、又想包含本地集群,可以在 Argo CD Web UI 中为本地集群创建一个 Secret:
- 在 Argo CD Web UI 中,进入Settings,再选择Clusters。
- 选择你的本地集群(通常名为
in-cluster)。 - 点击Edit按钮,将集群的NAME改为其他值,例如
in-cluster-local(任意其他值均可)。 - 其余字段保持不变。
- 点击Save。
这些步骤看似违反直觉,但修改本地集群默认值的行为会触发 Argo CD Web UI 为该集群创建一个新的 Secret。此时在 Argo CD 命名空间中会看到名为cluster-<集群后缀>的 Secret,且带有标签argocd.argoproj.io/secret-type: cluster。也可以改为通过声明式配置创建本地集群 Secret(见 声明式集群配置),或使用 CLI 命令argocd cluster add "(context name)" --in-cluster创建,而不必走 Web UI。
基于 Kubernetes 版本筛选集群
Cluster Generator 还支持按集群的 Kubernetes 版本筛选。实现方式为:在集群 Secret 上设置标签argocd.argoproj.io/auto-label-cluster-info: "true"。一旦设置,Controller 会自动为该集群 Secret 动态打上其所运行 Kubernetes 版本的标签。随后便可在选择器中用argocd.argoproj.io/kubernetes-version标签取值:
spec: goTemplate: true generators: - clusters: selector: matchLabels: argocd.argoproj.io/kubernetes-version: v1.28.1 # 同样支持 matchExpressions: #matchExpressions: # - key: argocd.argoproj.io/kubernetes-version # operator: In # values: # - "v1.27.1" # - "v1.28.1"这一能力在需要按 Kubernetes 版本分批升级、或针对特定版本集群做差异化发布(例如灰度到 v1.28 集群、跳过 v1.27 集群)的场景下非常实用。
通过values字段传递额外键值对
Cluster Generator 支持通过values字段向模板传递额外的任意字符串键值对。经由values字段添加的值,在模板中以values.<字段名>的形式访问。
以下示例根据集群 Secret 的标签匹配,为不同类型的集群传入不同的revision参数:
spec: goTemplate: true goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: matchLabels: type: 'staging' # 任意参数的键值映射 values: revision: HEAD # staging 集群使用 HEAD 分支 - clusters: selector: matchLabels: type: 'production' values: # production 使用不同的 revision 值,即 'stable' 分支 revision: stable template: metadata: name: '{{.name}}-guestbook' spec: project: "my-project" source: repoURL: https://github.com/argoproj/argocd-example-apps/ # 每个 generator 的 cluster values 字段会在此处被替换: targetRevision: '{{.values.revision}}' path: guestbook destination: server: '{{.server}}' namespace: guestbook该示例中,generators.clusters.values提供的revision值会以values.revision的形式进入模板——由哪个 generator 生成的参数集决定其取值为HEAD或stable。
注意:通过
generators.clusters.values提供的值,总会自动加上values.前缀。在template中使用该参数时务必包含此前缀。
在 values 中插值集群参数
values字段还支持对页面开头列出的集群参数进行模板插值,包括:
namenameNormalized(name的规范化形式,仅含小写字母数字、-或.)servermetadata.labels.<key>(Secret 中的每个标签)metadata.annotations.<key>(Secret 中的每个注解)
扩展上面的示例,可以实现「根据集群 Secret 注解动态决定 revision」:
spec: goTemplate: true goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: matchLabels: type: 'staging' # 任意参数的键值映射 values: # 如果集群 Secret 中有 my-custom-annotation,revision 将被替换为该注解的值。 revision: '{{index .metadata.annotations "my-custom-annotation"}}' clusterName: '{{.name}}' - clusters: selector: matchLabels: type: 'production' values: # production 使用不同的 revision 值,即 'stable' 分支 revision: stable clusterName: '{{.name}}' template: metadata: name: '{{.name}}-guestbook' spec: project: "my-project" source: repoURL: https://github.com/argoproj/argocd-example-apps/ # 每个 generator 的 cluster values 字段会在此处被替换: targetRevision: '{{.values.revision}}' path: guestbook destination: # 此处等价于直接使用 {{name}} server: '{{.values.clusterName}}' namespace: guestbook源码中,values的插值由appendTemplatedValues完成(调用见 cluster.go#L81),且会为插值结果统一加上values.前缀;测试用例验证了values中引用其他values.*、metadata.annotations.*、metadata.labels.*、server等参数的嵌套插值行为(见 applicationset/generators/cluster_test.go#L390-L474)。
使用 flatList 将集群信息聚合成扁平列表
有时你并不需要为每个集群部署一个 Application,而是希望一次性获取所有集群的信息(例如在一个 Application 中统一生成 Helm values)。此时可以使用 Cluster Generator 的flatList选项。
使用flatList: true时,所有匹配集群的参数不会各自渲染一个 Application,而是聚合为单个参数集,其中以clusters为键包含所有集群的参数字典列表,供模板用range遍历:
spec: goTemplate: true goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: matchLabels: type: 'staging' flatList: true template: metadata: name: 'flat-list-guestbook' spec: project: "my-project" source: repoURL: https://github.com/argoproj/argocd-example-apps/ targetRevision: 'HEAD' path: helm-guestbook helm: values: | clusters: {{- range .clusters }} - name: {{ .name }} {{- end }} destination: server: 'my-cluster' namespace: guestbook假设有两个集群 Secret 匹配(名称分别为cluster1和cluster2),上述配置将生成唯一一个Application:
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: flat-list-guestbook namespace: guestbook spec: project: "my-project" source: repoURL: https://github.com/argoproj/argocd-example-apps/ targetRevision: 'HEAD' path: helm-guestbook helm: values: | clusters: - name: cluster1 - name: cluster2在源码实现中(见 cluster.go#L110-L126),paramHolder的consolidate方法在isFlatMode为 true 时,会把收集到的所有参数切片包装成{"clusters": [...]}的单一参数集返回;对应测试用例(如「flat mode without selectors」「production or staging with flat mode」,见 applicationset/generators/cluster_test.go#L222-L288)验证了这一聚合行为。
注意:如果同时使用多个带
flatList的 Cluster Generator,则每个 Cluster Generator 各生成一个 Application。这是因为无法简单合并各 generator 中可能不同的 values 与模板。
小结与源码速查
Cluster Generator 是 ApplicationSet 中最常用的生成器之一,其设计核心是「集群即 Secret、Secret 即参数」:只要集群以带argocd.argoproj.io/secret-type: cluster标签的 Secret 形式注册在 Argo CD 中,Cluster Generator 就能自动生成参数并渲染 Application。结合标签选择器、values插值与flatList,它可以灵活支撑按环境(staging/production)选集群、按 Kubernetes 版本选集群、跨集群统一参数注入以及集群信息聚合等多种多集群发布场景。
关键源码与示例位置速查:
- 生成器核心实现:applicationset/generators/cluster.go
- 名称清洗函数
SanitizeName:applicationset/utils/template_functions.go - 单元测试(含 GoTemplate 与非 GoTemplate、flatList、values 插值):applicationset/generators/cluster_test.go
- 可运行示例:applicationset/examples/cluster/cluster-example.yaml 与 cluster-example-fasttemplate.yaml
- 集群 Secret 声明式字段说明:docs/operator-manual/declarative-setup.md#clusters
- 本地集群与远程集群相关常量:pkg/apis/application/v1alpha1/application_defaults.go#L30-L34
【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考