All Products
Search
Document Center

Container Service for Kubernetes:Use ApplicationSet for multi-environment deployments and dependencies

Last Updated:Mar 26, 2026

Use a Matrix Generator and a RollingSync strategy in a single ApplicationSet to enforce both environment sequencing (dev before staging) and within-environment dependency ordering (app1 before app2).

Background

When you deploy a web application with interdependent components — such as a database, backend, and frontend — you must deploy them in a specific order: Database > Backend > Frontend. In ACK One GitOps, each component maps to a separate Argo CD Application, so controlling deployment order across multiple Applications requires additional orchestration.

ApplicationSet automates this by generating multiple Argo CD Applications from a single template, making it well-suited for multi-cluster or multi-environment setups. Managing application dependencies _and_ multi-environment sequencing simultaneously requires a more advanced pattern.

This guide shows how to combine two ApplicationSet features in a single resource:

  1. A Matrix Generator generates Argo CD Applications for each environment (dev and staging) and attaches labels that identify the application name and environment.

  2. A RollingSync strategy (from Progressive Syncs) reads those labels to enforce the deployment order: dev-app1dev-app2staging-app1staging-app2.

image

Progressive Syncs

Progressive Syncs controls the creation and update order of Argo CD Applications based on their dependencies and health status. Define a steps list; the ApplicationSet controller monitors each Application's health and moves to the next step only after all Applications in the current step reach Healthy status.

Supported resources

Progressive Syncs watches for the Progressing state reported by an Argo CD Application during a pod rollout. DaemonSet, StatefulSet, and Argo Rollouts are supported. Any resource type that has a health check and can report a Progressing state also works.

Progressive Syncs requires high availability mode. Enable this mode before proceeding.

RollingSync matching behavior

Before writing the ApplicationSet YAML, review how rollingSync.steps works:

  • Applications are grouped using labels and matchExpressions.

  • All matchExpressions in a step must be true for an Application to be selected (AND logic).

  • The In and NotIn operators match if at least one value is true (OR logic within a single expression).

  • All Applications in a step must become Healthy before the controller moves to the next step.

Example application structure

This guide uses this example repository, which contains two applications, app1 and app2. app2 depends on app1, and both must be deployed to dev and staging. Both applications are managed by Kustomize, and each environment can contain multiple regions (this example uses only the bj region).

manifests
└── apps
    ├── env
    │   ├── dev
    │   │   └── config.json
    │   └── staging
    │       └── config.json
    ├── app1
    │   ├── base
    │   │   ├── deployment.yaml
    │   │   ├── kustomization.yaml
    │   │   └── service.yaml
    │   └── overlay
    │       ├── dev
    │       │   └── bj
    │       │       ├── deployment.yaml
    │       │       └── kustomization.yaml
    │       └── staging
    │           └── bj
    │               ├── deployment.yaml
    │               └── kustomization.yaml
    └── app2
        ├── base
        │   ├── deployment.yaml
        │   ├── kustomization.yaml
        │   └── service.yaml
        └── overlay
            ├── dev
            │   └── bj
            │       ├── deployment.yaml
            │       └── kustomization.yaml
            └── staging
                └── bj
                    ├── deployment.yaml
                    └── kustomization.yaml
  • manifests/apps/env: Per-environment configuration. The config.json file in each directory sets the cluster_address mapping used to route Applications to the correct cluster.

  • manifests/apps/app1 and manifests/apps/app2: Application manifests, each with a base directory and environment-specific overlays.

Important

To use this example, fork the repository to your own account and update the cluster_address in each config.json to your associated cluster's API Server endpoint.

Prerequisites

Before you begin, ensure that you have:

Step 1: Enable Progressive Syncs

Progressive Syncs is disabled by default. Enable it by adding a key to the argocd-cmd-params-cm ConfigMap and restarting the controller.

  1. Edit the ConfigMap using the Fleet kubeconfig.

    kubectl edit cm -n argocd argocd-cmd-params-cm

    Add the following key under data:

    apiVersion: v1
    data:
      applicationsetcontroller.enable.progressive.syncs: "true"
      ...
    kind: ConfigMap
    metadata:
      name: argocd-cmd-params-cm
      namespace: argocd
      ...
  2. Restart the argocd-application-controller to apply the change.

    kubectl rollout restart deployment argocd-application-controller -n argocd

