【CN】Argo 持续集成和交付(二)

7.25.通知

概述

Argo CD 通知持续监控 Argo CD 应用程序,并提供一种灵活的方式来通知用户应用程序状态的重要变化。使用灵活的触发器和模板机制,可以配置何时发送通知以及通知内容。Argo CD 通知包含有用的触发器和模板目录。因此,可以直接使用它们,而不必重新发明新的触发器和模板。

入门
  • 从目录安装触发器和模板
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/notifications_catalog/install.yaml
  • 将电子邮件用户名和密码令牌添加到 argocd-notifications-secret secret 中
EMAIL_USER=<your-username>
PASSWORD=<your-password>

kubectl apply -n argocd -f - << EOF
apiVersion: v1
kind: Secret
metadata:
  name: argocd-notifications-secret
stringData:
  email-username: $EMAIL_USER
  email-password: $PASSWORD
type: Opaque
EOF
  • 注册电子邮件通知服务
kubectl patch cm argocd-notifications-cm -n argocd --type merge -p '{"data": {"service.email.gmail": "{ username: $email-username, password: $email-password, host: smtp.gmail.com, port: 465, from: $email-username }" }}'

通过将notifications.argoproj.io/subscribe.on-sync-succeeded.slack注释添加到Argo CD 应用程序或项目来订阅通知:

kubectl patch app <my-app> -n argocd -p '{"metadata": {"annotations": {"notifications.argoproj.io/subscribe.on-sync-succeeded.slack":"<my-channel>"}}}' --type merge

尝试同步应用程序以便在同步完成时收到通知。

基于命名空间的配置

Argo CD 通知的常见安装方法是将其安装在专用命名空间中以管理整个集群。在这种情况下,管理员通常是唯一可以在该命名空间中配置通知的人。但是,在某些情况下,需要允许最终用户为其 Argo CD 应用程序配置通知。例如,最终用户可以在他们有权访问且其 Argo CD 应用程序正在运行的命名空间中为其 Argo CD 应用程序配置通知。

此功能基于任意命名空间中的应用程序。有关更多信息,请参阅任意命名空间中的应用程序页面

为了启用此功能,Argo CD 管理员必须重新配置 argocd-notification-controller 工作负载,以将 --application-namespaces--self-service-notification-enabled 参数添加到容器的启动命令中。--application-namespaces 控制 Argo CD 应用程序所在的命名空间列表。--self-service-notification-enabled 启用此功能。

通过在 argocd-cmd-params-cm ConfigMap 中指定 application.namespacesnotificationscontroller.selfservice.enabled,也可以方便地设置两者的启动参数并保持同步,而无需更改相应工作负载的清单。例如:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cmd-params-cm
data:
  application.namespaces: app-team-one, app-team-two
  notificationscontroller.selfservice.enabled: "true"

要使用此功能,可以在 Argo CD 应用程序所在的命名空间中部署名为 argocd-notifications-cm 的配置映射以及可能的密钥 argocd-notifications-secret

当以这种方式配置时,控制器将使用控制器级别配置(位于与控制器相同的命名空间中的配置映射)以及位于 Argo CD 应用程序所在的同一命名空间中的配置发送通知。

示例:当控制器级别配置仅支持 Slack 时,应用程序团队希望使用 PagerDutyV2 接收通知。

以下两个资源部署在 Argo CD 应用程序所在的命名空间中。

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.pagerdutyv2: |
    serviceKeys:
      my-service: $pagerduty-key-my-service
...
apiVersion: v1
kind: Secret
metadata:
  name: argo-cd-notification-secret
type: Opaque
data:
  pagerduty-key-my-service: <pd-integration-key>

当 Argo CD 应用程序具有以下订阅时,用户会从寻呼机任务收到应用程序同步失败消息。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    notifications.argoproj.io/subscribe.on-sync-failed.pagerdutyv2: "<serviceID for Pagerduty>"

当在控制器级别配置和应用程序级别配置中定义相同的通知服务和触发器时,两种通知都会根据各自的配置进行发送。

当标志--self-service-notification-enable处于开启状态时,定义和使用通知模板功能中的密钥不可用。

触发器

触发器定义应发送通知的条件。定义包括名称、条件和通知模板引用。条件是一个谓词表达式,如果应发送通知,则返回 true。触发器条件评估由 antonmedv/expr 提供支持。条件语言语法在 language-definition.md 中描述。

触发器在 argocd-notifications-cm ConfigMap 中配置。例如,当使用 app-sync-status 模板的app-sync-status更改为“Unknown”时,以下触发器会发送通知:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  trigger.on-sync-status-unknown: |
    - when: app.status.sync.status == 'Unknown'     # trigger condition
      send: [app-sync-status, github-commit-status] # template names

每个条件可能使用多个模板。通常,每个模板负责生成特定于服务的通知部分。在上面的示例中,app-sync-status 模板“knows”如何创建电子邮件和 Slack 通知,而 github-commit-status 知道如何生成 GitHub webhook 的有效负载。

条件捆绑

触发器通常由管理员管理,并封装有关何时发送通知以及发送哪种通知的信息。最终用户只需订阅触发器并指定通知目的地即可。为了改善用户体验,触发器可能包含多个条件,每个条件都有一组不同的模板。例如,以下触发器涵盖同步状态操作的所有阶段,并针对不同情况使用不同的模板:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  trigger.sync-operation-change: |
    - when: app.status.operationState.phase in ['Succeeded']
      send: [github-commit-status]
    - when: app.status.operationState.phase in ['Running']
      send: [github-commit-status]
    - when: app.status.operationState.phase in ['Error', 'Failed']
      send: [app-sync-failed, github-commit-status]
避免过于频繁地发送相同的通知

在某些情况下,触发条件可能是“抖动(flapping)”。下面的示例说明了这个问题。当 Argo CD 应用程序成功同步且健康时,触发器应该生成一次通知。但是,应用程序健康状态可能会间歇性地切换到“Progressing”,然后又切换回“Healthy”,因此触发器可能会不必要地生成多个通知。oncePer 字段将触发器配置为仅在相应的应用程序字段发生变化时生成通知。下面示例中的on-deployed触发器只会在观察到的部署存储库的 Git 修订版中发送一次通知。

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  # Optional 'oncePer' property ensure that notification is sent only once per specified field value
  # E.g. following is triggered once per sync revision
  trigger.on-deployed: |
    when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy'
    oncePer: app.status.sync.revision
    send: [app-sync-succeeded]
Mono Repo 使用

当使用一个存储库同步多个应用程序时,oncePer: app.status.sync.revision 字段将触发每次提交的通知。对于 mono 存储库,更好的方法是使用 oncePer: app.status.operationState.syncResult.revision 语句。这样,只会针对特定应用程序的修订版发送通知。

oncePer

oncePer 字段的支持如下。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    example.com/version: v0.1
oncePer: app.metadata.annotations["example.com/version"]
默认触发器

可以使用 defaultTriggers 字段,而不是为注释指定单独的触发器。

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  # Holds list of triggers that are used by default if trigger is not specified explicitly in the subscription
  defaultTriggers: |
    - on-sync-status-unknown

  defaultTriggers.mattermost: |
    - on-sync-running
    - on-sync-succeeded

指定注释如下以使用 defaultTriggers。在此示例中,slackon-sync-status-unknown 时发送,mattermoston-sync-runningon-sync-succeeded 时发送。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    notifications.argoproj.io/subscribe.slack: my-channel
    notifications.argoproj.io/subscribe.mattermost: my-mattermost-channel

功能

触发器可以访问一组内置函数。
例子:

when: time.Now().Sub(time.Parse(app.status.operationState.startedAt)).Minutes() >= 5

time
与时间相关的功能。

time.Now() Time
执行 Golang 内置的 time.Now 函数。返回 Golang Time 的一个实例。

time.Parse(val string) Time
使用 RFC3339 布局解析指定的字符串。返回 Golang Time 的一个实例。

字符串
字符串相关函数。
strings.ReplaceAll() string
执行函数内置的Golang strings.ReplaceAll函数。

strings.ToUpper() string
执行函数内置的Golang strings.ToUpper函数。

strings.ToLower() string
执行函数内置的Golang strings.ToLower函数。

sync
sync.GetInfoItem(app map, name string) string 根据给定名称返回存储在 Argo CD App 同步操作中的信息项值。

repo
提供有关应用程序源存储库的附加信息的功能。

repo.RepoURLToHTTPS(url string) string 将给定的 GIT URL 转换为 HTTPs 格式。

repo.FullNameByRepoURL(url string) string 返回存储库 URL 全名 (<owner>/<repoName>)。目前仅支持 Github、GitLab 和 Bitbucket。

repo.QueryEscape(s string) string QueryEscape 对字符串进行转义,因此可以安全地将其放置在 URL 中

例子:

/projects/{{ call .repo.QueryEscape (call .repo.FullNameByRepoURL .app.status.RepoURL) }}/merge_requests

repo.GetCommitMetadata(sha string) CommitMetadata
返回提交元数据。提交必须属于应用程序源存储库。CommitMetadata 字段:

  • Message string - 提交消息
  • Author string - 提交作者
  • Date time.Time - 提交创建日期
  • Tags []string - 相关标签

repo.GetAppDetails() AppDetail
返回应用程序详细信息。AppDetail 字段:

  • Type string - AppDetail 类型
  • Helm HelmAppSpec - Helm详细
  • 属性 :
    • Name string
    • ValueFiles []string
    • Parameters []*v1alpha1.HelmParameter
    • Values string
    • FileParameters []*v1alpha1.HelmFileParameter
  • 方法 :
    • GetParameterValueByName(Name string) 根据参数字段中的名称检索值
    • GetFileParameterPathByName(Name string) 根据 FileParameters 字段中的名称检索路径 *
    • Kustomize *apiclient.KustomizeAppSpec - Kustomize详细
    • Directory *apiclient.DirectoryAppSpec - Directory详细

模板

通知模板用于生成通知内容,并在 argocd-notifications-cm ConfigMap 中配置。该模板利用 html/template golang 包并允许自定义通知消息。模板旨在可重复使用,并可被多个触发器引用。

以下模板用于通知用户应用程序同步状态。

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  template.my-custom-template-slack-template: |
    message: |
      Application {{.app.metadata.name}} sync is {{.app.status.sync.status}}.
      Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.

每个模板都可以访问以下字段:

  • app 保存应用程序对象
  • context 用户定义的字符串映射,可能包含任何字符串键和值。.
  • secrets 提供对存储在 argocd-notifications-secret 中的敏感数据的访问
  • serviceType 保存通知服务类型名称(例如“slack”或“email”)。该字段可用于有条件地呈现特定于服务的字段。
  • recipient 保存收件人姓名。
定义用户定义上下文

可以通过设置键值对的顶级 YAML 文档来定义所有通知模板之间的一些共享上下文,然后可以在模板内使用这些上下文,如下所示:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  context: |
    region: east
    environmentName: staging

  template.a-slack-template-with-context: |
    message: "Something happened in {{ .context.environmentName }} in the {{ .context.region }} data center!"
在通知模板中定义和使用密钥

某些通知服务用例需要在模板中使用密钥。这可以通过使用模板中提供的密钥数据变量来实现。
假设我们有以下 argocd-notifications-secret

apiVersion: v1
kind: Secret
metadata:
  name: argocd-notifications-secret
stringData:
  sampleWebhookToken: secret-token 
type: Opaque

我们可以在模板中使用定义的sampleWebhookToken,如下所示:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  template.trigger-webhook: |
      webhook:
        sample-webhook:
          method: POST
          path: 'webhook/endpoint/with/auth'
          body: 'token={{ .secrets.sampleWebhookToken }}&variables[APP_SOURCE_PATH]={{ .app.spec.source.path }}
通知服务特定字段

模板定义的message字段允许为任何通知服务创建基本通知。可以利用通知服务特定字段来创建复杂通知。例如,使用服务特定字段,可以为 slack 添加块和附件、为电子邮件或 URL 路径添加主题以及为 Webhook 添加正文。有关更多信息,请参阅相应的服务文档

更改时区

可以按如下方式更改通知中显示的时区。

  1. 调用时间功能。
{{ (call .time.Parse .app.status.operationState.startedAt).Local.Format "2006-01-02T15:04:05Z07:00" }}
  1. argocd-notifications-controller 容器上设置 TZ 环境变量。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: argocd-notifications-controller
spec:
  template:
    spec:
      containers:
      - name: argocd-notifications-controller
        env:
        - name: TZ
          value: Asia/Tokyo
功能

模板可以访问一组内置函数:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  template.my-custom-template-slack-template: |
    message: "Author: {{(call .repo.GetCommitMetadata .app.status.sync.revision).Author}}"

同上面功能

触发器和模板目录

触发器

名称描述模板
on-created应用程序已创建.app-created
on-deleted应用程序已删除.app-deleted
on-deployed应用程序已同步且健康.每次提交触发一次。app-deployed
on-health-degraded应用程序已降级app-health-degraded
on-sync-failed应用程序同步失败app-sync-failed
on-sync-running应用程序正在同步app-sync-running
on-sync-status-unknown申请状态为“Unknown”app-sync-status-unknown
on-sync-succeeded应用程序同步成功app-sync-succeeded
模板

app-created

email:
  subject: Application {{.app.metadata.name}} has been created.
message: Application {{.app.metadata.name}} has been created.
teams:
  title: Application {{.app.metadata.name}} has been created.

app-deleted

email:
  subject: Application {{.app.metadata.name}} has been deleted.
message: Application {{.app.metadata.name}} has been deleted.
teams:
  title: Application {{.app.metadata.name}} has been deleted.

app-deployed

email:
  subject: New version of an application {{.app.metadata.name}} is up and running.
message: |
  {{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} is now running new version of deployments manifests.
slack:
  attachments: |
    [{
      "title": "{{ .app.metadata.name}}",
      "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
      "color": "#18be52",
      "fields": [
      {
        "title": "Sync Status",
        "value": "{{.app.status.sync.status}}",
        "short": true
      },
      {
        "title": "Repository",
        "value": "{{.app.spec.source.repoURL}}",
        "short": true
      },
      {
        "title": "Revision",
        "value": "{{.app.status.sync.revision}}",
        "short": true
      }
      {{range $index, $c := .app.status.conditions}}
      ,
      {
        "title": "{{$c.type}}",
        "value": "{{$c.message}}",
        "short": true
      }
      {{end}}
      ]
    }]
  deliveryPolicy: Post
  groupingKey: ""
  notifyBroadcast: false
teams:
  facts: |
    [{
      "name": "Sync Status",
      "value": "{{.app.status.sync.status}}"
    },
    {
      "name": "Repository",
      "value": "{{.app.spec.source.repoURL}}"
    },
    {
      "name": "Revision",
      "value": "{{.app.status.sync.revision}}"
    }
    {{range $index, $c := .app.status.conditions}}
      ,
      {
        "name": "{{$c.type}}",
        "value": "{{$c.message}}"
      }
    {{end}}
    ]
  potentialAction: |-
    [{
      "@type":"OpenUri",
      "name":"Operation Application",
      "targets":[{
        "os":"default",
        "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}"
      }]
    },
    {
      "@type":"OpenUri",
      "name":"Open Repository",
      "targets":[{
        "os":"default",
        "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
      }]
    }]
  themeColor: '#000080'
  title: New version of an application {{.app.metadata.name}} is up and running.

app-health-degraded

email:
  subject: Application {{.app.metadata.name}} has degraded.
message: |
  {{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} has degraded.
  Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
slack:
  attachments: |
    [{
      "title": "{{ .app.metadata.name}}",
      "title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
      "color": "#f4c030",
      "fields": [
      {
        "title": "Health Status",
        "value": "{{.app.status.health.status}}",
        "short": true
      },
      {
        "title": "Repository",
        "value": "{{.app.spec.source.repoURL}}",
        "short": true
      }
      {{range $index, $c := .app.status.conditions}}
      ,
      {
        "title": "{{$c.type}}",
        "value": "{{$c.message}}",
        "short": true
      }
      {{end}}
      ]
    }]
  deliveryPolicy: Post
  groupingKey: ""
  notifyBroadcast: false
teams:
  facts: |
    [{
      "name": "Health Status",
      "value": "{{.app.status.health.status}}"
    },
    {
      "name": "Repository",
      "value": "{{.app.spec.source.repoURL}}"
    }
    {{range $index, $c := .app.status.conditions}}
      ,
      {
        "name": "{{$c.type}}",
        "value": "{{$c.message}}"
      }
    {{end}}
    ]
  potentialAction: |
    [{
      "@type":"OpenUri",
      "name":"Open Application",
      "targets":[{
        "os":"default",
        "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}"
      }]
    },
    {
      "@type":"OpenUri",
      "name":"Open Repository",
      "targets":[{
        "os":"default",
        "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
      }]
    }]
  themeColor: '#FF0000'
  title: Application {{.app.metadata.name}} has degraded.

app-sync-failed

email:
  subject: Failed to sync application {{.app.metadata.name}}.
message: |
  {{if eq .serviceType "slack"}}:exclamation:{{end}}  The sync operation of application {{.app.metadata.name}} has failed at {{.app.status.operationState.finishedAt}} with the following error: {{.app.status.operationState.message}}
  Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .
slack:
  attachments: |
    [{
      "title": "{{ .app.metadata.name}}",
      "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
      "color": "#E96D76",
      "fields": [
      {
        "title": "Sync Status",
        "value": "{{.app.status.sync.status}}",
        "short": true
      },
      {
        "title": "Repository",
        "value": "{{.app.spec.source.repoURL}}",
        "short": true
      }
      {{range $index, $c := .app.status.conditions}}
      ,
      {
        "title": "{{$c.type}}",
        "value": "{{$c.message}}",
        "short": true
      }
      {{end}}
      ]
    }]
  deliveryPolicy: Post
  groupingKey: ""
  notifyBroadcast: false
teams:
  facts: |
    [{
      "name": "Sync Status",
      "value": "{{.app.status.sync.status}}"
    },
    {
      "name": "Failed at",
      "value": "{{.app.status.operationState.finishedAt}}"
    },
    {
      "name": "Repository",
      "value": "{{.app.spec.source.repoURL}}"
    }
    {{range $index, $c := .app.status.conditions}}
      ,
      {
        "name": "{{$c.type}}",
        "value": "{{$c.message}}"
      }
    {{end}}
    ]
  potentialAction: |-
    [{
      "@type":"OpenUri",
      "name":"Open Operation",
      "targets":[{
        "os":"default",
        "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
      }]
    },
    {
      "@type":"OpenUri",
      "name":"Open Repository",
      "targets":[{
        "os":"default",
        "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
      }]
    }]
  themeColor: '#FF0000'
  title: Failed to sync application {{.app.metadata.name}}.

app-sync-running

email:
  subject: Start syncing application {{.app.metadata.name}}.
message: |
  The sync operation of application {{.app.metadata.name}} has started at {{.app.status.operationState.startedAt}}.
  Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .
slack:
  attachments: |
    [{
      "title": "{{ .app.metadata.name}}",
      "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
      "color": "#0DADEA",
      "fields": [
      {
        "title": "Sync Status",
        "value": "{{.app.status.sync.status}}",
        "short": true
      },
      {
        "title": "Repository",
        "value": "{{.app.spec.source.repoURL}}",
        "short": true
      }
      {{range $index, $c := .app.status.conditions}}
      ,
      {
        "title": "{{$c.type}}",
        "value": "{{$c.message}}",
        "short": true
      }
      {{end}}
      ]
    }]
  deliveryPolicy: Post
  groupingKey: ""
  notifyBroadcast: false
teams:
  facts: |
    [{
      "name": "Sync Status",
      "value": "{{.app.status.sync.status}}"
    },
    {
      "name": "Started at",
      "value": "{{.app.status.operationState.startedAt}}"
    },
    {
      "name": "Repository",
      "value": "{{.app.spec.source.repoURL}}"
    }
    {{range $index, $c := .app.status.conditions}}
      ,
      {
        "name": "{{$c.type}}",
        "value": "{{$c.message}}"
      }
    {{end}}
    ]
  potentialAction: |-
    [{
      "@type":"OpenUri",
      "name":"Open Operation",
      "targets":[{
        "os":"default",
        "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
      }]
    },
    {
      "@type":"OpenUri",
      "name":"Open Repository",
      "targets":[{
        "os":"default",
        "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
      }]
    }]
  title: Start syncing application {{.app.metadata.name}}.

app-sync-status-unknown

email:
  subject: Application {{.app.metadata.name}} sync status is 'Unknown'
message: |
  {{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} sync is 'Unknown'.
  Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
  {{if ne .serviceType "slack"}}
  {{range $c := .app.status.conditions}}
      * {{$c.message}}
  {{end}}
  {{end}}
slack:
  attachments: |
    [{
      "title": "{{ .app.metadata.name}}",
      "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
      "color": "#E96D76",
      "fields": [
      {
        "title": "Sync Status",
        "value": "{{.app.status.sync.status}}",
        "short": true
      },
      {
        "title": "Repository",
        "value": "{{.app.spec.source.repoURL}}",
        "short": true
      }
      {{range $index, $c := .app.status.conditions}}
      ,
      {
        "title": "{{$c.type}}",
        "value": "{{$c.message}}",
        "short": true
      }
      {{end}}
      ]
    }]
  deliveryPolicy: Post
  groupingKey: ""
  notifyBroadcast: false
teams:
  facts: |
    [{
      "name": "Sync Status",
      "value": "{{.app.status.sync.status}}"
    },
    {
      "name": "Repository",
      "value": "{{.app.spec.source.repoURL}}"
    }
    {{range $index, $c := .app.status.conditions}}
      ,
      {
        "name": "{{$c.type}}",
        "value": "{{$c.message}}"
      }
    {{end}}
    ]
  potentialAction: |-
    [{
      "@type":"OpenUri",
      "name":"Open Application",
      "targets":[{
        "os":"default",
        "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}"
      }]
    },
    {
      "@type":"OpenUri",
      "name":"Open Repository",
      "targets":[{
        "os":"default",
        "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
      }]
    }]
  title: Application {{.app.metadata.name}} sync status is 'Unknown'

app-sync-succeeded

email:
  subject: Application {{.app.metadata.name}} has been successfully synced.
message: |
  {{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}.
  Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .
slack:
  attachments: |
    [{
      "title": "{{ .app.metadata.name}}",
      "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
      "color": "#18be52",
      "fields": [
      {
        "title": "Sync Status",
        "value": "{{.app.status.sync.status}}",
        "short": true
      },
      {
        "title": "Repository",
        "value": "{{.app.spec.source.repoURL}}",
        "short": true
      }
      {{range $index, $c := .app.status.conditions}}
      ,
      {
        "title": "{{$c.type}}",
        "value": "{{$c.message}}",
        "short": true
      }
      {{end}}
      ]
    }]
  deliveryPolicy: Post
  groupingKey: ""
  notifyBroadcast: false
teams:
  facts: |
    [{
      "name": "Sync Status",
      "value": "{{.app.status.sync.status}}"
    },
    {
      "name": "Synced at",
      "value": "{{.app.status.operationState.finishedAt}}"
    },
    {
      "name": "Repository",
      "value": "{{.app.spec.source.repoURL}}"
    }
    {{range $index, $c := .app.status.conditions}}
      ,
      {
        "name": "{{$c.type}}",
        "value": "{{$c.message}}"
      }
    {{end}}
    ]
  potentialAction: |-
    [{
      "@type":"OpenUri",
      "name":"Operation Details",
      "targets":[{
        "os":"default",
        "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
      }]
    },
    {
      "@type":"OpenUri",
      "name":"Open Repository",
      "targets":[{
        "os":"default",
        "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
      }]
    }]
  themeColor: '#000080'
  title: Application {{.app.metadata.name}} has been successfully synced

监控

Argo CD 通知控制器在端口 9001 上提供 Prometheus 指标。

可以使用 argocd-notifications-controller 部署中的 --metrics-port 标志来更改指标端口。

指标

可用的指标如下:
argocd_notifications_deliveries_total
已发送通知的数量。标签:

  • template - 通知模板名称
  • notifier -通知服务名称
  • succeeded - 指示通知是否发送成功或失败的标志

argocd_notifications_trigger_eval_total
触发器评估的次数。标签:

  • name - 触发器名称
  • triggered - 指示触发条件是否返回真或假的标志

订阅

可以使用notifications.argoproj.io/subscribe.<trigger>.<service>: <recipient>注释定义对Argo CD应用程序事件的订阅。例如,以下注释将两个slack频道订阅有关Argo CD应用程序每次成功同步的通知:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my-channel1;my-channel2
注释键由以下部分组成:
  • on-sync-succeeded - 触发器名称
  • slack - 通知服务名称
  • my-channel1;my-channel2 - 以分号分隔的收件人列表

可以通过向 AppProject 资源添加相同的注释来为 Argo CD 项目的所有应用程序创建订阅:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  annotations:
    notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my-channel1;my-channel2
默认订阅

可以使用 subscriptions 字段在 argocd-notifications-cm ConfigMap 中全局配置订阅。默认订阅适用于所有应用程序。可以使用触发器和选择器字段配置触发器和应用程序:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  # Contains centrally managed global application subscriptions
  subscriptions: |
    # subscription for on-sync-status-unknown trigger notifications
    - recipients:
      - slack:test2
      - email:test@gmail.com
      triggers:
      - on-sync-status-unknown
    # subscription restricted to applications with matching labels only
    - recipients:
      - slack:test3
      selector: test=true
      triggers:
      - on-sync-status-unknown

如果想在订阅中使用 webhook,则需要将自定义 webhook 名称存储在订阅的收件人字段中。

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.webhook.<webhook-name>: |
    (snip)
  subscriptions: |
    - recipients:
      - <webhook-name>
      triggers:
      - on-sync-status-unknown

故障排除

argocd admin notifications 是一个 CLI 命令组,可帮助配置控制器设置和解决问题。完整的命令详细信息可在命令参考中找到。

全局标志

以下全局标志适用于所有子命令:

  • --config-map 包含 argocd-notifications-cm ConfigMap 的文件的路径。如果未指定,则命令使用本地 Kubernetes 配置文件加载 argocd-notification-cm ConfigMap。
  • --secret 包含 argocd-notifications-secret ConfigMap 的文件的路径。如果未指定,则命令使用本地 Kubernetes 配置文件加载 argocd-notification-secret Secret。此外,可以指定 :empty 以使用没有通知服务设置的空 secret。

例子:
获取本地配置映射中配置的触发器列表:

argocd admin notifications trigger get \
  --config-map ./argocd-notifications-cm.yaml --secret :empty

使用集群内配置图和密钥触发通知:

argocd admin notifications template notify \
  app-sync-succeeded guestbook --recipient slack:argocd admin notifications
Kustomize

如果使用 Kustomize 管理 argocd-notifications 配置,则可以使用 --config-map - 标志将整个 kustomize 构建输出传送到 stdin

kustomize build ./argocd-notifications | \
  argocd-notifications \
  template notify app-sync-succeeded guestbook --recipient grafana:argocd \
  --config-map -
如何获取

可以从 GitHub 发布附件中下载 argocd CLI。

二进制文件可在 quay.io/argoproj/argocd 镜像中找到。使用 docker runvolume mount 在任何平台上执行二进制文件。

例如

docker run --rm -it -w /src -v $(pwd):/src \
  quay.io/argoproj/argocd:<version> \
  /app/argocd admin notifications trigger get \
  --config-map ./argocd-notifications-cm.yaml --secret :empty

在集群中
通过 SSH 进入正在运行的 argocd-notifications-controller pod 并使用 kubectl exec 命令来验证集群内配置。

例如

kubectl exec -it argocd-notifications-controller-<pod-hash> \
  /app/argocd admin notifications trigger get
命令

以下命令可能有助于调试通知问题:

argocd admin notifications template get
argocd admin notifications template notify
argocd admin notifications trigger get
argocd admin notifications trigger run
错误

无法解析新设置

  • 将 YAML 转换为 JSON 时出错
    YAML 语法不正确。
    错误:
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.slack: |
    token: $slack-token
    icon: :rocket:

正确:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.slack: |
    token: $slack-token
    icon: ":rocket:"
  • 不支持服务类型‘xxxx’
    需要检查 argocd-notifications 控制器版本。例如,团队集成支持 v1.1.0 及更高版本。

未能通知收件人

  • 不支持通知服务‘xxxx’
    尚未在 argocd-notifications-cm 中定义 xxxx,或者无法解析设置。

通知服务

Alertmanager

AlertManager是一个开源的告警管理工具,主要用于处理来自于监控系统(如Prometheus)的告警。它的设计目标是提供一个统一的告警处理平台,能够集中管理告警的路由、去重、分组和通知等操作。在现代云服务架构中,AlertManager扮演着至关重要的角色,确保关键系统和服务的可靠性和稳定性。

参数
通知服务用于将事件推送到Alertmanager,需要指定以下设置:

  • targets - alertmanager服务地址,数组类型
  • scheme - 可选,默认为“http”,例如 http 或 https
  • apiPath - 可选,默认为“/api/v2/alerts”
  • insecureSkipVerify - 可选,默认为 false,当 scheme 为 https 时是否跳过 ca 验证
  • basicAuth - 可选,服务器认证
  • bearerToken - 可选,服务器认证
  • timeout - 可选,发送警报时使用的超时时间(秒),默认为“3 秒”

使用basicAuth或者bearerToken进行认证,可选其一,若两者同时设置,basicAuth优先于bearerToken。

例子

  • Prometheus Alertmanager 配置
global:
  resolve_timeout: 5m

route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: 'default'
receivers:
- name: 'default'
  webhook_configs:
  - send_resolved: false
    url: 'http://10.5.39.39:10080/api/alerts/webhook'

应该关闭“send_resolved”,否则您将在“resolve_timeout”之后收到不必要的恢复通知。

  • 发送一个无需授权的警报管理器
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.alertmanager: |
    targets:
    - 10.5.39.39:9093
  • 使用自定义 api 路径发送 alertmanager 集群
    如果alertmanager改变了默认api,可以自定义“apiPath”。
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.alertmanager: |
    targets:
    - 10.5.39.39:443
    scheme: https
    apiPath: /api/events
    insecureSkipVerify: true
  • 使用身份验证发送高可用性警报管理器
    将身份验证令牌存储在 argocd-notifications-secret Secret 中,并在 argocd-notifications-cm ConfigMap 中使用配置。
apiVersion: v1
kind: Secret
metadata:
  name: <secret-name>
stringData:
  alertmanager-username: <username>
  alertmanager-password: <password>
  alertmanager-bearer-token: <token>

使用 basicAuth

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.alertmanager: |
    targets:
    - 10.5.39.39:19093
    - 10.5.39.39:29093
    - 10.5.39.39:39093
    scheme: https
    apiPath: /api/v2/alerts
    insecureSkipVerify: true
    basicAuth:
      username: $alertmanager-username
      password: $alertmanager-password   

使用 bearerToken

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.alertmanager: |
    targets:
    - 10.5.39.39:19093
    - 10.5.39.39:29093
    - 10.5.39.39:39093
    scheme: https
    apiPath: /api/v2/alerts
    insecureSkipVerify: true
    bearerToken: $alertmanager-bearer-token
模板
  • labels 至少需要一个标签对,根据alertmanager路由实现不同的通知策略
  • annotations 可选,指定一组信息标签,可用于存储更长的附加信息,但仅用于显示
  • generatorURL 可选,默认为 ‘{{.app.spec.source.repoURL}}’,用于在客户端识别导致此警报的实体的反向链接

label , annotations , generatorURL 值可以模板化。

context: |
  argocdUrl: https://example.com/argocd

template.app-deployed: |
  message: Application {{.app.metadata.name}} has been healthy.
  alertmanager:
    labels:
      fault_priority: "P5"
      event_bucket: "deploy"
      event_status: "succeed"
      recipient: "{{.recipient}}"
    annotations:
      application: '<a href="{{.context.argocdUrl}}/applications/{{.app.metadata.name}}">{{.app.metadata.name}}</a>'
      author: "{{(call .repo.GetCommitMetadata .app.status.sync.revision).Author}}"
      message: "{{(call .repo.GetCommitMetadata .app.status.sync.revision).Message}}"

可以根据标签在Alertmanager上做定向推送。

template.app-deployed: |
  message: Application {{.app.metadata.name}} has been healthy.
  alertmanager:
    labels:
      alertname: app-deployed
      fault_priority: "P5"
      event_bucket: "deploy"

有一个特殊的标签alertname,如果不设置它的值,则默认等于模板名称。

Email

参数
电子邮件通知服务使用 SMTP 协议发送电子邮件通知,并需要指定以下设置:

  • host - SMTP 服务器主机名
  • port - SMTP 服务器端口
  • username - 用户名
  • password - 密码
  • from - 来自电子邮件地址
  • html - 可选 bool,true 或 false
  • insecure_skip_verify - 可选 bool,true 或 false

例子
以下代码片段包含 Gmail 服务配置示例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.email.gmail: |
    username: $email-username
    password: $email-password
    host: smtp.gmail.com
    port: 465
    from: $email-username

无需身份验证:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.email.example: |
    host: smtp.example.com
    port: 587
    from: $email-username
GitHub

参数
GitHub 通知服务使用 GitHub Apps 更改提交状态,并需要指定以下设置:

  • appID - 应用程序 ID
  • installationID - 应用程序安装 ID
  • privateKey - 应用程序私钥
  • enterpriseBaseURL - 可选 URL, 例如 https://git.example.com/

配置

  1. 使用 https://github.com/settings/apps/new 创建 GitHub 应用程序
  2. 更改存储库权限以启用写入提交状态和/或部署和/或拉取请求评论
    在这里插入图片描述
  3. 生成私钥并自动下载
    在这里插入图片描述
  4. 安装应用到帐户
  5. 将 privateKey 存储在 argocd-notifications-secret Secret 中,并在 argocd-notifications-cm ConfigMap 中配置 GitHub 集成
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.github: |
    appID: <app-id>
    installationID: <installation-id>
    privateKey: $github-privateKey
apiVersion: v1
kind: Secret
metadata:
  name: <secret-name>
stringData:
  github-privateKey: |
    -----BEGIN RSA PRIVATE KEY-----
    (snip)
    -----END RSA PRIVATE KEY-----
  1. 为你的 GitHub 集成创建订阅
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    notifications.argoproj.io/subscribe.<trigger-name>.github: ""

例子
在这里插入图片描述

template.app-deployed: |
  message: |
    Application {{.app.metadata.name}} is now running new version of deployments manifests.
  github:
    repoURLPath: "{{.app.spec.source.repoURL}}"
    revisionPath: "{{.app.status.operationState.syncResult.revision}}"
    status:
      state: success
      label: "continuous-delivery/{{.app.metadata.name}}"
      targetURL: "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
    deployment:
      state: success
      environment: production
      environmentURL: "https://{{.app.metadata.name}}.example.com"
      logURL: "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
      requiredContexts: []
      autoMerge: true
      transientEnvironment: false
      reference: v1.0.0
    pullRequestComment:
      content: |
        Application {{.app.metadata.name}} is now running new version of deployments manifests.
        See more here: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true

笔记:

  • 如果消息设置为 140 个字符或更多,它将被截断。
  • 如果github.repoURLPathgithub.revisionPath与上面相同,则可以省略。
  • Automerge 是可选的,默认情况下对于 GitHub 部署为 true,以确保请求的引用与默认分支保持同步。如果在默认分支中部署较旧的引用,则需要将此选项设置为 false。有关更多信息,请参阅 GitHub 部署 API 文档
  • 如果 github.pullRequestComment.content 设置为 65536 个字符或更多,它将被截断。
  • Reference 是可选的。设置后,将作为部署的参考。如果不设置,则将使用修订版本作为部署的参考。

故障排除工具

该文档描述了如何使用 argocd 管理子命令来简化 Argo CD 设置自定义和解决连接问题。

设置

Argo CD 提供了多种自定义系统行为的方法,并且有很多设置。修改多个用户在生产中使用的 Argo CD 设置可能会很危险。在应用设置之前,可以使用 argocd admin 子命令来确保设置有效并且 Argo CD 正常运行。

argocd admin settings verify 命令执行基本设置验证并打印每个设置组的简短摘要。

差异定制
差异定制允许从差异过程中排除某些资源字段。差异定制在 argocd-cm ConfigMap 的 resource.customizations 字段中配置。

以下 argocd admin命令打印有关指定 ConfigMap 中排除差异的字段的信息。

argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argocd-cm-path ./argocd-cm.yaml

健康评估
Argo CD 为多种 Kubernetes 资源提供内置健康评估,可以通过在 Lua 中编写自己的健康检查来进一步定制这些资源。健康检查在 argocd-cm ConfigMap 的 resource.customizations 字段中配置。

以下 argocd 管理命令使用在指定 ConfigMap 中配置的 Lua 脚本评估资源健康状况。

argocd admin settings resource-overrides health ./deploy.yaml --argocd-cm-path ./argocd-cm.yaml

资源操作
资源操作允许配置执行资源修改的命名 Lua 脚本。

以下 argocd 管理命令使用在指定的 ConfigMap 中配置的 Lua 脚本执行操作并打印应用的修改。

argocd admin settings resource-overrides run-action /tmp/deploy.yaml restart --argocd-cm-path /private/tmp/argocd-cm.yaml

以下 argocd admin 命令使用在指定 ConfigMap 中配置的 Lua 脚本列出可用于给定资源的操作。

argocd admin settings resource-overrides list-actions /tmp/deploy.yaml --argocd-cm-path /private/tmp/argocd-cm.yaml

集群凭证
如果使用集群凭据手动创建 Secret 并尝试解决连接问题,则 argocd 管理员集群 kubeconfig 很有用。在这种情况下,建议使用以下步骤:

  1. 通过 SSH 进入 [argocd-application-controller] pod。
kubectl exec -n argocd -it \
  $(kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-application-controller -o jsonpath='{.items[0].metadata.name}') bash
  1. 使用 argocd admin cluster kubeconfig 命令从配置的 Secret 中导出 kubeconfig 文件:
argocd admin cluster kubeconfig https://<api-server-url> /tmp/kubeconfig --namespace argocd
  1. 使用 kubectl 获取有关连接问题的更多详细信息,修复它们并将更改应用回 secret:
export KUBECONFIG=/tmp/kubeconfig
kubectl get pods -v 9

ApplicationSet

简介

ApplicationSet 控制器是一个 Kubernetes 控制器,它添加了对 ApplicationSet CustomResourceDefinition (CRD) 的支持。此控制器/CRD 可实现自动化和更大的灵活性,从而跨大量集群和 monorepos 管理 Argo CD 应用程序,此外,它还使在多租户 Kubernetes 集群上实现自助服务成为可能。

ApplicationSet 控制器与现有的 Argo CD 安装一起工作。Argo CD 是一种声明式 GitOps 持续交付工具,它允许开发人员在现有的 Git 工作流中定义和控制 Kubernetes 应用程序资源的部署。

从 Argo CD v2.3 开始,ApplicationSet 控制器与 Argo CD 捆绑在一起。

ApplicationSet 控制器通过添加其他功能来补充 Argo CD,以支持以集群管理员为中心的场景。ApplicationSet 控制器提供:

  • 能够使用单个 Kubernetes 清单通过 Argo CD 定位多个 Kubernetes 集群
  • 能够使用单个 Kubernetes 清单通过 Argo CD 从一个或多个 Git 存储库部署多个应用程序
  • 改进了对 monorepos 的支持:在 Argo CD 上下文中,monorepo 是在单个 Git 存储库中定义的多个 Argo CD 应用程序资源
  • 在多租户集群中,提高单个集群租户使用 Argo CD 部署应用程序的能力(无需让特权集群管理员参与启用目标集群/命名空间)

在使用 ApplicationSet 之前请注意其安全隐患。

ApplicationSet 资源

此示例定义了一种 ApplicationSet 类型的新guestbook资源:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - list:
      elements:
      - cluster: engineering-dev
        url: https://1.2.3.4
      - cluster: engineering-prod
        url: https://2.4.6.8
      - cluster: finance-preprod
        url: https://9.8.7.6
  template:
    metadata:
      name: '{{.cluster}}-guestbook'
    spec:
      project: my-project
      source:
        repoURL: https://github.com/infra-team/cluster-deployments.git
        targetRevision: HEAD
        path: guestbook/{{.cluster}}
      destination:
        server: '{{.url}}'
        namespace: guestbook

在这个例子中,将我们的guestbook应用程序(该应用程序的 Kubernetes 资源来自 Git,因为这是 GitOps)部署到 Kubernetes 集群列表(目标集群列表在 ApplicationSet 资源的 List items 元素中定义)。

虽然有多种类型的生成器可用于 ApplicationSet 资源,但此示例使用 List 生成器,它仅包含要定位的固定集群文字列表。一旦 ApplicationSet 控制器处理了 ApplicationSet 资源,此集群列表将成为 Argo CD 在其上部署留言簿应用程序资源的集群。

生成器(例如 List 生成器)负责生成参数。参数是键值对,在模板渲染期间会替换到 ApplicationSet 资源的 template: 部分中。

ApplicationSet 控制器当前支持多个生成器:

  • 列表生成器:根据固定的集群名称/URL 值列表生成参数,如上例所示。
  • 集群生成器:集群生成器不会生成集群的文字列表(与列表生成器不同),而是根据 Argo CD 中定义的集群自动生成集群参数。
  • Git 生成器:Git 生成器根据生成器资源内定义的 Git 存储库中包含的文件或文件夹生成参数。
    • 包含 JSON 值的文件将被解析并转换为模板参数。
    • Git 存储库中的各个目录路径也可以用作参数值。
  • 矩阵生成器:矩阵生成器结合了另外两个生成器生成的参数。

有关单个生成器以及上面未列出的其他生成器的更多信息,请参阅生成器部分

模板中的参数替换

无论使用哪个生成器,生成器生成的参数都会替换为 ApplicationSet 资源的 template: 部分中的 {{parameter name}} 值。在此示例中,List 生成器定义了 clusterurl 参数,然后分别替换为模板的 {{cluster}}{{url}}值。

替换后,此guestbook ApplicationSet资源将应用到Kubernetes集群中:

  1. ApplicationSet 控制器处理生成器条目,生成一组模板参数。
  2. 这些参数被代入模板中,每组参数代入一次。
  3. 每个渲染的模板都转换为 Argo CD 应用程序资源,然后在 Argo CD 命名空间内创建(或更新)。
  4. 最后,Argo CD 控制器会收到这些应用程序资源的通知并负责处理它们。

在我们的示例中定义了三个不同的集群——engineering-dev、engineering-prod 和 finance-preprod——这将产生三个新的 Argo CD 应用程序资源:每个集群一个。

以下是针对 1.2.3.4 的 engineering-dev 集群创建的应用程序资源之一的示例:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: engineering-dev-guestbook
spec:
  source:
    repoURL: https://github.com/infra-team/cluster-deployments.git
    targetRevision: HEAD
    path: guestbook/engineering-dev
  destination:
    server: https://1.2.3.4
    namespace: guestbook

我们可以看到,生成的值已替换到模板的服务器和路径字段中,并且模板已呈现为完整的 Argo CD 应用程序。

现在也可以从 Argo CD UI 中看到这些应用程序:
在这里插入图片描述
ApplicationSet 控制器将确保对 ApplicationSet 资源所做的任何更改、更新或删除都自动应用于相应的应用程序。

例如,如果将新的集群/URL 列表条目添加到列表生成器,则会为该新集群创建新的 Argo CD 应用程序资源。对留言簿应用程序集资源所做的任何编辑都将影响由该资源实例化的所有 Argo CD 应用程序,包括新应用程序。

尽管 List 生成器的集群文字列表相当简单,但 ApplicationSet 控制器中的其他可用生成器支持更复杂的场景。

安装

本指南假设您熟悉 Argo CD 及其基本概念。请参阅 Argo CD 文档了解更多信息。

前提
  • 已安装 kubectl 命令行工具
  • 有一个 kubeconfig 文件(默认位置是 ~/.kube/config)。
安装

安装 ApplicationSet 控制器有几个选项。

A) 安装 ApplicationSet 作为 Argo CD 的一部分
从 Argo CD v2.3 开始,ApplicationSet 控制器与 Argo CD 捆绑在一起。不再需要单独安装 ApplicationSet 控制器,而只需在 Argo CD 中安装即可。

请按照 Argo CD 入门说明获取更多信息。

B) 将 ApplicationSet 安装到现有的 Argo CD 安装中(Argo CD v2.3 之前版本)
注意:这些说明仅适用于 v2.3.0 之前的 Argo CD 版本。

ApplicationSet 控制器必须安装到与其目标 Argo CD 相同的命名空间中。

假设 Argo CD 安装到 argocd 命名空间中,运行以下命令:

kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/applicationset/v0.4.0/manifests/install.yaml

一旦安装,ApplicationSet 控制器不需要额外的设置。

manifests/install.yaml 文件包含安装 ApplicationSet 控制器所需的 Kubernetes 清单(manifests):

  • ApplicationSet 资源的 CustomResourceDefinition
  • argocd-applicationset-controller 的部署
  • ServiceAccount 供 ApplicationSet 控制器使用,用于访问 Argo CD 资源
  • 为 ServiceAccount 授予 RBAC 对所需资源的访问权限的角色
  • RoleBinding 绑定 ServiceAccount 和 Role
启用高可用性模式

为了实现高可用性,必须在 argocd-applicationset-controller 容器中设置命令 --enable-leader-election=true 并增加副本。
manifests/install.yaml 中做以下更改

    spec:
      containers:
      - command:
        - entrypoint.sh
        - argocd-applicationset-controller
        - --enable-leader-election=true
可选:额外的升级后保障措施

有关可能希望添加到 install.yaml 中的 ApplicationSet 资源的其他参数的信息,请参阅控制资源修改页面,以便针对任何初始的、意外的升级后行为提供额外的安全性。

例如,为了暂时阻止升级后的 ApplicationSet 控制器进行任何更改,您可以:

  • 启用 dry-run
  • 使用create-only策略
  • 在 ApplicationSets 上启用 preserveResourcesOnDeletion
  • 在 ApplicationSets 模板中暂时禁用自动同步

这些参数将允许observe/control环境中新版本 ApplicationSet 控制器的行为,以确保对结果满意(有关详细信息,请参阅 ApplicationSet 日志文件)。测试完成后,请不要忘记删除任何临时更改!

但是,如上所述,这些步骤并非绝对必要:升级 ApplicationSet 控制器应该是一个微创过程,并且这些步骤仅作为额外安全的可选预防措施而建议。

下一步

一旦 ApplicationSet 控制器启动并运行,请继续使用案例来了解有关支持的场景的更多信息,或者直接继续生成器来查看示例 ApplicationSet 资源。

ApplicationSet 控制器支持的用例

借助生成器的概念,ApplicationSet 控制器提供了一套强大的工具来自动完成 Argo CD 应用程序的模板化和修改。生成器从各种来源(包括 Argo CD 集群和 Git 存储库)生成模板参数数据,支持和启用新的用例。

虽然这些工具可用于任何需要的目的,但这里是 ApplicationSet 控制器设计用于支持的一些特定用例。

用例:集群附加组件

ApplicationSet 控制器的初始设计重点是让基础设施团队的 Kubernetes 集群管理员能够自动创建大量不同的 Argo CD 应用程序,这些应用程序分布在大量集群中,并将这些应用程序作为一个单元进行管理。集群附加组件用例就是需要此功能的一个例子。

在集群附加组件用例中,管理员负责为一个或多个 Kubernetes 集群配置集群附加组件:cluster-addons 是操作员(例如 Prometheus 操作员)或控制器(例如 argo-workflows 控制器(Argo 生态系统的一部分))。

通常,开发团队的应用程序需要这些附加组件(例如,作为多租户集群的租户,他们可能希望向 Prometheus 提供指标数据或通过 Argo Workflows 协调工作流)。

由于安装这些附加组件需要各个开发团队不具备的集群级权限,因此安装是组织的基础架构/运营团队的责任,在大型组织内,该团队可能负责数十、数百或数千个 Kubernetes 集群(定期添加/修改/删除新的集群)。

跨大量集群进行扩展以及自动响应新集群的生命周期的需求必然要求某种形式的自动化。另一个要求是允许使用特定标准(例如,staging 与 production)将附加组件定位到集群子集。

在这里插入图片描述
在此示例中,基础设施团队维护一个 Git 存储库,其中包含 Argo Workflows 控制器和 Prometheus 操作员的应用程序清单。

基础设施团队希望使用 Argo CD 将这两个附加组件部署到大量集群,并且希望轻松管理新集群的创建/删除。

在这个用例中,我们可以使用 ApplicationSet 控制器的 List、Cluster 或 Git 生成器来提供所需的行为:

  • 列表生成器:管理员维护两个 ApplicationSet 资源,每个应用程序(工作流和 Prometheus)一个,并在每个应用程序的列表生成器元素中包含他们希望定位的集群列表。
    • 使用此生成器,添加/删除集群需要手动更新 ApplicationSet 资源的列表元素。
  • 集群生成器:管理员维护两个 ApplicationSet 资源,每个应用程序一个(Workflows 和 Prometheus),并确保所有新集群都在 Argo CD 中定义。
    • 由于 Cluster 生成器会自动检测并定位 Argo CD 中定义的集群,因此从 Argo CD 中添加/删除集群将自动导致 ApplicationSet 控制器创建 Argo CD 应用程序资源(针对每个应用程序)。
    • Git 生成器:Git 生成器是最灵活/最强大的生成器,因此有多种不同的方法来解决此用例。以下是几种:
      • 使用 Git 生成器文件字段:集群列表以 JSON 文件的形式保存在 Git 存储库中。通过 Git 提交对 JSON 文件的更新会导致添加/删除新集群。
      • 使用 Git 生成器目录字段:对于每个目标集群,Git 存储库中都存在一个同名的对应目录。通过 Git 提交添加/修改目录将触发共享目录名称的集群的更新。

有关每个生成器的详细信息,请参阅生成器部分。

用例:monorepos

在 monorepo 用例中,Kubernetes 集群管理员从单个 Git 存储库管理单个 Kubernetes 集群的整个状态。

合并到 Git 存储库的清单更改应自动部署到集群。

在这里插入图片描述
在此示例中,基础设施团队维护一个 Git 存储库,其中包含 Argo Workflows 控制器和 Prometheus 操作员的应用程序清单。独立开发团队还添加了他们希望部署到集群的其他服务。

对 Git 存储库所做的更改(例如,更新已部署工件的版本)应自动导致 Argo CD 将该更新应用于相应的 Kubernetes 集群。
Git 生成器可用于支持此用例:

  • Git 生成器目录字段可用于指定包含要部署的各个应用程序的特定子目录(使用通配符)。
  • Git 生成器文件字段可能引用包含 JSON 元数据的 Git 存储库文件,该元数据描述要部署的各个应用程序。
  • 有关更多详细信息,请参阅 Git 生成器文档。
用例:多租户集群上的 Argo CD 应用程序自助服务

自助服务用例旨在让开发人员(作为多租户 Kubernetes 集群的最终用户)更灵活地:

  • 使用 Argo CD 以自动化方式将多个应用程序部署到单个集群
  • 使用 Argo CD 以自动化方式部署到多个集群
  • 但是,在这两种情况下,为了让这些开发人员能够这样做,而无需集群管理员的参与(为他们创建必要的 Argo CD 应用程序/AppProject 资源)

该用例的一个潜在解决方案是让开发团队在 Git 存储库(包含他们希望部署的清单)中以应用程序的模式定义 Argo CD Application资源,然后让集群管理员通过合并请求审查/接受对此存储库的更改。

虽然这听起来像是一种有效的解决方案,但它的主要缺点是,需要高度的信任/审查才能接受包含 Argo CD 应用程序规范更改的提交。这是因为Application规范中包含许多敏感字段,包括project, cluster, namespace。无意的合并可能会允许应用程序访问它们不属于的命名空间/集群。

因此,在自助服务用例中,管理员希望仅允许开发人员控制Application规范的某些字段(例如 Git 源存储库),但不控制其他字段(例如,应该限制目标命名空间或目标集群)。

幸运的是,ApplicationSet 控制器为这种用例提供​​了另一种解决方案:集群管理员可以安全地创建一个包含 Git 生成器的 ApplicationSet 资源,该生成器使用template字段将应用程序资源的部署限制为固定值,同时允许开发人员随意定制“safe”字段。

config.json 文件包含描述应用程序的信息。

{
  (...)
  "app": {
    "source": "https://github.com/argoproj/argo-cd",
    "revision": "HEAD",
    "path": "applicationset/examples/git-generator-files-discovery/apps/guestbook"
  }
  (...)
}
kind: ApplicationSet
# (...)
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: https://github.com/argoproj/argo-cd.git
      files:
      - path: "apps/**/config.json"
  template:
    spec:
      project: dev-team-one # project is restricted
      source:
        # developers may customize app details using JSON files from above repo URL
        repoURL: {{.app.source}}
        targetRevision: {{.app.revision}}
        path: {{.app.path}}
      destination:
        name: production-cluster # cluster is restricted
        namespace: dev-team-one # namespace is restricted

有关更多详细信息,请参阅 Git 生成器

应用程序集安全

ApplicationSet 是一个强大的工具,在使用它之前了解它的安全隐患至关重要。

只有管​​理员可以创建/更新/删除 ApplicationSet

ApplicationSets 可以在任意项目下创建应用程序。Argo CD 设置通常包括具有高级别权限的项目(例如默认项目),通常包括管理 Argo CD 本身资源的能力(如 RBAC ConfigMap)。

ApplicationSets 还可以快速创建任意数量的应用程序并快速删除它们。

最后,ApplicationSets 可以泄露特权信息。例如,git 生成器可以读取 Argo CD 命名空间中的 Secrets,并将它们作为 auth 标头发送到任意 URL(例如为 api 字段提供的 URL)。(此功能旨在授权向 GitHub 等 SCM 提供商发出请求,但可能会被恶意用户滥用。)

出于这些原因,只有管理员才可以被授予权限(通过 Kubernetes RBAC 或任何其他机制)来创建、更新或删除 ApplicationSet。

管理员必须对 ApplicationSets 的真实来源应用适当的控制

即使非管理员无法创建 ApplicationSet 资源,他们也可能影响 ApplicationSet 的行为。

例如,如果 ApplicationSet 使用 git 生成器,则具有源 git 存储库推送权限的恶意用户可能会生成过多的应用程序,从而给 ApplicationSet 和应用程序控制器带来压力。他们还可能导致 SCM 提供程序的速率限制启动,从而降低 ApplicationSet 服务的性能。

模板化项目字段

特别要注意项目字段模板化的 ApplicationSet。对生成器真实来源具有写入权限的恶意用户(例如,对 git 生成器的 git 存储库具有推送权限的人)可以在限制不足的项目下创建应用程序。能够在无限制项目(如默认项目)下创建应用程序的恶意用户可以通过修改其 RBAC ConfigMap 等方式控制 Argo CD 本身。

如果项目字段不是在 ApplicationSet 的模板中硬编码的,那么管理员必须控制 ApplicationSet 生成器的所有真实来源。

ApplicationSet 控制器如何与 Argo CD 交互

当创建、更新或删除 ApplicationSet 资源时,ApplicationSet 控制器会通过创建、更新或删除一个或多个相应的 Argo CD 应用程序资源来做出响应。

实际上,ApplicationSet 控制器的唯一职责是在 Argo CD 命名空间内创建、更新和删除应用程序资源。控制器的唯一工作是确保应用程序资源与定义的声明性 ApplicationSet 资源保持一致,仅此而已。

因此 ApplicationSet 控制器:

  • 不创建/修改/删除 Kubernetes 资源(应用程序 CR 除外)
  • 不连接到除 Argo CD 部署到的集群之外的其他集群
  • 不与除 Argo CD 部署所在的命名空间之外的其他命名空间交互

所有 ApplicationSet 资源和 ApplicationSet 控制器必须安装在与 Argo CD 相同的命名空间中。不同命名空间中的 ApplicationSet 资源将被忽​​略。

Argo CD 本身负责生成的子Application资源(例如部署、服务和配置地图)的实际部署。

因此,可以将 ApplicationSet 控制器视为应用程序“工厂”,以 ApplicationSet 资源作为输入,并输出一个或多个与该集合的参数相对应的 Argo CD 应用程序资源。

在这里插入图片描述
在此图中,定义了一个 ApplicationSet 资源,ApplicationSet 控制器负责创建相应的 Application 资源。然后,生成的 Application 资源由 Argo CD 管理:也就是说,Argo CD 负责实际部署子资源。

Argo CD 根据Application spec字段中定义的 Git 存储库的内容生成应用程序的 Kubernetes 资源,例如部署、服务和其他资源。

创建、更新或删除 ApplicationSet 将直接影响 Argo CD 命名空间中存在的应用程序。同样,集群事件(使用集群生成器时添加/删除 Argo CD 集群密钥)或 Git 中的更改(使用 Git 生成器时)将用作 ApplicationSet 控制器在构建Application资源时的输入。

Argo CD 和 ApplicationSet 控制器协同工作,以确保存在一组一致的应用程序资源,并部署在目标集群中。

生成器

生成器负责生成参数,然后将其呈现到 ApplicationSet 资源的template:字段中。请参阅简介,了解生成器如何与模板配合使用以创建 Argo CD 应用程序的示例。

生成器主要基于它们用于生成模板参数的数据源。例如:列表生成器从文字列表中提供一组参数,集群生成器使用 Argo CD 集群列表作为源,Git 生成器使用 Git 存储库中的文件/目录,等等。

截至撰写本文时,共有 9 个生成器:

  • List generator: 列表生成器允许根据任何选定的键/值元素对的固定列表将 Argo CD 应用程序定位到集群。
  • Cluster generator: 集群生成器允许根据 Argo CD 内定义(并由 Argo CD 管理)的集群列表(包括自动响应 Argo CD 的集群添加/删除事件)将 Argo CD 应用程序定位到集群。
  • Git generator: Git 生成器允许您基于 Git 存储库中的文件或基于 Git 存储库的目录结构创建应用程序。
  • Matrix generator: 矩阵生成器可用于组合两个独立生成器的生成参数。
  • Merge generator: 合并生成器可用于合并两个或多个生成器生成的参数。附加生成器可以覆盖基础生成器的值。
  • SCM Provider generator: SCM 提供程序生成器使用 SCM 提供程序(例如 GitHub)的 API 来自动发现组织内的存储库。
  • Pull Request generator: Pull Request 生成器使用 SCMaaS 提供商(例如 GitHub)的 API 来自动发现存储库中的开放 Pull 请求。
  • Cluster Decision Resource generator: 集群决策资源生成器用于与 Kubernetes 自定义资源交互,该资源使用自定义资源特定逻辑来决定部署到哪组 Argo CD 集群。
  • Plugin generator: 插件生成器发出 RPC HTTP 请求来提供参数。

可以使用后选择器过滤所有生成器

列表生成器

List 生成器根据任意的键/值对列表生成参数(只要值是字符串值即可)。在此示例中,我们的目标是名为 engineering-dev 的本地集群:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - list:
      elements:
      - cluster: engineering-dev
        url: https://kubernetes.default.svc
      - cluster: engineering-prod
        url: https://kubernetes.default.svc
  template:
    metadata:
      name: '{{.cluster}}-guestbook'
    spec:
      project: "my-project"
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: applicationset/examples/list-generator/guestbook/{{.cluster}}
      destination:
        server: '{{.url}}'
        namespace: guestbook

(完整示例可在此处找到。)

在此示例中,List 生成器将 urlcluster 字段作为参数传递到模板中。如果我们想添加第二个环境,我们可以取消注释第二个元素,ApplicationSet 控制器会自动将其定位到定义的应用程序。

在 ApplicationSet v0.1.0 版本中,只能指定 urlcluster 元素字段(以及任意values)。从 ApplicationSet v0.2.0 开始,支持任何键/值元素对(也完全向后兼容 v0.1.0 格式):

spec:
  generators:
  - list:
      elements:
        # v0.1.0 form - requires cluster/url keys:
        - cluster: engineering-dev
          url: https://kubernetes.default.svc
          values:
            additional: value
        # v0.2.0+ form - does not require cluster/URL keys
        # (but they are still supported).
        - staging: "true"
          gitRepo: https://kubernetes.default.svc   
# (...)

这些集群必须已在 Argo CD 中定义,以便为这些值生成应用程序。ApplicationSet 控制器不会在 Argo CD 中创建集群(例如,它没有这样做的凭证)。

动态生成的元素

列表生成器还可以根据从以前的生成器(如 git)获得的 yaml/json 动态生成其元素,方法是将两者与矩阵生成器相结合。在此示例中,我们将矩阵生成器与 git 结合使用,然后使用列表生成器,并将 git 中文件的内容作为输入传递给列表生成器的 elementsYaml 字段:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: elementsYaml
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - matrix:
      generators:
      - git:
          repoURL: https://github.com/argoproj/argo-cd.git
          revision: HEAD
          files:
          - path: applicationset/examples/list-generator/list-elementsYaml-example.yaml
      - list:
          elementsYaml: "{{ .key.components | toJson }}"
  template:
    metadata:
      name: '{{.name}}'
    spec:
      project: default
      syncPolicy:
        automated:
          selfHeal: true    
        syncOptions:
        - CreateNamespace=true        
      sources:
        - chart: '{{.chart}}'
          repoURL: '{{.repoUrl}}'
          targetRevision: '{{.version}}'
          helm:
            releaseName: '{{.releaseName}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{.namespace}}'

其中 list-elementsYaml-example.yaml 内容为:

key:
  components:
    - name: component1
      chart: podinfo
      version: "6.3.2"
      releaseName: component1
      repoUrl: "https://stefanprodan.github.io/podinfo"
      namespace: component1
    - name: component2
      chart: podinfo
      version: "6.3.3"
      releaseName: component2
      repoUrl: "ghcr.io/stefanprodan/charts"
      namespace: component2
集群生成器

在 Argo CD 中,托管集群存储在 Argo CD 命名空间中的 Secrets 中。ApplicationSet 控制器使用相同的 Secrets 生成参数来识别和定位可用集群。

对于使用 Argo CD 注册的每个集群,集群生成器都会根据集群密钥中找到的项目列表生成参数。

它会自动向每个集群的应用程序模板提供以下参数值:

  • name
  • nameNormalized (‘name’ 但规范化为仅包含小写字母数字字符’-'或.
  • server
  • metadata.labels.<key> (对于 Secret 中的每个标签)
  • metadata.annotations.<key> (对于 Secret 中的每个注释)

如果集群名称包含对 Kubernetes 资源名称无效的字符(例如下划线),请使用 nameNormalized 参数。这可防止呈现名称为 my_cluster-app1 的无效 Kubernetes 资源,而是将其转换为 my-cluster-app1。

Argo CD 集群密钥中包括描述集群的数据字段:

kind: Secret
data:
  # Within Kubernetes these fields are actually encoded in Base64; they are decoded here for convenience.
  # (They are likewise decoded when passed as parameters by the Cluster generator)
  config: "{'tlsClientConfig':{'insecure':false}}"
  name: "in-cluster2"
  server: "https://kubernetes.default.svc"
metadata:
  labels:
    argocd.argoproj.io/secret-type: cluster
# (...)

集群生成器将自动识别用 Argo CD 定义的集群,并提取集群数据作为参数:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - clusters: {} # Automatically use all clusters defined within Argo CD
  template:
    metadata:
      name: '{{.name}}-guestbook' # 'name' field of the Secret
    spec:
      project: "my-project"
      source:
        repoURL: https://github.com/argoproj/argocd-example-apps/
        targetRevision: HEAD
        path: guestbook
      destination:
        server: '{{.server}}' # 'server' field of the secret
        namespace: guestbook

(完整示例可在此处找到。)

在此示例中,集群密钥的名称和服务器字段用于填充应用程序资源名称和服务器(然后用于定位同一个集群)。

标签选择器

标签选择器可用于将目标集群的范围缩小到仅与特定标签匹配的集群:

kind: ApplicationSet
metadata:
  name: guestbook
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - clusters:
      selector:
        matchLabels:
          staging: true
        # The cluster generator also supports matchExpressions.
        #matchExpressions:
        #  - key: staging
        #    operator: In
        #    values:
        #      - "true"
  template:
  # (...)

这将匹配包含以下内容的 Argo CD 集群密钥:

kind: Secret
data:
  # (... fields as above ...)
metadata:
  labels:
    argocd.argoproj.io/secret-type: cluster
    staging: "true"
# (...)

集群选择器还支持基于集合的要求,正如几个核心 Kubernetes 资源所使用的那样。

部署到本地集群

在 Argo CD 中,“local cluster”是安装 Argo CD(和 ApplicationSet 控制器)的集群。这是为了将其与“remote clusters”区分开来,后者是通过声明方式或通过 Argo CD CLI 添加到 Argo CD 的集群。

对于与集群选择器匹配的每个集群,集群生成器将自动定位本地集群和非本地集群。

如果希望仅将应用程序定位到远程集群(例如,想要排除本地集群),那么请使用带有标签的集群选择器,例如:

spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - clusters:
      selector:
        matchLabels:
          argocd.argoproj.io/secret-type: cluster
        # The cluster generator also supports matchExpressions.
        #matchExpressions:
        #  - key: staging
        #    operator: In
        #    values:
        #      - "true"

此选择器不会匹配默认本地集群,因为默认本地集群没有 Secret(因此该 Secret 上没有argocd.argoproj.io/secret-type 标签)。任何选择该标签的集群选择器都会自动排除默认本地集群。

但是,如果确实希望同时定位本地和非本地集群,同时使用标签匹配,则可以在 Argo CD Web UI 中为本地集群创建一个密钥:

  1. 在 Argo CD Web UI 中,选择“Settings”,然后选择“Clusters”。
  2. 选择本地集群,通常名为 in-cluster
  3. 单击“Edit”按钮,将集群的名称更改为其他值,例如 in-cluster-local。此处的任何其他值都可以。
  4. 保持其他所有字段不变。
  5. 点击“Save”

这些步骤可能看起来违反直觉,但更改本地集群的默认值之一会导致 Argo CD Web UI 为该集群创建新的密钥。在 Argo CD 命名空间中,现在应该会看到一个名为 cluster-(集群后缀)的密钥资源,标签为 argocd.argoproj.io/secret-type": "cluster"。您还可以声明性地创建本地集群密钥,或者使用 CLI 使用 argocd cluster add "(context name)" --in-cluster,而不是通过 Web UI。

根据 K8s 版本获取集群

还可以根据 Kubernetes 版本获取集群。为此,需要在集群密钥上将标签 argocd.argoproj.io/auto-label-cluster-info 设置为 true。设置完成后,控制器将使用集群密钥所运行的 Kubernetes 版本动态标记集群密钥。要检索该值,需要使用 argocd.argoproj.io/kubernetes-version,如下例所示:

spec:
  goTemplate: true
  generators:
  - clusters:
      selector:
        matchLabels:
          argocd.argoproj.io/kubernetes-version: 1.28
        # matchExpressions are also supported.
        #matchExpressions:
        #  - key: argocd.argoproj.io/kubernetes-version
        #    operator: In
        #    values:
        #      - "1.27"
        #      - "1.28"
通过values字段传递额外的键值对

可以通过集群生成器的 values 字段传递其他任意字符串键值对。通过 values 字段添加的值将作为values.(field)

在此示例中,根据集群密钥上的匹配标签传递了revision参数值:

spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - clusters:
      selector:
        matchLabels:
          type: 'staging'
      # A key-value map for arbitrary parameters
      values:
        revision: HEAD # staging clusters use HEAD branch
  - clusters:
      selector:
        matchLabels:
          type: 'production'
      values:
        # production uses a different revision value, for 'stable' branch
        revision: stable
  template:
    metadata:
      name: '{{.name}}-guestbook'
    spec:
      project: "my-project"
      source:
        repoURL: https://github.com/argoproj/argocd-example-apps/
        # The cluster values field for each generator will be substituted here:
        targetRevision: '{{.values.revision}}'
        path: guestbook
      destination:
        server: '{{.server}}'
        namespace: guestbook

在此示例中,来自 generators.clusters 字段的revision值作为 values.revision 传递到模板中,包含 HEADstable(基于哪个生成器生成参数集)。

values. 前缀始终添加到通过 generators.clusters.values 字段提供的值前面。使用时,请确保将此前缀包含在template中的参数名称中。

values中我们还可以插入以下参数值(即与本页开头所示的值相同)

  • name
  • nameNormalized (‘name’ 但规范化为仅包含小写字母数字字符’-‘或’.’ )
  • server
  • metadata.labels.<key> (对于 Secret 中的每个标签)
  • metadata.annotations.<key> (对于 Secret 中的每个注释)

扩展上面的例子,我们可以做这样的事情:

spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - clusters:
      selector:
        matchLabels:
          type: 'staging'
      # A key-value map for arbitrary parameters
      values:
        # If `my-custom-annotation` is in your cluster secret, `revision` will be substituted with it.
        revision: '{{index .metadata.annotations "my-custom-annotation"}}' 
        clusterName: '{{.name}}'
  - clusters:
      selector:
        matchLabels:
          type: 'production'
      values:
        # production uses a different revision value, for 'stable' branch
        revision: stable
        clusterName: '{{.name}}'
  template:
    metadata:
      name: '{{.name}}-guestbook'
    spec:
      project: "my-project"
      source:
        repoURL: https://github.com/argoproj/argocd-example-apps/
        # The cluster values field for each generator will be substituted here:
        targetRevision: '{{.values.revision}}'
        path: guestbook
      destination:
        # In this case this is equivalent to just using {{name}}
        server: '{{.values.clusterName}}'
        namespace: guestbook
Git 生成器

Git 生成器包含两个子类型:Git 目录生成器和 Git 文件生成器。

Git 生成器通常用于帮助(非管理员)开发人员更轻松地创建应用程序。如果 ApplicationSet 中的项目字段是模板化的,开发人员可能能够在具有过多权限的项目下创建应用程序。对于具有模板化项目字段的 ApplicationSet,真实来源必须由管理员控制 - 对于 git 生成器,PR 必须需要管理员批准。

Git 生成器:目录

Git 目录生成器是 Git 生成器的两个子类型之一,它使用指定 Git 存储库的目录结构生成参数。

假设您有一个具有以下目录结构的 Git 存储库:

├── argo-workflows
│   ├── kustomization.yaml
│   └── namespace-install.yaml
└── prometheus-operator
    ├── Chart.yaml
    ├── README.md
    ├── requirements.yaml
    └── values.yaml

此存储库包含两个目录,每个要部署的工作负载对应一个目录:

  • Argo Workflow 控制器 kustomization YAML 文件
  • Prometheus Operator Helm 图表

我们可以部署这两个工作负载,使用以下示例:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-addons
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: https://github.com/argoproj/argo-cd.git
      revision: HEAD
      directories:
      - path: applicationset/examples/git-generator-directory/cluster-addons/*
  template:
    metadata:
      name: '{{.path.basename}}'
    spec:
      project: "my-project"
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: '{{.path.path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{.path.basename}}'
      syncPolicy:
        syncOptions:
        - CreateNamespace=true

(完整示例可在此处找到。)

生成器参数为:

  • {{.path.path}}: Git 存储库中与path通配符匹配的目录路径。
  • {{index .path.segments n}}: Git 存储库中与path通配符匹配的目录路径,拆分为数组元素(n - 数组索引)
  • {{.path.basename}}: 对于 Git 存储库中与path通配符匹配的任何目录路径,将提取最右边的路径名(例如,/directory/directory2 将生成 directory2)。
  • {{.path.basenameNormalized}}: 该字段与 path.basename 相同,但将不支持的字符替换为 - (例如,路径 /directory/directory_2path.basenamedirectory_2 将在此处产生 directory-2)。

注意:最右边的路径名始终为 {{.path.basename}}。例如,对于 - path: /one/two/three/four{{.path.basename}}four

注意:如果指定了 pathParamPrefix 选项,则上述所有与path相关的参数名称都将以指定值和点分隔符作为前缀。例如,如果 pathParamPrefixmyRepo,则生成的参数名称将是 .myRepo.path,而不是 .path。在 Matrix 生成器中,如果两个子生成器都是 Git 生成器,则必须使用此选项(以避免在合并子生成器的项目时发生冲突)。

每当向 Git 存储库添加新的 Helm chart/Kustomize YAML/Application/plain 子目录时,ApplicationSet 控制器都会检测到此更改并自动在新的应用Application资源中部署生成的清单。

与其他生成器一样,必须已经在 Argo CD 中定义集群,才能为其生成应用程序。

排除目录
Git 目录生成器将自动排除以 . 开头的目录(例如 .git)。

Git 目录生成器还支持排除选项,以便将存储库中的目录排除在 ApplicationSet 控制器扫描之外:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-addons
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: https://github.com/argoproj/argo-cd.git
      revision: HEAD
      directories:
      - path: applicationset/examples/git-generator-directory/excludes/cluster-addons/*
      - path: applicationset/examples/git-generator-directory/excludes/cluster-addons/exclude-helm-guestbook
        exclude: true
  template:
    metadata:
      name: '{{.path.basename}}'
    spec:
      project: "my-project"
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: '{{.path.path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{.path.basename}}'

(完整示例可在此处找到。)

此示例将 exclude-helm-guestbook 目录从此 ApplicationSet 资源扫描的目录列表中排除。

如果目录至少匹配一个exclude模式,它将被排除。或者换句话说,排除规则优先于包含规则。

作为推论,included/excluded哪些目录不受directories字段列表中path顺序的影响(因为如上所述,排除规则始终优先于包含规则)。

例如,对于这些目录:

.
└── d
    ├── e
    ├── f
    └── g

假设你想包含 /d/e,但排除 /d/f/d/g。这将不起作用:

- path: /d/e
  exclude: false
- path: /d/*
  exclude: true

为什么?因为排除 /d/* 排除规则将优先于 /d/e 包含规则。当 ApplicationSet 控制器处理 Git 存储库中的/d/e 路径时,控制器会检测到至少有一条排除规则匹配,因此不应扫描该目录。

需要做的是:

- path: /d/*
- path: /d/f
  exclude: true
- path: /d/g
  exclude: true

或者,更短的方法(使用 path.Match 语法)是:

- path: /d/*
- path: /d/[fg]
  exclude: true

Git Repo 的根目录
可以通过提供“*”作为path来配置 Git 目录生成器从 git 存储库的根目录部署。

要排除目录,只需输入不想部署的目录的name/path.Match

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-addons
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: https://github.com/example/example-repo.git
      revision: HEAD
      directories:
      - path: '*'
      - path: donotdeploy
        exclude: true
  template:
    metadata:
      name: '{{.path.basename}}'
    spec:
      project: "my-project"
      source:
        repoURL: https://github.com/example/example-repo.git
        targetRevision: HEAD
        path: '{{.path.path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{.path.basename}}'

通过值字段传递额外的键值对

可以通过 git 目录生成器的 values 字段传递其他任意字符串键值对。通过 values 字段添加的值将添加为 values.(field)

在此示例中,传递了一个集群参数值。该值从branchpath变量中插入,然后用于确定目标命名空间。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-addons
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: https://github.com/example/example-repo.git
      revision: HEAD
      directories:
      - path: '*'
      values:
        cluster: '{{.branch}}-{{.path.basename}}'
  template:
    metadata:
      name: '{{.path.basename}}'
    spec:
      project: "my-project"
      source:
        repoURL: https://github.com/example/example-repo.git
        targetRevision: HEAD
        path: '{{.path.path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{.values.cluster}}'

values. 前缀始终添加到通过 generators.git.values 字段提供的值前面。使用时,请确保在template中的参数名称中包含此前缀。

Git 生成器:文件

Git 文件生成器是 Git 生成器的第二个子类型。Git 文件生成器使用在指定存储库中找到的 JSON/YAML 文件的内容生成参数。

假设有一个具有以下目录结构的 Git 存储库:

├── apps
│   └── guestbook
│       ├── guestbook-ui-deployment.yaml
│       ├── guestbook-ui-svc.yaml
│       └── kustomization.yaml
├── cluster-config
│   └── engineering
│       ├── dev
│       │   └── config.json
│       └── prod
│           └── config.json
└── git-generator-files.yaml

这些目录是:

  • guestbook 包含简单guestbook应用程序的 Kubernetes 资源
  • cluster-config 包含描述各个工程集群的 JSON/YAML 文件:一个用于开发,一个用于生产。
  • git-generator-files.yaml 是将guestbook部署到指定集群的示例 ApplicationSet 资源。

config.json 文件包含描述集群的信息(以及额外的样本数据):

{
  "aws_account": "123456",
  "asset_id": "11223344",
  "cluster": {
    "owner": "cluster-admin@company.com",
    "name": "engineering-dev",
    "address": "https://1.2.3.4"
  }
}

Git 生成器会自动发现包含对 config.json 文件更改的 Git 提交,并解析这些文件的内容并将其转换为模板参数。以下是针对上述 JSON 生成的参数:

aws_account: 123456
asset_id: 11223344
cluster.owner: cluster-admin@company.com
cluster.name: engineering-dev
cluster.address: https://1.2.3.4

并且所有发现的 config.json 文件的生成参数都会被代入到 ApplicationSet 模板中:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: https://github.com/argoproj/argo-cd.git
      revision: HEAD
      files:
      - path: "applicationset/examples/git-generator-files-discovery/cluster-config/**/config.json"
  template:
    metadata:
      name: '{{.cluster.name}}-guestbook'
    spec:
      project: default
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: "applicationset/examples/git-generator-files-discovery/apps/guestbook"
      destination:
        server: '{{.cluster.address}}'
        namespace: guestbook

(完整示例可在此处找到。)

cluster-config目录下的任何 config.json 文件都将根据指定的路径通配符模式进行参数化。每个文件中的 JSON 字段都被平铺为键/值对,此 ApplicationSet 示例使用模板中的 cluster.addresscluster.name 参数。

与其他生成器一样,必须已经在 Argo CD 中定义集群,才能为其生成应用程序。

除了配置文件中的扁平键/值对之外,还提供了以下生成器参数:

  • {{.path.path}}: Git 存储库中包含匹配配置文件的目录的路径。示例:/clusters/clusterA(如果配置文件为 /clusters/clusterA/config.json
  • {{index .path n}}: Git 存储库中匹配配置文件的路径,拆分为数组元素(n - 数组索引)。示例:index .path 0: clusters, index .path 1: clusterA
  • {{.path.basename}}: 包含配置文件的目录路径的基本名称(例如,上面示例中的 clusterA)。
  • {{.path.basenameNormalized}}: 该字段与 .path.basename 相同,但将不支持的字符替换为 - (例如,路径 /directory/directory_2directory_2.path.basename 将在此处生成 directory-2)。
  • {{.path.filename}}: 匹配的文件名。例如上例中的 config.json
  • {{.path.filenameNormalized}}: 将匹配的文件名中不支持的字符替换为 -

注意:最右侧的目录名称始终为 {{.path.basename}}。例如,from - path: /one/two/three/four/config.json{{.path.basename}} 将是 four。始终可以使用 {{.path.filename}} 访问文件名。

注意:如果指定了 pathParamPrefix 选项,则上述所有与path相关的参数名称都将以指定值和点分隔符作为前缀。例如,如果 pathParamPrefixmyRepo,则生成的参数名称将是 myRepo.path 而不是 path。在 Matrix 生成器中,如果两个子生成器都是 Git 生成器,则必须使用此选项(以避免在合并子生成器的项目时发生冲突)。

注意:Git 文件生成器的默认行为非常贪婪。请参阅 Git 文件生成器 Globbing 了解更多信息。

通过值字段传递额外的键值对
可以通过 git 文件生成器的 values 字段传递其他任意字符串键值对。通过 values 字段添加的值将作为 values.(field) 添加。

在此示例中,传递了一个 base_dir 参数值。它是从路径段中插入的,然后用于确定源路径。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: https://github.com/argoproj/argo-cd.git
      revision: HEAD
      files:
      - path: "applicationset/examples/git-generator-files-discovery/cluster-config/**/config.json"
      values:
        base_dir: "{{index .path 0}}/{{index .path 1}}/{{index .path 2}}"
  template:
    metadata:
      name: '{{.cluster.name}}-guestbook'
    spec:
      project: default
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: "{{.values.base_dir}}/apps/guestbook"
      destination:
        server: '{{.cluster.address}}'
        namespace: guestbook

values. 前缀始终添加到通过 generators.git.values 字段提供的值前面。使用时,请确保在template中的参数名称中包含此前缀。

在值中我们还可以插入如上所述的 git 文件生成器设置的所有字段。

Webhook 配置
使用 Git 生成器时,ApplicationSet 每三分钟轮询一次 Git 存储库以检测更改。为了消除轮询延迟,可以配置 ApplicationSet webhook 服务器以接收 webhook 事件。ApplicationSet 支持来自 GitHub 和 GitLab 的 Git webhook 通知。下面介绍如何为 GitHub 配置 Git webhook,但相同的过程应该适用于其他提供商。

ApplicationSet 控制器 webhook 不使用与此处定义的 API 服务器相同的 webhook。ApplicationSet 将 webhook 服务器公开为 ClusterIP 类型的服务。需要创建 ApplicationSet 特定的 Ingress 资源,以将此服务公开给 webhook 源。

  1. 在 Git 提供程序中创建 webhook
    在 Git 提供程序中,导航到可以配置 webhook 的设置页面。在 Git 提供程序中配置的负载 URL 应使用 ApplicationSet 实例的 /api/webhook 端点(例如 https://applicationset.example.com/api/webhook)。如果您希望使用共享密钥,请在密钥中输入任意值。此值将在下一步配置 webhook 时使用。

在这里插入图片描述
在 GitHub 中创建 webhook 时,“内容类型”需要设置为“application/json”。用于处理钩子的库不支持默认值“application/x-www-form-urlencoded”

  1. 使用 webhook secret 配置 ApplicationSet (可选)
    配置 webhook 共享密钥是可选的,因为 ApplicationSet 仍会刷新由 Git 生成器生成的应用程序,即使有未经身份验证的 webhook 事件也是如此。这样做是安全的,因为 webhook 有效负载的内容被视为不受信任,并且只会导致应用程序刷新(该过程已经以三分钟的间隔发生)。如果 ApplicationSet 可公开访问,则建议配置 webhook 密钥以防止 DDoS 攻击。

在 argocd-secret Kubernetes 密钥中,包含在步骤 1 中配置的 Git 提供程序的 webhook 密钥。

编辑 Argo CD Kubernetes 密钥:

kubectl edit secret argocd-secret -n argocd

提示:为了方便输入密钥,Kubernetes 支持在 stringData 字段中输入密钥,这样就省去了对值进行 base64 编码并将其复制到数据字段的麻烦。只需将步骤 1 中创建的共享 webhook 密钥复制到 stringData 字段下相应的 GitHub/GitLab/BitBucket 密钥即可:

apiVersion: v1
kind: Secret
metadata:
  name: argocd-secret
  namespace: argocd
type: Opaque
data:
...

stringData:
  # github webhook secret
  webhook.github.secret: shhhh! it's a github secret

  # gitlab webhook secret
  webhook.gitlab.secret: shhhh! it's a gitlab secret

保存后,请重新启动 ApplicationSet pod 以使更改生效。

矩阵(Matrix)生成器

矩阵生成器将两个子生成器生成的参数组合在一起,并遍历每个生成器生成的参数的每种组合。

通过组合两个生成器的参数,产生所有可能的组合,这使您能够获得两个生成器的固有属性。例如,许多可能的用例中的一小部分包括:

  • SCM 提供程序生成器 + 集群生成器:扫描 GitHub 组织的存储库以查找应用程序资源,并将这些资源定位到所有可用的集群。
  • Git 文件生成器 + 列表生成器:通过配置文件提供要部署的应用程序列表,并提供可选的配置选项,并将其部署到固定的集群列表。
  • Git 目录生成器 + 集群决策资源生成器:定位 Git 存储库文件夹中包含的应用程序资源,并将其部署到通过外部自定义资源提供的集群列表中。
  • 等等…

可以使用任意一组生成器,并将这些生成器的组合值插入到模板参数中,就像往常一样。

注意:如果两个子生成器都是 Git 生成器,则其中一个或两个都必须使用 pathParamPrefix 选项,以避免在合并子生成器的项目时发生冲突。

示例:Git 目录生成器 + 集群生成器
举例来说,假设我们有两个集群:

  • staging集群(位于 https://1.2.3.4)
  • production集群(位于 https://2.4.6.8)

我们的应用程序 YAML 在 Git 存储库中定义:

  • Argo Workflows 控制器(examples/git-generator-directory/cluster-addons/argo-workflows
  • Prometheus 操作员(/examples/git-generator-directory/cluster-addons/prometheus-operator

我们的目标是将这两个应用程序部署到两个集群上,并且更普遍地说,将来可以在 Git 存储库中自动部署新应用程序,也可以在 Argo CD 中定义的新集群上自动部署新应用程序。

为此,我们将使用 Matrix 生成器,并以 Git 和 Cluster 作为子生成器:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-git
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    # matrix 'parent' generator
    - matrix:
        generators:
          # git generator, 'child' #1
          - git:
              repoURL: https://github.com/argoproj/argo-cd.git
              revision: HEAD
              directories:
                - path: applicationset/examples/matrix/cluster-addons/*
          # cluster generator, 'child' #2
          - clusters:
              selector:
                matchLabels:
                  argocd.argoproj.io/secret-type: cluster
  template:
    metadata:
      name: '{{.path.basename}}-{{.name}}'
    spec:
      project: '{{index .metadata.labels "environment"}}'
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: '{{.path.path}}'
      destination:
        server: '{{.server}}'
        namespace: '{{.path.basename}}'

首先,Git 目录生成器将扫描 Git 存储库,发现指定路径下的目录。它发现 argo-workflowsprometheus-operator 应用程序,并生成两组相应的参数:

- path: /examples/git-generator-directory/cluster-addons/argo-workflows
  path.basename: argo-workflows

- path: /examples/git-generator-directory/cluster-addons/prometheus-operator
  path.basename: prometheus-operator

接下来,集群生成器扫描 Argo CD 中定义的集群集,找到暂存和生产集群密钥,并生成两组相应的参数:

- name: staging
  server: https://1.2.3.4

- name: production
  server: https://2.4.6.8

最后,Matrix生成器将组合两组输出并产生:

- name: staging
  server: https://1.2.3.4
  path: /examples/git-generator-directory/cluster-addons/argo-workflows
  path.basename: argo-workflows

- name: staging
  server: https://1.2.3.4
  path: /examples/git-generator-directory/cluster-addons/prometheus-operator
  path.basename: prometheus-operator

- name: production
  server: https://2.4.6.8
  path: /examples/git-generator-directory/cluster-addons/argo-workflows
  path.basename: argo-workflows

- name: production
  server: https://2.4.6.8
  path: /examples/git-generator-directory/cluster-addons/prometheus-operator
  path.basename: prometheus-operator

(完整示例可在此处找到。)

在另一个子生成器中使用一个子生成器的参数
矩阵生成器允许在一个子生成器中使用另一个子生成器生成的参数。下面是一个将 git-files 生成器与集群生成器结合使用的示例。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-git
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    # matrix 'parent' generator
    - matrix:
        generators:
          # git generator, 'child' #1
          - git:
              repoURL: https://github.com/argoproj/applicationset.git
              revision: HEAD
              files:
                - path: "examples/git-generator-files-discovery/cluster-config/**/config.json"
          # cluster generator, 'child' #2
          - clusters:
              selector:
                matchLabels:
                  argocd.argoproj.io/secret-type: cluster
                  kubernetes.io/environment: '{{.path.basename}}'
  template:
    metadata:
      name: '{{.name}}-guestbook'
    spec:
      project: default
      source:
        repoURL: https://github.com/argoproj/applicationset.git
        targetRevision: HEAD
        path: "examples/git-generator-files-discovery/apps/guestbook"
      destination:
        server: '{{.server}}'
        namespace: guestbook

以下是 git-files 生成器使用的 git 存储库的相应文件夹结构:

├── apps
│   └── guestbook
│       ├── guestbook-ui-deployment.yaml
│       ├── guestbook-ui-svc.yaml
│       └── kustomization.yaml
├── cluster-config
│   └── engineering
│       ├── dev
│       │   └── config.json
│       └── prod
│           └── config.json
└── git-generator-files.yaml

在上面的示例中,git-files 生成器生成的 {{.path.basename}} 参数将解析为 devprod。在第二个子生成器中,带有标签 kubernetes.io/environment: {{.path.basename}} 的标签选择器将使用第一个子生成器的参数(kubernetes.io/environment: prodkubernetes.io/environment: dev)生成的值进行解析。

因此,在上面的例子中,带有标签 kubernetes.io/environment: prod 的集群将仅具有应用于它的 prod 特定配置(即 prod/config.json),而带有标签 kubernetes.io/environment: dev 的集群将仅具有应用于它的 dev 特定配置(即 dev/config.json

在另一个子生成器中覆盖一个子生成器的参数
矩阵生成器允许在多个子生成器中定义同名的参数。这很有用,例如,在一个生成器中为所有阶段定义默认值,并在另一个生成器中使用特定于阶段的值覆盖它们。下面的示例使用带有两个 git 生成器的矩阵生成器生成基于 Helm 的应用程序:第一个提供特定于阶段的值(每个阶段一个目录),第二个为所有阶段提供全局值。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: parameter-override-example
spec:
  generators:
    - matrix:
        generators:
          - git:
              repoURL: https://github.com/example/values.git
              revision: HEAD
              files:
                - path: "**/stage.values.yaml"
          - git:
               repoURL: https://github.com/example/values.git
               revision: HEAD
               files:
                  - path: "global.values.yaml"
  goTemplate: true
  template:
    metadata:
      name: example
    spec:
      project: default
      source:
        repoURL: https://github.com/example/example-app.git
        targetRevision: HEAD
        path: .
        helm:
          values: |
            {{ `{{ . | mustToPrettyJson }}` }}
      destination:
        server: in-cluster
        namespace: default

给定示例/值存储库的以下结构/内容:

├── test
│   └── stage.values.yaml
│         stageName: test
│         cpuRequest: 100m
│         debugEnabled: true
├── staging
│   └── stage.values.yaml
│         stageName: staging
├── production
│   └── stage.values.yaml
│         stageName: production
│         memoryLimit: 512Mi
│         debugEnabled: false
└── global.values.yaml
      cpuRequest: 200m
      memoryLimit: 256Mi
      debugEnabled: true

上述矩阵生成器将产生以下结果:

- stageName: test
  cpuRequest: 100m
  memoryLimit: 256Mi
  debugEnabled: true

- stageName: staging
  cpuRequest: 200m
  memoryLimit: 256Mi
  debugEnabled: true

- stageName: production
  cpuRequest: 200m
  memoryLimit: 512Mi
  debugEnabled: false

示例:两个使用 pathParamPrefix 的 Git 生成器
如果矩阵生成器的子生成器生成的结果包含相同的键但值不同,则矩阵生成器将失败。这对于两个子生成器都是 Git 生成器的矩阵生成器来说是一个问题,因为它们会在输出中自动填充与path相关的参数。为了避免此问题,请在其中一个或两个子生成器上指定 pathParamPrefix,以避免输出中的参数键发生冲突。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: two-gits-with-path-param-prefix
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - matrix:
        generators:
          # git file generator referencing files containing details about each
          # app to be deployed (e.g., `appName`).
          - git:
              repoURL: https://github.com/some-org/some-repo.git
              revision: HEAD
              files:
                - path: "apps/*.json"
              pathParamPrefix: app
          # git file generator referencing files containing details about
          # locations to which each app should deploy (e.g., `region` and
          # `clusterName`).
          - git:
              repoURL: https://github.com/some-org/some-repo.git
              revision: HEAD
              files:
                - path: "targets/{{.appName}}/*.json"
              pathParamPrefix: target
  template: {} # ...

然后,给出以下文件结构/内容:

├── apps
│   ├── app-one.json
│   │   { "appName": "app-one" }
│   └── app-two.json
│       { "appName": "app-two" }
└── targets
    ├── app-one
    │   ├── east-cluster-one.json
    │   │   { "region": "east", "clusterName": "cluster-one" }
    │   └── east-cluster-two.json
    │       { "region": "east", "clusterName": "cluster-two" }
    └── app-two
        ├── east-cluster-one.json
        │   { "region": "east", "clusterName": "cluster-one" }
        └── west-cluster-three.json
            { "region": "west", "clusterName": "cluster-three" }

…上面的矩阵生成器将产生以下结果:

- appName: app-one
  app.path: /apps
  app.path.filename: app-one.json
  # plus additional path-related parameters from the first child generator, all
  # prefixed with "app".
  region: east
  clusterName: cluster-one
  target.path: /targets/app-one
  target.path.filename: east-cluster-one.json
  # plus additional path-related parameters from the second child generator, all
  # prefixed with "target".

- appName: app-one
  app.path: /apps
  app.path.filename: app-one.json
  region: east
  clusterName: cluster-two
  target.path: /targets/app-one
  target.path.filename: east-cluster-two.json

- appName: app-two
  app.path: /apps
  app.path.filename: app-two.json
  region: east
  clusterName: cluster-one
  target.path: /targets/app-two
  target.path.filename: east-cluster-one.json

- appName: app-two
  app.path: /apps
  app.path.filename: app-two.json
  region: west
  clusterName: cluster-three
  target.path: /targets/app-two
  target.path.filename: west-cluster-three.json

限制

  1. 矩阵生成器当前仅支持组合两个子生成器的输出(例如,不支持生成 3 个或更多个组合)。
  2. 应该为每个数组条目仅指定一个生成器,例如这是无效的:
- matrix:
    generators:
    - list: # (...)
      git: # (...)

虽然 Kubernetes API 验证会接受此方法,但控制器会在生成时报告错误。每个生成器都应在单独的数组元素中指定,如上例所示。

  1. 矩阵生成器目前不支持在子生成器上指定的template覆盖,例如,此模板将不会被处理:
- matrix:
    generators:
      - list:
          elements:
            - # (...)
          template: { } # Not processed
  1. 组合型生成器(矩阵或合并)只能嵌套一次。例如,以下代码不起作用:
- matrix:
    generators:
      - matrix:
          generators:
            - matrix:  # This third level is invalid.
                generators:
                  - list:
                      elements:
                        - # (...)
  1. 当在一个子生成器中使用另一个子生成器的参数时,使用参数的子生成器必须位于生成参数的子生成器之后。例如,以下示例将无效(cluster-generator 必须位于 git-files 生成器之后):
- matrix:
    generators:
      # cluster generator, 'child' #1
      - clusters:
          selector:
            matchLabels:
              argocd.argoproj.io/secret-type: cluster
              kubernetes.io/environment: '{{.path.basename}}' # {{.path.basename}} is produced by git-files generator
      # git generator, 'child' #2
      - git:
          repoURL: https://github.com/argoproj/applicationset.git
          revision: HEAD
          files:
            - path: "examples/git-generator-files-discovery/cluster-config/**/config.json"
  1. 不能让两个子生成器使用彼此的参数。在下面的示例中,集群生成器正在使用由 git-files 生成器生成的 {{.path.basename}} 参数,而 git-files 生成器正在使用由集群生成器生成的 {{.name}} 参数。这将导致循环依赖,这是无效的。
- matrix:
    generators:
      # cluster generator, 'child' #1
      - clusters:
          selector:
            matchLabels:
              argocd.argoproj.io/secret-type: cluster
              kubernetes.io/environment: '{{.path.basename}}' # {{.path.basename}} is produced by git-files generator
      # git generator, 'child' #2
      - git:
          repoURL: https://github.com/argoproj/applicationset.git
          revision: HEAD
          files:
            - path: "examples/git-generator-files-discovery/cluster-config/engineering/{{.name}}**/config.json" # {{.name}} is produced by cluster generator
  1. 当使用嵌套在另一个矩阵或合并生成器中的矩阵生成器时,此嵌套生成器的生成器的 Post 选择器仅在通过 spec.applyNestedSelectors 启用时才会应用。即使 Post 选择器不在嵌套矩阵或合并生成器内,而是嵌套矩阵或合并生成器的兄弟,您可能也需要启用此功能。
- matrix:
    generators:
      - matrix:
          generators:
            - list
                elements:
                  - # (...)
              selector: { } # Only applied when applyNestedSelectors is true
合并生成器

合并生成器将基础(第一个)生成器生成的参数与后续生成器生成的匹配参数集组合在一起。匹配参数集对于配置的合并键具有相同的值。不匹配的参数集将被丢弃。覆盖优先级从下到上:生成器 3 生成的匹配参数集的值将优先于生成器 2 生成的相应参数集的值。

当参数集的子集需要覆盖时,使用合并生成器是合适的。

示例:基础集群生成器 + 覆盖集群生成器 + 列表生成器
举例来说,假设我们有两个集群:

  • staging cluster (https://1.2.3.4)
  • production cluster (https://2.4.6.8)
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-git
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    # merge 'parent' generator
    - merge:
        mergeKeys:
          - server
        generators:
          - clusters:
              values:
                kafka: 'true'
                redis: 'false'
          # For clusters with a specific label, enable Kafka.
          - clusters:
              selector:
                matchLabels:
                  use-kafka: 'false'
              values:
                kafka: 'false'
          # For a specific cluster, enable Redis.
          - list:
              elements: 
                - server: https://2.4.6.8
                  values.redis: 'true'
  template:
    metadata:
      name: '{{.name}}'
    spec:
      project: '{{index .metadata.labels "environment"}}'
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: app
        helm:
          parameters:
            - name: kafka
              value: '{{.values.kafka}}'
            - name: redis
              value: '{{.values.redis}}'
      destination:
        server: '{{.server}}'
        namespace: default

基础集群生成器扫描 Argo CD 中定义的集群集,找到暂存和生产集群密钥,并生成两组相应的参数:

- name: staging
  server: https://1.2.3.4
  values.kafka: 'true'
  values.redis: 'false'

- name: production
  server: https://2.4.6.8
  values.kafka: 'true'
  values.redis: 'false'

覆盖集群生成器扫描 Argo CD 中定义的集群集,找到暂存集群密钥(具有所需标签),并生成以下参数:

- name: staging
  server: https://1.2.3.4
  values.kafka: 'false'

与基本生成器的参数合并时,暂存集群的 values.kafka 值设置为“false”。

- name: staging
  server: https://1.2.3.4
  values.kafka: 'false'
  values.redis: 'false'

- name: production
  server: https://2.4.6.8
  values.kafka: 'true'
  values.redis: 'false'

最后,List集群生成一组参数:

- server: https://2.4.6.8
  values.redis: 'true'

与更新后的基础参数合并后,生产集群的 values.redis 值将设置为“true”。这是合并生成器的最终输出:

- name: staging
  server: https://1.2.3.4
  values.kafka: 'false'
  values.redis: 'false'

- name: production
  server: https://2.4.6.8
  values.kafka: 'true'
  values.redis: 'true'

示例:在合并中使用值插值
一些生成器支持附加值以及从生成的变量插入到选定值。这可用于教导合并生成器使用哪些生成的变量来组合不同的生成器。
以下示例通过集群标签和分支名称组合发现的集群和 git 存储库:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-git
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    # merge 'parent' generator:
    # Use the selector set by both child generators to combine them.
    - merge:
        mergeKeys:
          # Note that this would not work with goTemplate enabled,
          # nested merge keys are not supported there.
          - values.selector
        generators:
          # Assuming, all configured clusters have a label for their location:
          # Set the selector to this location.
          - clusters:
              values:
                selector: '{{index .metadata.labels "location"}}'
          # The git repo may have different directories which correspond to the
          # cluster locations, using these as a selector.
          - git:
              repoURL: https://github.com/argoproj/argocd-example-apps/
              revision: HEAD
              directories:
              - path: '*'
              values:
                selector: '{{.path.path}}'
  template:
    metadata:
      name: '{{.name}}'
    spec:
      project: '{{index .metadata.labels "environment"}}'
      source:
        repoURL: https://github.com/argoproj/argocd-example-apps/
        # The cluster values field for each generator will be substituted here:
        targetRevision: HEAD
        path: '{{.path.path}}'
      destination:
        server: '{{.server}}'
        namespace: default

假设有一个名为 germany01 的集群,其标签为 metadata.labels.location=Germany,并且有一个 git 存储库,其中包含一个名为 Germany 的目录,则这些值可以组合成以下值:

  # From the cluster generator
- name: germany01
  server: https://1.2.3.4
  # From the git generator
  path: Germany
  # Combining selector with the merge generator
  values.selector: 'Germany'
  # More values from cluster & git generator
  # […]

限制

  1. 应该为每个数组条目仅指定一个生成器。这是无效的:
- merge:
    generators:
    - list: # (...)
      git: # (...)

虽然 Kubernetes API 验证会接受此方法,但控制器会在生成时报告错误。每个生成器都应在单独的数组元素中指定,如上例所示。

  1. 合并生成器不支持子生成器上指定的template覆盖。不会处理此模板:
- merge:
    generators:
      - list:
          elements:
            - # (...)
          template: { } # Not processed
  1. 组合类型生成器(Matrix 或 Merge)只能嵌套一次。例如,以下代码不起作用:
- merge:
    generators:
      - merge:
          generators:
            - merge:  # This third level is invalid.
                generators:
                  - list:
                      elements:
                        - # (...)
  1. 使用 goTemplate: true 时合并嵌套值目前不受支持,这将不起作用
spec:
  goTemplate: true
  generators:
  - merge:
      mergeKeys:
        - values.merge
  1. 当使用嵌套在另一个矩阵或合并生成器中的合并生成器时,仅当通过 spec.applyNestedSelectors 启用时,才会应用此嵌套生成器的生成器的后选择器。
- merge:
    generators:
      - merge:
          generators:
            - list
                elements:
                  - # (...)
              selector: { } # Only applied when applyNestedSelectors is true
SCM 提供商生成器

SCM 提供程序生成器使用 SCMaaS 提供程序(例如 GitHub)的 API 自动发现组织内的存储库。这非常符合将微服务拆分到多个存储库的 GitOps 布局模式。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  generators:
  - scmProvider:
      # Which protocol to clone using.
      cloneProtocol: ssh
      # See below for provider specific options.
      github:
        # ...

cloneProtocol:SCM URL 使用哪种协议。默认为提供商特定,但如果可能,则使用 ssh。并非所有提供商都支持所有协议,请参阅下面的提供商文档以了解可用选项。

了解使用 SCM 生成器的安全隐患。只有管理员可以创建 ApplicationSet 以避免泄露机密,并且只有管理员可以在使用 SCM 生成器的 ApplicationSet 的项目字段已模板化的情况下创建存储库/分支,以避免授予对越界资源的管理权。

GitHub
GitHub 模式使用 GitHub API 在 github.com 或 GitHub Enterprise 中扫描组织。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  generators:
  - scmProvider:
      github:
        # The GitHub organization to scan.
        organization: myorg
        # For GitHub Enterprise:
        api: https://git.example.com/
        # If true, scan every branch of every repository. If false, scan only the default branch. Defaults to false.
        allBranches: true
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: github-token
          key: token
        # (optional) use a GitHub App to access the API instead of a PAT.
        appSecretName: gh-app-repo-creds
  template:
  # ...
  • organization: 需要扫描的 GitHub 组织的必填名称。如果有多个组织,请使用多个生成器。
  • api: 如果使用 GitHub Enterprise,则为访问它的 URL。
  • allBranches: 默认情况下(false),模板将仅针对每个存储库的默认分支进行评估。如果为 true,则每个存储库的每个分支都将传递给过滤器。如果使用此标志,您可能希望使用 branchMatch 过滤器。
  • tokenRef: 包含用于请求的 GitHub 访问令牌的 Secret 名称和密钥。如果未指定,将发出具有较低速率限制且只能查看公共存储库的匿名请求。
  • appSecretName: 包含 repo-creds 格式的 GitHub App 机密的 Secret 名称。

对于标签过滤,使用存储库主题。
可用的克隆协议是 sshhttps

Gitlab
GitLab 模式使用 GitLab API 在 gitlab.com 或自托管的 GitLab 中进行扫描和组织。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  generators:
  - scmProvider:
      gitlab:
        # The base GitLab group to scan.  You can either use the group id or the full namespaced path.
        group: "8675309"
        # For self-hosted GitLab:
        api: https://gitlab.example.com/
        # If true, scan every branch of every repository. If false, scan only the default branch. Defaults to false.
        allBranches: true
        # If true, recurses through subgroups. If false, it searches only in the base group. Defaults to false.
        includeSubgroups: true
        # If true and includeSubgroups is also true, include Shared Projects, which is gitlab API default.
        # If false only search Projects under the same path. Defaults to true.
        includeSharedProjects: false
        # filter projects by topic. A single topic is supported by Gitlab API. Defaults to "" (all topics).
        topic: "my-topic"
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: gitlab-token
          key: token
        # If true, skips validating the SCM provider's TLS certificate - useful for self-signed certificates.
        insecure: false
  template:
  # ...
  • group: 要扫描的基本 GitLab 组的必填名称。如果您有多个基本组,请使用多个生成器。
  • api: 如果使用自托管 GitLab,则访问它的 URL。
  • allBranches: 默认情况下(false),模板将仅针对每个存储库的默认分支进行评估。如果为 true,则每个存储库的每个分支都将传递给过滤器。如果使用此标志,您可能希望使用 branchMatch 过滤器。
  • includeSubgroups: 默认情况下(false),控制器将仅直接在基础组中搜索存储库。如果为 true,它将递归遍历所有子组以搜索要扫描的存储库。
  • includeSharedProjects: 如果为 true 并且 includeSubgroups 也为 true,则包含共享项目,这是 gitlab API 默认设置。如果为 false,则仅搜索同一路径下的项目。一般来说,大多数人希望设置为 false 时的行为。默认为 true。
  • topic: 按主题过滤项目。Gitlab API 支持单个主题。默认为“”(所有主题)。
  • tokenRef: 包含用于请求的 GitLab 访问令牌的 Secret 名称和密钥。如果未指定,将发出具有较低速率限制且只能查看公共存储库的匿名请求。
  • insecure: 默认情况下(false)-跳过检查 SCM 证书的有效性 - 对于自签名 TLS 证书很有用。

对于标签过滤,使用存储库主题。
可用的克隆协议是 ssh 和 https。

自签名 TLS 证书
作为将 insecure 设置为 true 的更好替代方案,您可以为 Gitlab 配置自签名 TLS 证书。

为了让 ApplicationSet 的 SCM / PR Gitlab 生成器使用自签名 TLS 证书,需要将该证书挂载到应用程序集控制器上。必须使用环境变量 ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH 或使用参数 --scm-root-ca-path 明确设置挂载证书的路径。应用程序集控制器将读取挂载的证书以创建 SCM/PR 提供商的 Gitlab 客户端

通过在 argocd-cmd-params-cm ConfigMap 中设置 applicationsetcontroller.scm.root.ca.path 即可轻松实现。设置此值后,请务必重新启动 ApplicationSet 控制器。

Gitea
Gitea 模式使用 Gitea API 扫描实例中的组织

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  generators:
  - scmProvider:
      gitea:
        # The Gitea owner to scan.
        owner: myorg
        # The Gitea instance url
        api: https://gitea.mydomain.com/
        # If true, scan every branch of every repository. If false, scan only the default branch. Defaults to false.
        allBranches: true
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: gitea-token
          key: token
  template:
  # ...
  • owner: 需要扫描的 Gitea 组织的必填名称。如果您有多个组织,请使用多个生成器。
  • api: 正在使用的 Gitea 实例的 URL。
  • allBranches: 默认情况下(false),模板将仅针对每个存储库的默认分支进行评估。如果为 true,则每个存储库的每个分支都将传递给过滤器。如果使用此标志,您可能希望使用 branchMatch 过滤器。
  • tokenRef: 包含用于请求的 Gitea 访问令牌的 Secret 名称和密钥。如果未指定,将发出具有较低速率限制且只能查看公共存储库的匿名请求。
  • insecure: 允许自签名 TLS 证书。

此 SCM 提供程序尚不支持标签过滤

可用的克隆协议为 ssh 和 https。

Bitbucket 服务器
使用 Bitbucket Server API (1.0) 扫描项目中的存储库。请注意,Bitbucket Server 与 Bitbucket Cloud (API 2.0) 不同

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  generators:
  - scmProvider:
      bitbucketServer:
        project: myproject
        # URL of the Bitbucket Server. Required.
        api: https://mycompany.bitbucket.org
        # If true, scan every branch of every repository. If false, scan only the default branch. Defaults to false.
        allBranches: true
        # Credentials for Basic authentication. Required for private repositories.
        basicAuth:
          # The username to authenticate with
          username: myuser
          # Reference to a Secret containing the password or personal access token.
          passwordRef:
            secretName: mypassword
            key: password
        # Support for filtering by labels is TODO. Bitbucket server labels are not supported for PRs, but they are for repos
  template:
  # ...
  • project: Bitbucket 项目的必填名称
  • api: 访问 Bitbucket REST api 所需的 URL。
  • allBranches: 默认情况下(false),模板将仅针对每个存储库的默认分支进行评估。如果为 true,则每个存储库的每个分支都将传递给过滤器。如果使用此标志,您可能希望使用 branchMatch 过滤器。

如果想要访问私有存储库,还必须提供基本身份验证的凭证(这是当前唯一支持的身份验证): * username:用于身份验证的用户名。它只需要对相关存储库具有读取权限。 * passwordRef:包含用于请求的密码或个人访问令牌的 Secret 名称和密钥。

可用的克隆协议是 ssh 和 https。

Azure DevOps
使用 Azure DevOps API 根据 Azure DevOps 组织内的团队项目查找符合条件的存储库。默认的 Azure DevOps URL 是 https://dev.azure.com,但可以使用字段 azureDevOps.api 覆盖此 URL。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  generators:
  - scmProvider:
      azureDevOps:
        # The Azure DevOps organization.
        organization: myorg
        # URL to Azure DevOps. Optional. Defaults to https://dev.azure.com.
        api: https://dev.azure.com
        # If true, scan every branch of eligible repositories. If false, check only the default branch of the eligible repositories. Defaults to false.
        allBranches: true
        # The team project within the specified Azure DevOps organization.
        teamProject: myProject
        # Reference to a Secret containing the Azure DevOps Personal Access Token (PAT) used for accessing Azure DevOps.
        accessTokenRef:
          secretName: azure-devops-scm
          key: accesstoken
  template:
  # ...
  • organization: 必填。Azure DevOps 组织的名称。
  • teamProject: 必填。指定组织内的团队项目的名称。
  • accessTokenRef: 必需。包含用于请求的 Azure DevOps 个人访问令牌 (PAT) 的机密名称和密钥。
  • api: 可选。Azure DevOps 的 URL。如果未设置,则使用 https://dev.azure.com
  • allBranches: 可选,默认为 false。如果为 true,则扫描符合条件的存储库的每个分支。如果为 false,则仅检查符合条件的存储库的默认分支。

Bitbucket Cloud
Bitbucket 模式使用 Bitbucket API V2 扫描 bitbucket.org 中的工作区。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  generators:
  - scmProvider:
      bitbucket:
        # The workspace id (slug).  
        owner: "example-owner"
        # The user to use for basic authentication with an app password.
        user: "example-user"
        # If true, scan every branch of every repository. If false, scan only the main branch. Defaults to false.
        allBranches: true
        # Reference to a Secret containing an app password.
        appPasswordRef:
          secretName: appPassword
          key: password
  template:
  # ...
  • owner: 查找存储库时使用的工作区 ID (slug)。
  • user: 用于向 bitbucket.org 上的 Bitbucket API V2 进行身份验证的用户。
  • allBranches: 默认情况下(false),模板将仅针对每个存储库的主分支进行评估。如果为 true,则每个存储库的每个分支都将传递给过滤器。如果使用此标志,您可能希望使用 branchMatch 过滤器。
  • appPasswordRef: 包含用于请求的 bitbucket 应用程序密码的 Secret 名称和密钥。

此 SCM 提供程序尚不支持标签过滤

可用的克隆协议为 ssh 和 https。

AWS CodeCommit (Alpha)
参考官网

Filters
过滤器允许选择要为哪些存储库生成。每个过滤器可以声明一个或多个条件,所有条件都必须满足。如果存在多个过滤器,则任何条件都可以匹配以包含存储库。如果未指定过滤器,则将处理所有存储库。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  generators:
  - scmProvider:
      filters:
      # Include any repository starting with "myapp" AND including a Kustomize config AND labeled with "deploy-ok" ...
      - repositoryMatch: ^myapp
        pathsExist: [kubernetes/kustomization.yaml]
        labelMatch: deploy-ok
      # ... OR include any repository starting with "otherapp" AND a Helm folder and doesn't have file disabledrepo.txt.
      - repositoryMatch: ^otherapp
        pathsExist: [helm]
        pathsDoNotExist: [disabledrepo.txt]
  template:
  # ...
  • repositoryMatch: 与存储库名称匹配的正则表达式。
  • pathsExist: 存储库中必须存在的路径数组。可以是文件或目录。
  • pathsDoNotExist: 存储库中不得存在的路径数组。可以是文件或目录。
  • labelMatch: 与存储库标签匹配的正则表达式。如果任何标签匹配,则包含存储库。
  • branchMatch: 与分支名称匹配的正则表达式。

Template
与所有生成器一样,会生成几个参数以供 ApplicationSet 资源模板使用。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - scmProvider:
    # ...
  template:
    metadata:
      name: '{{ .repository }}'
    spec:
      source:
        repoURL: '{{ .url }}'
        targetRevision: '{{ .branch }}'
        path: kubernetes/
      project: default
      destination:
        server: https://kubernetes.default.svc
        namespace: default
  • organization: 存储库所在组织的名称。
  • repository: 存储库的名称。
  • url: 存储库的克隆 URL。
  • branch: 存储库的默认分支。
  • sha: 该分支的 Git 提交 SHA。
  • short_sha: 分支的缩写 Git 提交 SHA(8 个字符或更短的 SHA 长度)。
  • short_sha_7: 分支的缩写 Git 提交 SHA(7 个字符或更短的 sha 的长度)。
  • labels: 如果是 Gitea,则为以逗号分隔的存储库标签列表;如果是 Gitlab 和 Github,则为存储库主题列表。Bitbucket Cloud、Bitbucket Server 或 Azure DevOps 不支持该列表。
  • branchNormalized: branch的值已规范化为仅包含小写字母数字字符“-”或“.”。

通过值字段传递额外的键值对
可以通过任何 SCM 生成器的 values 字段传递额外的任意字符串键值对。通过 values 字段添加的值将作为 values.(field) 添加。

在此示例中,传递了一个 name 参数值。该参数值从 organizationrepository 中插入,以生成不同的模板名称。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - scmProvider:
      bitbucketServer:
        project: myproject
        api: https://mycompany.bitbucket.org
        allBranches: true
        basicAuth:
          username: myuser
          passwordRef:
            secretName: mypassword
            key: password
      values:
        name: "{{.organization}}-{{.repository}}"

  template:
    metadata:
      name: '{{ .values.name }}'
    spec:
      source:
        repoURL: '{{ .url }}'
        targetRevision: '{{ .branch }}'
        path: kubernetes/
      project: default
      destination:
        server: https://kubernetes.default.svc
        namespace: default

values. 前缀始终添加到通过 generators.scmProvider.values 字段提供的值前面。使用template时,请确保在参数名称中包含此前缀。

values中我们还可以插入如上所述的 SCM 生成器设置的所有字段。

集群决策资源生成器

集群决策资源生成 Argo CD 集群列表。这是使用 duck-typing 完成的,它不需要了解所引用的 Kubernetes 资源的完整形状。以下是基于集群决策资源的 ApplicationSet 生成器的示例:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
 name: guestbook
 namespace: argocd
spec:
 goTemplate: true
 goTemplateOptions: ["missingkey=error"]
 generators:
 - clusterDecisionResource:
    # ConfigMap with GVK information for the duck type resource
    configMapRef: my-configmap  
    name: quak           # Choose either "name" of the resource or "labelSelector"
    labelSelector:
      matchLabels:       # OPTIONAL
        duck: spotted
      matchExpressions:  # OPTIONAL
      - key: duck
        operator: In
        values:
        - "spotted"
        - "canvasback"   
    # OPTIONAL: Checks for changes every 60sec (default 3min)
    requeueAfterSeconds: 60
 template:
   metadata:
     name: '{{.name}}-guestbook'
   spec:
      project: "default"
      source:
        repoURL: https://github.com/argoproj/argocd-example-apps/
        targetRevision: HEAD
        path: guestbook
      destination:
        server: '{{.clusterName}}' # 'server' field of the secret
        namespace: guestbook

ApplicationSet clusterDecisionResource 生成器引用的 quak 资源:

apiVersion: mallard.io/v1beta1
kind: Duck
metadata:
  name: quak
spec: {}
status:
  # Duck-typing ignores all other aspects of the resource except 
  # the "decisions" list
  decisions:
  - clusterName: cluster-01
  - clusterName: cluster-02

ApplicationSet 资源引用了定义要在此 duck-typing 中使用的资源的 ConfigMap。每个 ArgoCD 实例只需要一个 ConfigMap 来标识资源。您可以通过为每种资源类型创建一个 ConfigMap 来支持多种资源类型。

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-configmap
data:
  # apiVersion of the target resource
  apiVersion: mallard.io/v1beta1  
  # kind of the target resource
  kind: ducks
  # status key name that holds the list of Argo CD clusters
  statusListKey: decisions
  # The key in the status list whose value is the cluster name found in Argo CD
  matchKey: clusterName

(完整示例可在此处找到。)

此示例利用了 open-cluster-management.io 社区的集群管理功能。通过使用 GVK 为 open-cluster-management.io Placement 规则创建 ConfigMap, ApplicationSet 可以以多种新颖的方式配置到不同的集群。一个例子是让 ApplicationSet 在 3 个或更多集群中仅维护两个 Argo CD 应用程序。然后,当发生维护或中断时,ApplicationSet 将始终维护两个应用程序,并根据 Placement 规则的指示将应用程序移动到可用的集群。

怎么运行的
需要在 Argo CD 命名空间中创建 ApplicationSet,将 ConfigMap 放在同一命名空间中可让 ClusterDecisionResource 生成器读取它。ConfigMap 存储 GVK 信息以及状态键定义。在 open-cluster-management 示例中,ApplicationSet 生成器将读取 apiVersion 为 apps.open-cluster-management.io/v1 的 placementrules 类型。它将尝试从关键决策中提取集群列表。然后,它根据列表中每个元素中的键 clusterName 的值验证 Argo CD 中定义的实际集群名称。

ClusterDecisionResource 生成器将鸭子类型资源状态列表中的“name”、“server”和其他任何键/值作为参数传递到 ApplicationSet 模板中。在此示例中,决策数组包含一个附加键 clusterName,现在该键可供 ApplicationSet 模板使用。

Status.Decisions 中列出的集群名称必须在 Argo CD 中定义,以便为这些值生成应用程序。ApplicationSet 控制器不会在 Argo CD 中创建集群。
默认集群列表键是clusters

拉取请求生成器

Pull 请求生成器使用 SCMaaS 提供商(GitHub、Gitea 或 Bitbucket Server)的 API 自动发现存储库中的未结 Pull 请求。这非常符合创建 Pull 请求时构建测试环境的风格。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      # When using a Pull Request generator, the ApplicationSet controller polls every `requeueAfterSeconds` interval (defaulting to every 30 minutes) to detect changes.
      requeueAfterSeconds: 1800
      # See below for provider specific options.
      github:
        # ...

了解 ApplicationSet 中 PR 生成器的安全隐患。只有管理员可以创建 ApplicationSet 以避免泄露机密,并且只有管理员可以在带有 PR 生成器的 ApplicationSet 的项目字段被模板化的情况下创建 PR,以避免授予对越界资源的管理权。

GitHub
指定从中获取 GitHub Pull 请求的存储库。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      github:
        # The GitHub organization or user.
        owner: myorg
        # The Github repository
        repo: myrepository
        # For GitHub Enterprise (optional)
        api: https://git.example.com/
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: github-token
          key: token
        # (optional) use a GitHub App to access the API instead of a PAT.
        appSecretName: github-app-repo-creds
        # Labels is used to filter the PRs that you want to target. (optional)
        labels:
        - preview
      requeueAfterSeconds: 1800
  template:
  # ...
  • owner: GitHub 组织或用户的必填名称。
  • repo: GitHub 存储库的必填名称。
  • api: 如果使用 GitHub Enterprise,则为访问它的 URL。(可选)
  • tokenRef: 包含用于请求的 GitHub 访问令牌的 Secret 名称和密钥。如果未指定,将发出具有较低速率限制且只能查看公共存储库的匿名请求。(可选)
  • labels: 将 PR 筛选为包含所有列出的标签的 PR。(可选)
  • appSecretName: 包含 repo-creds 格式的 GitHub App 机密的 Secret 名称。

GitLab
指定从中获取 GitLab 合并请求的项目。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      gitlab:
        # The GitLab project ID.
        project: "12341234"
        # For self-hosted GitLab (optional)
        api: https://git.example.com/
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: gitlab-token
          key: token
        # Labels is used to filter the MRs that you want to target. (optional)
        labels:
        - preview
        # MR state is used to filter MRs only with a certain state. (optional)
        pullRequestState: opened
        # If true, skips validating the SCM provider's TLS certificate - useful for self-signed certificates.
        insecure: false
      requeueAfterSeconds: 1800
  template:
  # ...
  • project: GitLab 项目的必填项目 ID。
  • api: 如果使用自托管 GitLab,则为访问它的 URL。(可选)
  • tokenRef: 包含用于请求的 GitLab 访问令牌的 Secret 名称和密钥。如果未指定,将发出具有较低速率限制且只能查看公共存储库的匿名请求。(可选)
  • labels: 标签用于过滤您想要定位的 MR。(可选)
  • pullRequestState: PullRequestState 是一个附加的 MR 过滤器,用于仅获取具有特定状态的 MR。默认值:“”(所有状态)
  • insecure: 默认情况下(false)-跳过检查 SCM 证书的有效性 - 对于自签名 TLS 证书很有用。

作为将 insecure 设置为 true 的更好替代方案,您可以通过将自签名证书挂载到应用程序集控制器来为 Gitlab 配置自签名 TLS 证书。

Gitea
指定从中获取gitea拖拉请求的存储库。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      gitea:
        # The Gitea organization or user.
        owner: myorg
        # The Gitea repository
        repo: myrepository
        # The Gitea url to use
        api: https://gitea.mydomain.com/
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: gitea-token
          key: token
        # many gitea deployments use TLS, but many are self-hosted and self-signed certificates
        insecure: true
      requeueAfterSeconds: 1800
  template:
  # ...
  • owner: Gitea组织或用户的必需名称。
  • repo: Gitea存储库的必需名称。
  • api: Gitea实例的URL。
  • tokenRef: 包含gitea访问令牌的秘密名称和键,用于请求。如果未指定,将提出匿名请求,该请求的利率限制较低,只能看到公共存储库。 (选修的)
  • insecure: 允许自签名证书,主要用于测试。

Bitbucket服务器
从Bitbucket服务器上托管的存储库中提取拉的请求(与Bitbucket Cloud不同)。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      bitbucketServer:
        project: myproject
        repo: myrepository
        # URL of the Bitbucket Server. Required.
        api: https://mycompany.bitbucket.org
        # Credentials for Basic authentication. Required for private repositories.
        basicAuth:
          # The username to authenticate with
          username: myuser
          # Reference to a Secret containing the password or personal access token.
          passwordRef:
            secretName: mypassword
            key: password
      # Labels are not supported by Bitbucket Server, so filtering by label is not possible.
      # Filter PRs using the source branch name. (optional)
      filters:
      - branchMatch: ".*-argocd"
  template:
  # ...
  • project: Bitbucket项目的必需名称
  • repo: Bitbucket存储库的必需名称。
  • api: 需要URL访问Bitbucket REST API。对于上面的示例,将提出API请求https://mycompany.bitbucket.org/rest/api/1.0/projects/myproject/repos/myrepository/pull-requests
  • branchMatch: 可选的REGEXP过滤器,该过滤器应匹配源分支名称。这是Bitbucket服务器不支持的标签的替代品。

如果要访问私人存储库,则还必须提供基本验证的凭据(这是当前唯一支持的验证): * username:可以使用的用户名。它只需要阅读相关存储库的访问。 * passwordRef:包含Secret或个人访问令牌的密钥名称和键,用于请求。

Bitbucket Cloud
从Bitbucket云上托管的回购中提取拉的请求。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - pullRequest:
        bitbucket:
          # Workspace name where the repoistory is stored under. Required.
          owner: myproject
          # Repository slug. Required.
          repo: myrepository
          # URL of the Bitbucket Server. (optional) Will default to 'https://api.bitbucket.org/2.0'.
          api: https://api.bitbucket.org/2.0
          # Credentials for Basic authentication (App Password). Either basicAuth or bearerToken
          # authentication is required to access private repositories
          basicAuth:
            # The username to authenticate with
            username: myuser
            # Reference to a Secret containing the password or personal access token.
            passwordRef:
              secretName: mypassword
              key: password
          # Credentials for Bearer Token (App Token) authentication. Either basicAuth or bearerToken
          # authentication is required to access private repositories
          bearerToken:
            tokenRef:
              secretName: repotoken
              key: token
        # Labels are not supported by Bitbucket Cloud, so filtering by label is not possible.
        # Filter PRs using the source branch name. (optional)
        filters:
          - branchMatch: ".*-argocd"
  template:
  # ...
  • owner: Bitbucket工作区的必需名称
  • repo: Bitbucket存储库的必需名称。
  • api: 可选的URL访问Bitbucket REST API。对于上面的示例,将提出API请求https://api.bitbucket.org/2.0/repositories/{workspace}/{repo_slug}/pullrequests. If not set, defaults to https://api.bitbucket.org/2.0
  • branchMatch:可选的REGEXP过滤器,该过滤器应匹配源分支名称。这是Bitbucket服务器不支持的标签的替代品。

如果要访问私人存储库,Argo CD将需要凭据才能访问Bitbucket Cloud中的存储库。您可以使用BitBucket应用程序密码(每个用户生成,使用整个工作区)或BitBucket应用程序令牌(每个存储库生成,仅访问仅限存储库范围)。如果定义了应用程序密码和应用程​​序令牌,则将使用应用程序令牌。

要使用BitBucket App密钥,请使用BasicAuth部分。 - username:可以使用的用户名。它只需要阅读相关存储库的访问。 - PasswordRef:包含密钥或个人访问令牌的秘密名称和键,用于请求。

如果是Bitbucket应用程序令牌,请与BearerToken部分一起使用。 - tokenref:包含用于请求的应用程序令牌的密钥名称和键。

Azure DevOps
指定要获取拉动请求的组织,项目和存储库。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      azuredevops:
        # Azure DevOps org to scan. Required.
        organization: myorg
        # Azure DevOps project name to scan. Required.
        project: myproject
        # Azure DevOps repo name to scan. Required.
        repo: myrepository
        # The Azure DevOps API URL to talk to. If blank, use https://dev.azure.com/.
        api: https://dev.azure.com/
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: azure-devops-token
          key: token
        # Labels is used to filter the PRs that you want to target. (optional)
        labels:
        - preview
      requeueAfterSeconds: 1800
  template:
  # ...
  • organization: Azure DevOps组织的必需名称。
  • project: Azure DevOps项目的必需名称。
  • repo: Azure DevOps存储库的必需名称。
  • api: 如果使用自托管的Azure DevOps存储库,则可以访问它的URL。 (选修的)
  • tokenRef: 包含Azure DevOps访问令牌的秘密名称和键,用于请求。如果未指定,将提出匿名请求,该请求的利率限制较低,只能看到公共存储库。 (选修的)
  • labels: 将PR过滤到包含列出的所有标签的人。 (选修的)

Filters
过滤器允许选择要生成哪些拉的请求。每个过滤器都可以声明一个或多个条件,所有条件必须通过。如果存在多个过滤器,则可以将任何存储库匹配。如果未指定过滤器,则将处理所有拉的请求。当前,与SCM提供商过滤器进行比较时,只有一部分过滤器。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      # ...
      # Include any pull request ending with "argocd". (optional)
      filters:
      - branchMatch: ".*-argocd"
  template:
  # ...
  • branchMatch: 与源分支名称相匹配的正则配音。
  • targetBranchMatch: 正则与目标分支名称相匹配。

GitHub和GitLab还支持labels过滤器。

Template
与所有生成器一样,可以在生成的应用程序中更换几个密钥。

以下是一个全面的舵申请示例;

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
    # ...
  template:
    metadata:
      name: 'myapp-{{.branch}}-{{.number}}'
    spec:
      source:
        repoURL: 'https://github.com/myorg/myrepo.git'
        targetRevision: '{{.head_sha}}'
        path: kubernetes/
        helm:
          parameters:
          - name: "image.tag"
            value: "pull-{{.head_sha}}"
      project: "my-project"
      destination:
        server: https://kubernetes.default.svc
        namespace: default

而且,这是一个强大的kustomize示例;

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
    # ...
  template:
    metadata:
      name: 'myapp-{{.branch}}-{{.number}}'
    spec:
      source:
        repoURL: 'https://github.com/myorg/myrepo.git'
        targetRevision: '{{.head_sha}}'
        path: kubernetes/
        kustomize:
          nameSuffix: '{{.branch}}'
          commonLabels:
            app.kubernetes.io/instance: '{{.branch}}-{{.number}}'
          images:
          - 'ghcr.io/myorg/myrepo:{{.head_sha}}'
      project: "my-project"
      destination:
        server: https://kubernetes.default.svc
        namespace: default
  • number: 拉请求的ID号。
  • branch: 拉申请头的分支的名称。
  • branch_slug: 将清理该分支名称,以符合RFC 1123中定义的DNS标签标准,并将其截断为50个字符,以便为其附加/后缀带有13个字符。
  • target_branch: 拉请请求的目标分支的名称。
  • target_branch_slug: 目标分支名称将被清洗,以符合RFC 1123中定义的DNS标签标准,并将其截断为50个字符,以便为其附加/后缀添加13个字符提供空间。
  • head_sha: 这是拉申请的头部。
  • head_short_sha: 这是拉力请求的头部简短(如果较短,则为8个字符长或头部的长度)。
  • head_short_sha_7: 这是拉力请求的头部简短(长7个字符或头部的长度,如果较短)。
  • labels: 拉请求标签的数组。 (仅针对GO Template Applicationset表明。)

Webhook配置
使用拉动请求生成器时,Applicationset Controller会对每requeueAfterSeconds间隔进行轮询(默认为每30分钟)以检测更改。为了从轮询中消除此延迟,可以将Applicationset Webhook服务器配置为接收Webhook事件,这将触发Pull request Generator的应用程序生成。

该配置几乎与GIT生成器中描述的配置相同,但是有一个区别:如果还要使用拉请请求生成器,则还配置了以下设置。

Applicationset控制器Webhook不使用与此处定义的API服务器相同的Webhook。应用程序集将Webhook服务器视为类型clusterip的服务。需要创建应用程序集特定的入口资源来将此服务公开到Webhook源。

GitHub Webhook配置
在第1节中,“Create the webhook in the Git provider”,添加一个事件,以便在更改,封闭或标签更改时将发送Webhook请求。

使用URI /api/webhook添加Webhook URL,然后选择内容类型作为JSON
在这里插入图片描述
选择Let me select individual events,然后启用复选框以获取Pull requests
在这里插入图片描述
下一个操作发生时,拉力请求生成器将要求。

  • opened
  • closed
  • reopened
  • labeled
  • unlabeled
  • synchronized

有关每个事件的更多信息,请参阅官方文档

Gitlab Webhook配置
启用触发器列表中“Merge request events”的复选框。
在这里插入图片描述
下一个操作发生时,拉力请求生成器将要求。

  • open
  • close
  • reopen
  • update
  • merge

有关每个事件的更多信息,请参阅官方文档

生命周期
当满足配置的条件时发现拉动请求时,将生成应用程序 - 即,当拉动请求与指定的labels 和/或 pullrequestState匹配时GitHub。当拉请请求不再符合指定条件时,将删除申请。

发布(Post)选择所有生成器

选择器允许使用Kubernetes Common Labelselector格式根据生成的值进行过滤。在示例中,列表生成器生成了一个两个应用程序,然后通过键值过滤,以仅选择值stagingenv

示例:列表生成器 +发布生成器

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - list:
      elements:
        - cluster: engineering-dev
          url: https://kubernetes.default.svc
          env: staging
        - cluster: engineering-prod
          url: https://kubernetes.default.svc
          env: prod
    selector:
      matchLabels:
        env: staging
  template:
    metadata:
      name: '{{.cluster}}-guestbook'
    spec:
      project: default
      source:
        repoURL: https://github.com/argoproj-labs/applicationset.git
        targetRevision: HEAD
        path: examples/list-generator/guestbook/{{.cluster}}
      destination:
        server: '{{.url}}'
        namespace: guestbook

列表生成器 +发布生成器生成一组参数:

- cluster: engineering-dev
  url: https://kubernetes.default.svc
  env: staging

也可以将MatchExpressions用于更强大的选择器。

spec:
  generators:
    - clusters: {}
      selector:
        matchExpressions:
          - key: server
            operator: In
            values:
              - https://kubernetes.default.svc
              - https://some-other-cluster
插件生成器

插件允许提供自己的生成器。

  • 你可以用任何语言写
  • 简单:插件只是响应RPC HTTP请求。
  • 你可以在边锋或独立部署中使用它。
  • 你今天可以运行插件,无需等待3-5个月即可进行审核,批准,合并和ARGO软件版本。
  • 你可以将其与矩阵或合并结合。

要开始使用自己的插件,可以根据示例applicationset-hello-plugin生成新的存储库。

简单示例
使用生成器插件而不将其与矩阵或合并结合在一起。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myplugin
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - plugin:
        # Specify the configMap where the plugin configuration is located.
        configMapRef:
          name: my-plugin
        # You can pass arbitrary parameters to the plugin. `input.parameters` is a map, but values may be any type.
        # These parameters will also be available on the generator's output under the `generator.input.parameters` key.
        input:
          parameters:
            key1: "value1"
            key2: "value2"
            list: ["list", "of", "values"]
            boolean: true
            map:
              key1: "value1"
              key2: "value2"
              key3: "value3"

        # You can also attach arbitrary values to the generator's output under the `values` key. These values will be
        # available in templates under the `values` key.
        values:
          value1: something

        # When using a Plugin generator, the ApplicationSet controller polls every `requeueAfterSeconds` interval (defaulting to every 30 minutes) to detect changes.
        requeueAfterSeconds: 30
  template:
    metadata:
      name: myplugin
      annotations:
        example.from.input.parameters: "{{ index .generator.input.parameters.map "key1" }}"
        example.from.values: "{{ .values.value1 }}"
        # The plugin determines what else it produces.
        example.from.plugin.output: "{{ .something.from.the.plugin }}"
  • configMapRef.name: 一个包含用于RPC调用的插件配置的ConfigMap名称。
  • input.parameters: RPC调用插件中包含的输入参数。 (选修的)

插件的概念不应通过外在化GIT外部化数据来破坏Gitops的精神。目标是在特定情况下保持互补。例如,当使用Pullrequest生成器之一时,不可能检索与CI相关的参数(只有COMMH HASH可用),这限制了可能性。通过使用插件,可以从单独的数据源检索必要的参数,并使用它们扩展生成器的功能。

添加ConfigMap来配置插件的访问

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-plugin
  namespace: argocd
data:
  token: "$plugin.myplugin.token" # Alternatively $<some_K8S_secret>:plugin.myplugin.token
  baseUrl: "http://myplugin.plugin-ns.svc.cluster.local."
  • token: 预共享令牌用于身份验证HTTP请求(指向您在ArgoCD-Secret Secret中创建的正确键的点)
  • baseUrl: K8S服务的baseurl将您的插件公开在集群中。

存储凭据

apiVersion: v1
kind: Secret
metadata:
  name: argocd-secret
  namespace: argocd
  labels:
    app.kubernetes.io/name: argocd-secret
    app.kubernetes.io/part-of: argocd
type: Opaque
data:
  # ...
  # The secret value must be base64 encoded **once**.
  # this value corresponds to: `printf "strong-password" | base64`.
  plugin.myplugin.token: "c3Ryb25nLXBhc3N3b3Jk"
  # ...

选择
如果你想将敏感数据存储在另一个kubernetes Secret 中,而不是argocd-secret,而ArgoCD知道如何在kubernetes中的data下检查键,则只要configmap中的值以$为单位,那么Kubernetes的kubernetes Secret名称和:(colon)关键名称。

句法:$<k8s_secret_name>:<a_key_in_that_k8s_secret>

注意:密钥必须有标签app.kubernetes.io/part-of: argocd

例子
another-secret

apiVersion: v1
kind: Secret
metadata:
  name: another-secret
  namespace: argocd
  labels:
    app.kubernetes.io/part-of: argocd
type: Opaque
data:
  # ...
  # Store client secret like below.
  # The secret value must be base64 encoded **once**.
  # This value corresponds to: `printf "strong-password" | base64`.
  plugin.myplugin.token: "c3Ryb25nLXBhc3N3b3Jk"

HTTP server
一个简单的Python插件
可以将其部署为边车或独立部署(建议将其部署为独立部署)。
在示例中,令牌存储在此位置的文件中:/var/run/argo/doken

strong-password
import json
from http.server import BaseHTTPRequestHandler, HTTPServer

with open("/var/run/argo/token") as f:
    plugin_token = f.read().strip()


class Plugin(BaseHTTPRequestHandler):

    def args(self):
        return json.loads(self.rfile.read(int(self.headers.get('Content-Length'))))

    def reply(self, reply):
        self.send_response(200)
        self.end_headers()
        self.wfile.write(json.dumps(reply).encode("UTF-8"))

    def forbidden(self):
        self.send_response(403)
        self.end_headers()

    def unsupported(self):
        self.send_response(404)
        self.end_headers()

    def do_POST(self):
        if self.headers.get("Authorization") != "Bearer " + plugin_token:
            self.forbidden()

        if self.path == '/api/v1/getparams.execute':
            args = self.args()
            self.reply({
                "output": {
                    "parameters": [
                        {
                            "key1": "val1",
                            "key2": "val2"
                        },
                        {
                            "key1": "val2",
                            "key2": "val2"
                        }
                    ]
                }
            })
        else:
            self.unsupported()


if __name__ == '__main__':
    httpd = HTTPServer(('', 4355), Plugin)
    httpd.serve_forever()

用卷发执行getParams:

curl http://localhost:4355/api/v1/getparams.execute -H "Authorization: Bearer strong-password" -d \
'{
  "applicationSetName": "fake-appset",
  "input": {
    "parameters": {
      "param1": "value1"
    }
  }
}'

这里有些事情要注意:

  • 你只需要实现调用/api/v1/getparams.execute
  • 你应该检查Authorization标头是否包含与/var/run/argo/doken相同的bearer值。返回403如果不是
  • 输入参数包含在请求主体中,并且可以使用input.parameters变量访问。
  • 输出必须始终是嵌套在输出下的对象图的列表。
  • generator.input.parametersvalues是保留的密钥。如果存在插件输出中,则这些键将被Input.parametersvalues插件生成器规范中的参数和值密钥覆盖。

使用矩阵并拉请求示例
在下面的示例中,插件实现将返回给定分支的一组图像摘要。返回的列表仅包含与该分支最新构建的图像相对应的一项。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: fb-matrix
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - matrix:
        generators:
          - pullRequest:
              github: ...
              requeueAfterSeconds: 30
          - plugin:
              configMapRef:
                name: cm-plugin
              input:
                parameters:
                  branch: "{{.branch}}" # provided by generator pull request
              values:
                branchLink: "https://git.example.com/org/repo/tree/{{.branch}}"
  template:
    metadata:
      name: "fb-matrix-{{.branch}}"
    spec:
      source:
        repoURL: "https://github.com/myorg/myrepo.git"
        targetRevision: "HEAD"
        path: charts/my-chart
        helm:
          releaseName: fb-matrix-{{.branch}}
          valueFiles:
            - values.yaml
          values: |
            front:
              image: myregistry:{{.branch}}@{{ .digestFront }} # digestFront is generated by the plugin
            back:
              image: myregistry:{{.branch}}@{{ .digestBack }} # digestBack is generated by the plugin
      project: default
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true
      destination:
        server: https://kubernetes.default.svc
        namespace: "{{.branch}}"
      info:
        - name: Link to the Application's branch
          value: "{{values.branchLink}}"

为了显示 :

  • 生成器刷子将返回,例如2个分支:feature-branch-1和feature-branch-2。
  • 然后,发电机插件将执行2个请求,如下所示:
curl http://localhost:4355/api/v1/getparams.execute -H "Authorization: Bearer strong-password" -d \
'{
  "applicationSetName": "fb-matrix",
  "input": {
    "parameters": {
      "branch": "feature-branch-1"
    }
  }
}'

然后

curl http://localhost:4355/api/v1/getparams.execute -H "Authorization: Bearer strong-password" -d \
'{
  "applicationSetName": "fb-matrix",
  "input": {
    "parameters": {
      "branch": "feature-branch-2"
    }
  }
}'

对于每个调用,它将返回一个唯一的结果,例如:

{
  "output": {
    "parameters": [
      {
        "digestFront": "sha256:a3f18c17771cc1051b790b453a0217b585723b37f14b413ad7c5b12d4534d411",
        "digestBack": "sha256:4411417d614d5b1b479933b7420079671facd434fd42db196dc1f4cc55ba13ce"
      }
    ]
  }
}

然后

{
  "output": {
    "parameters": [
      {
        "digestFront": "sha256:7c20b927946805124f67a0cb8848a8fb1344d16b4d0425d63aaa3f2427c20497",
        "digestBack": "sha256:e55e7e40700bbab9e542aba56c593cb87d680cefdfba3dd2ab9cfcb27ec384c2"
      }
    ]
  }
}

在此示例中,通过组合两者,可以确保有一个或多个拉动请求可用,并且已经正确生成了生成的标签。仅凭提交哈希,这是不可能的,因为仅哈希没有证明构建的成功。

模板字段
Templates

Applicationset spec 的模板字段用于生成Argo CD Application资源。

Applicationset正在使用FastTemplate,但很快就会弃用使用GO模板。

模板字段

通过将来自生成器的参数与模板的字段(通过{{values}})组合来创建ARGO CD应用程序,并从该字段中产生正确的Application并将其应用于群集。

这是集群生成器的模板子字段:

# (...)
 template:
   metadata:
     name: '{{cluster}}-guestbook'
   spec:
     source:
       repoURL: https://github.com/infra-team/cluster-deployments.git
       targetRevision: HEAD
       path: guestbook/{{cluster}}
     destination:
       server: '{{url}}'
       namespace: guestbook

模板子字段直接对应于Argo CD应用程序资源的 spec

  • project 请参考使用中正在使用的ARGO CD项目(默认情况下可以使用默认的Argo CD项目)
  • source 定义从哪些GIT存储库提取所需的应用程序表现
    • repoURL: 存储库的URL(例如https://github.com/argoproj/argocd-example-apps.git
    • targetRevision: 存储库的修订(tag/branch/commit)(例如HEAD
    • path: 在Kubernetes(and/or Helm, Kustomize, Jsonnet resources)群体所在的存储库中的路径
  • destination: 定义哪个kubernetes群集/名称空间要部署到
    • name:集群的名称(在Argo CD中)部署到
    • server: 集群的API服务器URL(示例:https://kubernetes.default.svc)
    • namespace: 目标名称空间在其中部署清单从来源(示例:my-app-namespace)

笔记:

  • 引用的集群必须在Argo CD中定义,以使应用程序控制器使用它们
  • 只能指定nameserver中的一个:如果两者都指定,则返回错误。

模板的metadata字段也可用于设置应用程序name,或在应用程序中添加标签或注释。

虽然Applicationset spec提供了一种基本的模板形式,但并非打算替换诸如Kustomize,Helm或Jsonnet等工具的全面配置管理功能。

部署ApplicationSet资源作为Helm图表的一部分
Applicationset使用与Helm({{}})相同的模板符号。如果Applicationset模板未写为Helm String文字,则Helm将抛出未定义的函数“cluster”之类的错误。为了避免该错误,请将模板写为舵字符串字面。例如:

    metadata:
      name: '{{`{{.cluster}}`}}-guestbook'

仅当使用Helm来部署应用程序网资源时,这才适用。

生成器模板

除了在Applicationset资源的.spec.template中指定模板外,还可以在生成器中指定模板。这对于覆盖规格级模板的值很有用。

生成器的模板字段优先于spectemplate字段:

  • 如果两个模板都包含相同的字段,则将使用生成器的字段值。
  • 如果只有其中一个模板字段具有值,则将使用该值。

因此,可以将生成器模板视为针对外部spec级模板字段的补丁。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
spec:
  generators:
  - list:
      elements:
        - cluster: engineering-dev
          url: https://kubernetes.default.svc
      template:
        metadata: {}
        spec:
          project: "default"
          source:
            targetRevision: HEAD
            repoURL: https://github.com/argoproj/argo-cd.git
            # New path value is generated here:
            path: 'applicationset/examples/template-override/{{cluster}}-override'
          destination: {}

  template:
    metadata:
      name: '{{cluster}}-guestbook'
    spec:
      project: "default"
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        # This 'default' value is not used: it is replaced by the generator's template path, above
        path: applicationset/examples/template-override/default
      destination:
        server: '{{url}}'
        namespace: guestbook

(可以在此处(https://github.com/argoproj/argo-cd/tree/master/applicationset/examples/template-override)找到完整的示例。)

在此示例中,应用程序集控制器将使用列表生成器生成的路径生成一个应用程序资源,而不是.spec.template中定义的path值。

模板补丁
模板仅在字符串类型上可用。但是,某些用例可能需要在其他类型上应用模板。
例子:

  • 有条件设置自动同步策略。
  • 有条件地将选择布尔值切换为true
  • 从列表中添加多个helm值文件。

TemplatePatch功能可实现高级模板,并支持JSON和YAML。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
spec:
  goTemplate: true
  generators:
  - list:
      elements:
        - cluster: engineering-dev
          url: https://kubernetes.default.svc
          autoSync: true
          prune: true
          valueFiles:
            - values.large.yaml
            - values.debug.yaml
  template:
    metadata:
      name: '{{.cluster}}-deployment'
    spec:
      project: "default"
      source:
        repoURL: https://github.com/infra-team/cluster-deployments.git
        targetRevision: HEAD
        path: guestbook/{{ .cluster }}
      destination:
        server: '{{.url}}'
        namespace: guestbook
  templatePatch: |
    spec:
      source:
        helm:
          valueFiles:
          {{- range $valueFile := .valueFiles }}
            - {{ $valueFile }}
          {{- end }}
    {{- if .autoSync }}
      syncPolicy:
        automated:
          prune: {{ .prune }}
    {{- end }}

templatePatch可以将任意更改应用于模板。如果参数包括不信任的用户输入,则可能可以将恶意更改注入模板中。建议仅将templatePatch与受信任的输入一起使用,或在模板中使用之前仔细逃脱输入。对toJson的管道输入应有助于防止用户成功地向Newlines注入字符串。
模板绘制中不支持spec.project字段。如果需要更改项目,则可以在template字段中使用spec.project字段。
编写时templatePatch,你正在制作补丁。因此,如果补丁包含一个空的spec: # nothing in here,它将有效地清除现有字段。有关此行为的示例,请参阅#17040

已暂停,请参考https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/GoTemplate/,下一步改为总结式。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琴 韵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值