Step 2: Create the ApplicationSet

  1. Log in to the ACK One console. In the left navigation pane, choose Fleet > Multi-cluster GitOps.

  2. Click Create Multi-cluster Application > GitOps. On the Create Multi-cluster Application - GitOps page, click Create from YAML and apply the following YAML.

    When pathParamPrefix is set, all variables from that generator must use the prefix. For example, {{.path.basename}} becomes {{.env.path.basename}} when the prefix is env.
    Parameter Description Example values
    {{.env.path.basename}} Base name of the environment directory dev, staging
    {{.target.path.path}} Full path to the app overlay directory manifests/apps/app2/overlay/dev/bj
    {{index .target.path.segments 2}} App name extracted from path segments app1, app2
    apiVersion: argoproj.io/v1alpha1
    kind: ApplicationSet
    metadata:
      name: dependency-apps
      namespace: argocd
    spec:
      goTemplate: true
      goTemplateOptions: ["missingkey=error"]
      generators:
        - matrix:
            generators:
              - git:
                  repoURL: https://github.com/AliyunContainerService/gitops-demo.git
                  revision: main
                  pathParamPrefix: env
                  files:
                  - path: "manifests/apps/env/*/config.json"
              - git:
                  repoURL: https://github.com/AliyunContainerService/gitops-demo.git
                  revision: main
                  pathParamPrefix: target
                  directories:
                  - path: "manifests/apps/app1/overlay/{{.env.path.basename}}/*"
        - matrix:
            generators:
              - git:
                  repoURL: https://github.com/AliyunContainerService/gitops-demo.git
                  revision: HEAD
                  pathParamPrefix: env
                  files:
                  - path: "manifests/apps/env/*/config.json"
              - git:
                  repoURL: https://github.com/AliyunContainerService/gitops-demo.git
                  revision: HEAD
                  pathParamPrefix: target
                  directories:
                  - path: "manifests/apps/app2/overlay/{{.env.path.basename}}/*"
      strategy:
        type: RollingSync
        rollingSync:
          steps:
            - matchExpressions:
                - key: app.kubernetes.io/instance
                  operator: In
                  values:
                    - app1
                - key: environment
                  operator: In
                  values:
                    - dev
            - matchExpressions:
                - key: app.kubernetes.io/instance
                  operator: In
                  values:
                    - app2
                - key: environment
                  operator: In
                  values:
                    - dev
            - matchExpressions:
                - key: app.kubernetes.io/instance
                  operator: In
                  values:
                    - app1
                - key: environment
                  operator: In
                  values:
                    - staging
            - matchExpressions:
                - key: app.kubernetes.io/instance
                  operator: In
                  values:
                    - app2
                - key: environment
                  operator: In
                  values:
                    - staging
      template:
        metadata:
          name: '{{.env.path.basename}}-{{index .target.path.segments 2}}-{{.target.path.basename}}'
          labels:
            app.kubernetes.io/instance: '{{index .target.path.segments 2}}'
            environment: '{{.env.path.basename}}'
        spec:
          project: default
          source:
            repoURL: https://github.com/AliyunContainerService/gitops-demo.git
            targetRevision: HEAD
            path: '{{.target.path.path}}'
          destination:
            server: '{{index .cluster_address .target.path.basename}}'
            namespace: demo
          syncPolicy:
            automated:
              prune: true
              selfHeal: true
            retry:
              limit: 5
              backoff:
                duration: 5s
                maxDuration: 3m0s
                factor: 2
            syncOptions:
              - CreateNamespace=true

    This ApplicationSet uses a Matrix Generator to generate four Argo CD Applications (two for app1, two for app2) and a RollingSync strategy from Progressive Syncs to enforce the deployment order. How the Matrix Generator works Each matrix block combines two Git generators: one that reads config.json files to discover environments, and one that scans overlay directories to discover app variants. The pathParamPrefix parameter namespaces the variables from each generator to avoid conflicts. Why labels must be explicit The rollingSync.steps matcher reads labels on the generated Argo CD Application resources. Labels are not set automatically — they must be defined in .spec.template.metadata.labels. If a label is missing, the step matcher cannot select the Application, and the deployment will not proceed.

Important

Keep production and non-production (development, testing, and staging) environments in separate ApplicationSet resources. This limits the blast radius of any misconfiguration and lets you enforce an explicit promotion gate for production by using manual sync.

Step 3: Verify the deployment order

The ApplicationSet generates four Application instances. Each starts only after the previous one finishes syncing and reaches Healthy status, following the order dev-app1dev-app2staging-app1staging-app2.

Console

  1. Log in to the ACK One console. In the left navigation pane, choose Fleet > Multi-cluster GitOps.

  2. Find the target multi-cluster application and click its name to see the Application instances. The applications deploy in sequence. After each step completes, the next application starts syncing.

    1. Deploy dev-app1. image

    2. Deploy dev-app2. image

    3. Deploy staging-app1. image

    4. Deploy staging-app2. image

    image

CLI

Run the following command with the Fleet kubeconfig to check Application status.

kubectl -n argocd get app

The table below shows the expected status at each deployment stage. Each Application moves from OutOfSync / Missing to Synced / Progressing while deploying, and then to Synced / Healthy when complete.

Application Stage 1: dev-app1 deploying Stage 2: dev-app2 deploying Stage 3: staging-app1 deploying Stage 4: staging-app2 deploying
dev-app1-bj Synced / Progressing Synced / Healthy Synced / Healthy Synced / Healthy
dev-app2-bj OutOfSync / Missing Synced / Progressing Synced / Healthy Synced / Healthy
staging-app1-bj OutOfSync / Missing OutOfSync / Missing Synced / Progressing Synced / Healthy
staging-app2-bj OutOfSync / Missing OutOfSync / Missing OutOfSync / Missing Synced / Progressing