> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/continuous-delivery/use-gitops/argo-rollouts/argo-rollouts-with-cv.md).

# Argo Rollouts with Continuous Verification

Continuous Verification (CV) validates deployments by analyzing metrics and logs from your monitoring tools. When combined with Argo Rollouts canary deployments, CV ensures each canary stage is healthy before promoting to the next stage, providing automated safety checks throughout the progressive rollout.

### Overview <a href="#overview" id="overview"></a>

Argo Rollouts with Continuous Verification enables you to:

* **Validate each canary stage:** CV analyzes metrics and logs at each canary percentage (10%, 25%, 50%, 100%) before promotion
* **Automated rollback:** If CV detects anomalies, it can automatically trigger rollback before the issue affects more users
* **Machine learning-based analysis:** Harness uses ML algorithms to identify normal behavior and detect anomalies
* **Multi-stage validation:** Each canary stage is independently validated before traffic increases

#### How CV Works with Canary Deployments <a href="#how-cv-works-with-canary-deployments" id="how-cv-works-with-canary-deployments"></a>

In a canary deployment with CV:

1. **Traffic Split:** Argo Rollouts shifts a percentage of traffic to the new version (e.g., 10%)
2. **CV Analysis:** The Verify step analyzes metrics and logs from the canary pods for the configured duration
3. **Health Decision:** CV determines if the canary is healthy based on sensitivity settings
4. **Promotion or Rollback:** If healthy, the rollout promotes to the next stage. If unhealthy, CV can trigger rollback
5. **Repeat:** This process repeats for each canary stage (10% → 25% → 50% → 100%)

### Prerequisites <a href="#prerequisites" id="prerequisites"></a>

Before setting up Argo Rollouts with Continuous Verification, ensure you have:

* **Argo Rollouts installed** in your cluster (see [Argo Rollouts Overview](/continuous-delivery/use-gitops/argo-rollouts/argo-rollouts-overview.md))
* **Harness GitOps Agent** configured and connected to your cluster
* **GitOps Application** with a Rollout resource configured for canary deployment
* **Monitored Service** configured in Harness with health sources (APM or logging tools)
* **Health sources connected:** Prometheus, Datadog, New Relic, or other supported monitoring tools
* **Pipeline created** with deployment stage configured (see [Managing Rollouts in Harness Pipeline](/continuous-delivery/use-gitops/argo-rollouts/managing-rollouts-in-harness-pipelines.md))

For more information about setting up Continuous Verification, see [Verify Overview](/continuous-delivery/use-continuous-delivery/verify-deployments/verify-deployments-with-the-verify-step.md).

### Step-by-Step Guide <a href="#step-by-step-guide" id="step-by-step-guide"></a>

This guide walks you through the complete setup from creating a GitOps Application to running a pipeline with Continuous Verification.

#### Step 1: Prepare Your Git Repository <a href="#step-1-prepare-your-git-repository" id="step-1-prepare-your-git-repository"></a>

First, prepare your Git repository with the Rollout manifest and related Kubernetes resources.

**1.1 Create the Rollout Manifest**

Create a Rollout manifest file (e.g., `rollout.yaml`) in your Git repository. Your Argo Rollout manifest should define a canary strategy with pause steps. Here's a production-ready example:

<details>

<summary>Rollout manifest example</summary>

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: loans-api
  labels:
    app: loans-api
    strategy: canary
spec:
  replicas: 2
  selector:
    matchLabels:
      app: loans-api
  template:
    metadata:
      labels:
        app: loans-api
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/port: '8083'
        prometheus.io/path: /metrics
    spec:
      containers:
      - name: loans-api
        image: docker.io/akshitmadanharness/loans-api:latest
        ports:
        - containerPort: 8083
        env:
        - name: ENVIRONMENT
          value: prod-na
        resources:
          requests:
            memory: 512Mi
            cpu: 400m
          limits:
            memory: 1Gi
            cpu: 800m
        livenessProbe:
          httpGet:
            path: /health
            port: 8083
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8083
          initialDelaySeconds: 5
          periodSeconds: 5
  minReadySeconds: 30
  revisionHistoryLimit: 3
  strategy:
    canary:
      maxSurge: 25%
      maxUnavailable: 0
      steps:
      - setWeight: 10
      - pause: {}
      - setWeight: 25
      - pause: {}
      - setWeight: 50
      - pause: {}
      - setWeight: 100
```

</details>

**Key configuration elements:**

* **`replicas: 2`:** Number of pod replicas for the stable version. During canary, additional pods are created for the new version.
* **`strategy.canary.steps`:** Defines the canary progression stages:
  * **`setWeight: 10`** → Shifts 10% of traffic to canary (initial validation stage)
  * **`setWeight: 25`** → Increases to 25% traffic
  * **`setWeight: 50`** → Increases to 50% traffic
  * **`setWeight: 100`** → Full promotion to 100% traffic
  * **`pause: {}`:** Pauses the rollout at each stage, waiting for CV validation or manual promotion
* **`maxSurge: 25%`:** Allows up to 25% additional pods during rollout (beyond the replica count). This ensures capacity for both stable and canary versions.
* **`maxUnavailable: 0`:** Ensures zero downtime by preventing any pods from being unavailable during the rollout.
* **`minReadySeconds: 30`:** Waits 30 seconds after a pod becomes ready before considering it available. This helps ensure pods are truly ready before receiving traffic.
* **`revisionHistoryLimit: 3`:** Keeps the last 3 rollout revisions for rollback purposes.
* **Prometheus annotations:** The `prometheus.io/scrape`, `prometheus.io/port`, and `prometheus.io/path` annotations enable Prometheus to scrape metrics from the pods. This is essential for CV to collect metrics during canary validation.
* **Health probes:**
  * **`livenessProbe`:** Checks if the container is running (restarts if unhealthy)
  * **`readinessProbe`:** Checks if the container is ready to receive traffic
* **Resource limits:** Defines CPU and memory requests and limits to ensure proper resource allocation and prevent resource contention.

**CV Integration Points:**

* Each `pause: {}` step is where your Verify step will validate the canary
* Prometheus annotations enable CV to collect metrics for analysis
* Health probes ensure pods are healthy before CV analysis begins

**1.2 Commit and Push to Git**

1. Save the Rollout manifest to your Git repository
2. Commit the changes
3. Push to your repository (e.g., `main` branch)

Your repository structure should look similar to this:

```
my-gitops-repo/
├── apps/
│   └── loans-api/
│       ├── rollout.yaml          # Rollout manifest
│       ├── service.yaml          # Service for traffic routing (optional)
│       └── kustomization.yaml    # Kustomize configuration (if using Kustomize)
└── README.md
```

#### Step 2: Create a Harness GitOps Application <a href="#step-2-create-a-harness-gitops-application" id="step-2-create-a-harness-gitops-application"></a>

You must create a GitOps Application before you can use it in a pipeline. The GitOps Application connects your Git repository to your Kubernetes cluster.

**2.1 Navigate to GitOps Applications**

1. In Harness, navigate to **Deployments > GitOps > Applications**
2. Click **+ New Application**

**2.2 Configure Application Basic Settings**

Configure the application basic information:

* **Name:** Enter a name for your application (e.g., `loans-api-gitops`)
* **GitOps Agent:** Select the GitOps Agent connected to your cluster
* **Service (optional):** Create or select a service to track this deployment (e.g., `loans-api`)
* **Environment (optional):** Create or select an environment (e.g., `prod-na`)

Click **Continue**.

**2.3 Configure Application Source**

On the **Source** page, configure where your Rollout manifests are located:

* **Repository Type:** Git
* **Repository URL:** Your Git repository URL (e.g., `https://github.com/org/my-gitops-repo`)
* **Target Revision:** Branch or tag (e.g., `main`, `master`)
* **Path:** Path to your Rollout manifests (e.g., `apps/loans-api/`)

If using Kustomize:

* Leave **Kustomize** options at their defaults, or configure as needed

Click **Continue**.

**2.4 Configure Application Destination**

Configure where the Rollout will be deployed:

* **Cluster:** Select your target cluster
* **Namespace:** Enter the namespace where the Rollout will be deployed (e.g., `default`)

Click **Create**.

**2.5 Sync the Application**

After creating the application, sync it to deploy the Rollout to your cluster:

1. In the application details page, click **Sync**
2. Configure sync options if needed:
   * Select **Target Revision** if needed (default is usually correct)
   * Leave other options at defaults
3. Click **Synchronize**

Wait for the sync to complete and the application to reach **Healthy** state.

**2.6 Verify Rollout is Deployed**

1. Navigate to the application's **Resources** tab
2. Verify the following resources appear:
   * **Rollout** resource (e.g., `loans-api`)
   * **Service** resources (if configured)
   * **ReplicaSet** created by the Rollout
   * **Pods** managed by the Rollout

All resources should show as **Healthy**.

![Rollout App Status](/files/phUlSwDk6IEwym3ip2wC)

**Your GitOps Application is now ready!** The Rollout is deployed and synced to your cluster.

#### Step 3: Create a Monitored Service <a href="#step-3-create-a-monitored-service" id="step-3-create-a-monitored-service"></a>

Before adding Verify steps, create a Monitored Service that connects to your health sources:

1. Navigate to **Service Reliability Management > Monitored Services**
2. Click **+ New Monitored Service**
3. Configure:
   * **Service:** Select the service associated with your GitOps Application
   * **Environment:** Select the environment where the rollout is deployed
   * **Name:** Enter a descriptive name (e.g., `loansapi_Prod_NA_GitOps_Product_Demo`)
4. Add **Health Sources:**

   * Click **+ Add New Health Source**
   * Select your monitoring tool (e.g., Prometheus, Datadog)
   * Configure metrics and queries
   * Save the health source

   ![Prom Health Source](/files/rGgIRW9Ihkiy4itvtdAQ)
5. Click **Save**

For detailed instructions, see [Create a Monitored Service](/service-reliability-management/use-srm/monitored-services/create-monitored-service.md).

#### Step 4: Create Your Pipeline <a href="#step-4-create-your-pipeline" id="step-4-create-your-pipeline"></a>

Now that your GitOps Application and Monitored Service are configured, create a pipeline to orchestrate the canary deployment with CV validation.

**4.1 Create a New Pipeline**

1. Navigate to **Deployments > Pipelines**
2. Click **+ New Pipeline**
3. Enter a pipeline name (e.g., `deploy-loans-api-canary`)
4. Select your project and organization

**4.2 Add a Deployment Stage**

1. Click **+ Add Stage**
2. Select **Deploy** stage type
3. Configure the stage:

**Stage Configuration:**

* **Name:** Give your stage a name (e.g., `Deploy Canary`)
* **Service:** Select the service that matches your GitOps Application (e.g., `loans-api`)
* **Environment:** Select the environment that matches your GitOps Application (e.g., `prod-na`)
* **Infrastructure:** Select the cluster/infrastructure

{% hint style="info" %}
**IMPORTANT**

**Critical:** The service, environment, and cluster must match what you configured in your GitOps Application. This is required for the GitOps Rollout step to find and manage your rollout.
{% endhint %}

**4.3 Configure Stage Execution**

1. Go to the **Execution** tab in your stage
2. You'll see default steps (Service, GitopsClusters) - these are fine
3. You can optionally add a **GitOps Sync** step if you want to sync changes before managing the rollout

**Note:** If your Rollout is already synced and healthy, you can skip the Sync step and go directly to the Rollout step.

**4.4 Add GitOps Sync Step (Optional)**

If you want to sync new changes from Git before managing the rollout:

1. Click **Add Step**
2. Search for and select **GitOps Sync**
3. Configure the step:
   * **Agent:** Select your GitOps Agent
   * **Application:** Select your GitOps Application
   * **Wait until healthy:** Check this to wait until the application is healthy
   * **Fail If Step Times Out:** Check if you want the step to fail on timeout
   * **Timeout:** Set appropriate timeout (e.g., `10m`)

#### Step 5: Add GitOps Rollout and Verify Steps <a href="#step-5-add-gitops-rollout-and-verify-steps" id="step-5-add-gitops-rollout-and-verify-steps"></a>

Add GitOps Rollout steps for each canary stage, followed by Verify steps for CV validation.

![Pipeline Canary with Rolout](/files/AIJf2Z7cmkUM2MJqLfdk)

**5.1 Add First Canary Stage (10%)**

1. Click **Add Step**
2. Search for and select **GitOps Rollout**
3. Configure the step:

**Step Parameters:**

* **Name:** `ArgoRollout Canary 10`
* **Timeout:** `10m`
* **Agent:** Select your GitOps Agent
* **Application:** Select your GitOps Application (e.g., `loans-api-gitops`)
* **Rollout Name:** Select your Rollout resource (e.g., `loans-api`)
* **Namespace:** Enter the namespace (e.g., `default`)

**Rollout Configuration:**

* **Wait until Health Status:** Select `Suspended`
* **Health Message:** Enter `CanaryPauseStep` (or use regex pattern like `Canary.*`)
* **Auto Action for Rollouts:** Leave empty (CV will validate first)
* **Fail On Timeout:** Check this box

This step will wait until the rollout is paused at the 10% canary stage.

1. In your pipeline, go to the **Execution** tab
2. Click **Add Step**
3. Search for and select **GitOps Rollout**
4. Configure the step:

**Step Parameters:**

* **Name:** `ArgoRollout Canary 10`
* **Timeout:** `10m`
* **Agent:** Select your GitOps Agent
* **Application:** Select your GitOps Application
* **Rollout Name:** Select your Rollout resource (e.g., `loans-api`)
* **Namespace:** Enter the namespace

**Rollout Configuration:**

* **Wait until Health Status:** Select `Suspended`
* **Health Message:** Enter `CanaryPauseStep` (or use regex pattern like `Canary.*`)
* **Auto Action for Rollouts:** Leave empty (CV will validate first)
* **Fail On Timeout:** Check this box

This step will wait until the rollout is paused at the 10% canary stage.

**5.2 Add Verify Step After First Canary Stage**

1. Click **Add Step** after the first GitOps Rollout step
2. Search for and select **Verify**
3. Configure the step:

**Step Parameters:**

* **Name:** `Verify_1`
* **Timeout:** `2h` (sufficient time for CV analysis)
* **Continuous Verification Type:** Select `Canary`
* **Sensitivity:** Select `High` (recommended for production)
* **Duration:** Select `5 min` (or adjust based on your needs)
* **Fail On No Analysis:** Check this to fail if no data is available

**Monitored Service:**

* **Monitored Service Type:** Select `Default`
* **Monitored Service Name:** Select the Monitored Service you created in Step 2

**Health Sources:**

* Verify your health sources are configured
* Add additional health sources if needed

This Verify step will analyze metrics and logs from the 10% canary stage.

**5.3 Add Wait Step (Optional)**

You can add a **Wait** step after the Verify step to pause the pipeline before promoting to the next stage. This gives you time to review CV results:

1. Click **Add Step**
2. Search for and select **Wait**
3. Configure:
   * **Name:** `Wait`
   * **Duration:** Set as needed (e.g., `5m`)

**5.4 Repeat for Remaining Canary Stages**

Add similar steps for the remaining canary stages:

* **ArgoRollout Canary 25** → **Verify\_2** → **Wait**
* **ArgoRollout Canary 50** → **Verify\_3** → **Wait**
* **ArgoRollout Canary 100** → Final verification (optional)

For each GitOps Rollout step:

* Update the **Name** to reflect the canary percentage (Canary 25, Canary 50, Canary 100)
* Keep **Wait until Health Status:** `Suspended`
* Keep **Health Message:** `CanaryPauseStep`

For each Verify step:

* Update the **Name** (Verify\_1, Verify\_2, Verify\_3)
* Keep the same CV configuration (Canary type, Sensitivity, Duration)
* Use the same Monitored Service

#### Step 6: Configure Verify Step for Canary Validation <a href="#step-6-configure-verify-step-for-canary-validation" id="step-6-configure-verify-step-for-canary-validation"></a>

The Verify step configuration is critical for proper canary validation:

**Continuous Verification Type**

Select **Canary** to match your deployment strategy. This tells CV to:

* Compare canary pods (new version) against stable pods (old version)
* Analyze metrics from both versions simultaneously
* Detect anomalies in the canary version relative to baseline

**Sensitivity**

Choose the sensitivity level based on your risk tolerance:

* **High:** Even minor anomalies cause verification failure (recommended for production)
* **Medium:** Moderate anomalies are acceptable, major issues cause failure
* **Low:** Only severe anomalies cause verification failure

For canary deployments, **High** sensitivity is recommended to catch issues early.

**Duration**

Set the analysis duration (e.g., `5 min`). CV will:

* Collect metrics and logs for this duration
* Compare canary metrics against baseline
* Make a health decision based on the analysis

**Recommendation:** Use `5-10 minutes` for canary stages to get sufficient data while keeping deployment time reasonable.

**Monitored Service**

Select the Monitored Service that includes:

* Health sources connected to your monitoring tools
* Metrics and queries configured for your application
* Proper service and environment mapping

![CV Config](/files/1vTH6vrlH4L497SRujGp)

#### Step 7: Run the Pipeline <a href="#step-7-run-the-pipeline" id="step-7-run-the-pipeline"></a>

Now you're ready to run the pipeline and see the canary deployment with CV validation in action.

<details>

<summary>Pipeline YAML</summary>

```yaml
pipeline:
  projectIdentifier: akshitprojectqa
  orgIdentifier: default
  tags: {}
  stages:
    - stage:
        name: Dev Deploy
        identifier: Dev_Deploy
        description: ""
        type: Deployment
        spec:
          deploymentType: Kubernetes
          gitOpsEnabled: true
          service:
            serviceRef: loansapi
            serviceInputs:
              serviceDefinition:
                type: Kubernetes
                spec:
                  manifests:
                    - manifest:
                        identifier: manifests
                        type: ReleaseRepo
                        spec:
                          store:
                            type: Github
                            spec:
                              paths: <+input>
          execution:
            steps:
              - parallel:
                  - step:
                      type: GitOpsUpdateReleaseRepo
                      name: Modify Git
                      identifier: Modify_Git
                      timeout: 10m
                      spec:
                        variables:
                          - name: replicas[0].count
                            type: String
                            value: <+pipeline.variables.replica>
                        prTitle: Update Replica Count
                        allowEmptyCommit: true
                  - step:
                      type: JiraCreate
                      name: JiraCreate
                      identifier: JiraCreate
                      spec:
                        connectorRef: seenvjiratemp
                        projectKey: HD
                        issueType: Story
                        fields:
                          - name: Description
                            value: "Promote <+service.name> to production \\\\ Pipeline Name: <+pipeline.name> \\\\ Artifact: <+artifact.image> \\\\ Deployment URL: <+pipeline.executionUrl> \\\\ Requested by <+pipeline.triggeredBy.name>"
                          - name: Summary
                            value: Tracking GitOps Deployment
                      timeout: 10m
              - step:
                  type: MergePR
                  name: Approve Git Changes
                  identifier: Approve_Git_Changes
                  spec:
                    deleteSourceBranch: true
                    mergeStrategy: merge
                    variables: []
                  timeout: 10m
              - parallel:
                  - step:
                      type: GitOpsSync
                      name: ArgoCD Sync
                      identifier: GitOps_Sync
                      spec:
                        prune: false
                        dryRun: false
                        applyOnly: false
                        forceApply: false
                        applicationsList:
                          - applicationName: dev-loans-api
                            agentId: devgitopsdemo
                        retryStrategy: {}
                        retry: false
                        syncOptions:
                          skipSchemaValidation: false
                          autoCreateNamespace: false
                          pruneResourcesAtLast: false
                          applyOutOfSyncOnly: false
                          replaceResources: false
                          prunePropagationPolicy: foreground
                          respectIgnoreDifferences: false
                          serverSideApply: false
                        autoPromoteRolloutBehavior: promote-full
                      timeout: 10m
                  - step:
                      type: JiraUpdate
                      name: JiraUpdate - Dev
                      identifier: JiraUpdate_1
                      spec:
                        connectorRef: seenvjiratemp
                        issueKey: <+pipeline.stages.Dev_Deploy.spec.execution.steps.JiraCreate.issue.key>
                        fields:
                          - name: Comment
                            value: "Dev-Only: Updated GitRepo, Deployed via ArgoCD"
                        issueType: Story
                        projectKey: HD
                      timeout: 10m
            rollbackSteps:
              - step:
                  type: RevertPR
                  name: Revert PR
                  identifier: Revert_PR
                  spec:
                    commitId: <+pipeline.stages.Dev_Deploy.spec.execution.steps.updateReleaseRepo.updateReleaseRepoOutcome.commitId>
                  timeout: 10m
              - parallel:
                  - step:
                      type: GitOpsSync
                      name: Rollback - Sync
                      identifier: Rollback_Sync
                      spec:
                        prune: false
                        dryRun: false
                        applyOnly: false
                        forceApply: false
                        applicationsList:
                          - applicationName: dev-loans-api
                            agentId: devgitopsdemo
                        retryStrategy: {}
                        retry: false
                        syncOptions:
                          skipSchemaValidation: false
                          autoCreateNamespace: false
                          pruneResourcesAtLast: false
                          applyOutOfSyncOnly: false
                          replaceResources: false
                          prunePropagationPolicy: foreground
                          respectIgnoreDifferences: false
                          serverSideApply: false
                      timeout: 10m
                  - step:
                      type: JiraUpdate
                      name: JiraUpdate - Rollback
                      identifier: JiraUpdate_1
                      spec:
                        connectorRef: seenvjiratemp
                        issueKey: <+pipeline.stages.Dev_Deploy.spec.execution.steps.JiraCreate.issue.key>
                        fields:
                          - name: Comment
                            value: "Dev-Only: Rollback PR, Sync via ArgoCD"
                        issueType: Story
                        projectKey: HD
                      timeout: 10m
          environment:
            environmentRef: Dev_GitOps_Product_Demo
            deployToAll: false
            gitOpsClusters:
              - identifier: incluster
                agentIdentifier: devgitopsdemo
        tags: {}
        failureStrategies:
          - onFailure:
              errors:
                - AllErrors
              action:
                type: StageRollback
    - stage:
        name: QA Deploy
        identifier: QA_Deploy
        description: ""
        type: Deployment
        spec:
          deploymentType: Kubernetes
          gitOpsEnabled: true
          service:
            serviceRef: loansapi
            serviceInputs:
              serviceDefinition:
                type: Kubernetes
                spec:
                  manifests:
                    - manifest:
                        identifier: manifests
                        type: ReleaseRepo
                        spec:
                          store:
                            type: Github
                            spec:
                              paths: <+input>
          execution:
            steps:
              - step:
                  type: GitOpsUpdateReleaseRepo
                  name: Modify Git
                  identifier: Create_PR
                  spec:
                    variables:
                      - name: replicas[0].count
                        type: String
                        value: <+pipeline.variables.replica>
                    allowEmptyCommit: true
                  timeout: 10m
              - step:
                  type: MergePR
                  name: Approve Git Changes
                  identifier: Merge_PR
                  spec:
                    deleteSourceBranch: false
                    mergeStrategy: merge
                    variables: []
                  timeout: 10m
              - parallel:
                  - step:
                      type: GitOpsSync
                      name: ArgoCD Sync
                      identifier: GitOpsSync_1
                      spec:
                        prune: false
                        dryRun: false
                        applyOnly: false
                        forceApply: false
                        applicationsList:
                          - applicationName: qa-loans-api
                            agentId: qagitopsdemo
                        retryStrategy: {}
                        retry: false
                        syncOptions:
                          skipSchemaValidation: false
                          autoCreateNamespace: false
                          pruneResourcesAtLast: false
                          applyOutOfSyncOnly: false
                          replaceResources: false
                          prunePropagationPolicy: foreground
                          respectIgnoreDifferences: false
                          serverSideApply: false
                        autoPromoteRolloutBehavior: promote-full
                      timeout: 10m
                  - step:
                      type: JiraUpdate
                      name: JiraUpdate - QA
                      identifier: JiraUpdate_QA
                      spec:
                        connectorRef: seenvjiratemp
                        issueKey: <+pipeline.stages.Dev_Deploy.spec.execution.steps.JiraCreate.issue.key>
                        fields:
                          - name: Comment
                            value: "QA-Only: Updated GitRepo, Deployed via ArgoCD"
                        issueType: Story
                        projectKey: HD
                      timeout: 10m
            rollbackSteps: []
          environment:
            environmentRef: QA_GitOps_Product_Demo
            deployToAll: false
            gitOpsClusters:
              - identifier: incluster
                agentIdentifier: qagitopsdemo
        tags: {}
        failureStrategies:
          - onFailure:
              errors:
                - AllErrors
              action:
                type: StageRollback
    - stage:
        name: Prod Approval Gate
        identifier: Approve_Prod_NA_Deploy
        description: ""
        type: Approval
        spec:
          execution:
            steps:
              - step:
                  name: Approve Prod
                  identifier: Approve_Prod_NA
                  type: HarnessApproval
                  timeout: 1d
                  spec:
                    approvalMessage: Please Approve Prod NA Deploy
                    includePipelineExecutionHistory: true
                    approvers:
                      minimumCount: 1
                      disallowPipelineExecutor: false
                      userGroups:
                        - account._account_all_users
                    isAutoRejectEnabled: false
                    approverInputs: []
        tags: {}
    - stage:
        name: Prod-NA Deploy
        identifier: Prod_NA_Deploy
        description: ""
        type: Deployment
        spec:
          deploymentType: Kubernetes
          gitOpsEnabled: true
          service:
            serviceRef: loansapi
            serviceInputs:
              serviceDefinition:
                type: Kubernetes
                spec:
                  manifests:
                    - manifest:
                        identifier: manifests
                        type: ReleaseRepo
                        spec:
                          store:
                            type: Github
                            spec:
                              paths: <+input>
          execution:
            steps:
              - step:
                  type: GitOpsUpdateReleaseRepo
                  name: Modify Git
                  identifier: Create_PR
                  spec:
                    variables:
                      - name: spec.replicas
                        type: String
                        value: <+pipeline.variables.replica>
                      - name: spec.template.spec.containers[0].image
                        type: String
                        value: <+input>
                    allowEmptyCommit: true
                  timeout: 10m
              - step:
                  type: MergePR
                  name: Approve Git Changes
                  identifier: Merge_PR
                  spec:
                    deleteSourceBranch: false
                    mergeStrategy: merge
                    variables: []
                  timeout: 10m
              - parallel:
                  - step:
                      type: GitOpsSync
                      name: ArgoCD Sync
                      identifier: GitOps_Sync
                      spec:
                        prune: false
                        dryRun: false
                        applyOnly: false
                        forceApply: false
                        applicationsList:
                          - applicationName: prod-na-loans-api
                            agentId: prodnagitopsdemo
                        retryStrategy: {}
                        retry: false
                        syncOptions:
                          skipSchemaValidation: false
                          autoCreateNamespace: false
                          pruneResourcesAtLast: false
                          applyOutOfSyncOnly: false
                          replaceResources: false
                          prunePropagationPolicy: foreground
                          respectIgnoreDifferences: false
                          serverSideApply: false
                      timeout: 10m
                  - step:
                      type: JiraUpdate
                      name: JiraUpdate - ProdNA
                      identifier: JiraUpdate_ProdNA
                      spec:
                        connectorRef: seenvjiratemp
                        issueKey: <+pipeline.stages.Dev_Deploy.spec.execution.steps.JiraCreate.issue.key>
                        fields:
                          - name: Comment
                            value: "ProdNA-Only: Updated GitRepo, Deployed via ArgoCD"
                        issueType: Story
                        projectKey: HD
                      timeout: 10m
              - step:
                  type: GitOpsRollout
                  name: ArgoRollout  Canary 25
                  identifier: ArgoRollout_Canary_25
                  spec:
                    agentIdentifier: prodnagitopsdemo
                    namespace: loans
                    appName: prod-na-loans-api
                    rolloutName: loans-api
                    waitUntilHealthStatus:
                      healthStatus: Suspended
                  timeout: 10m
              - parallel:
                  - step:
                      type: Verify
                      name: Verify_1
                      identifier: Verify_1
                      spec:
                        isMultiServicesOrEnvs: false
                        type: Canary
                        monitoredService:
                          type: Default
                          spec: {}
                        spec:
                          sensitivity: HIGH
                          duration: 5m
                      timeout: 2h
                      failureStrategies:
                        - onFailure:
                            errors:
                              - Verification
                            action:
                              type: ManualIntervention
                              spec:
                                timeout: 2h
                                onTimeout:
                                  action:
                                    type: StageRollback
                        - onFailure:
                            errors:
                              - Unknown
                            action:
                              type: ManualIntervention
                              spec:
                                timeout: 2h
                                onTimeout:
                                  action:
                                    type: Ignore
                    contextType: Pipeline
                  - step:
                      type: GitOpsRollout
                      name: Wait
                      identifier: Wait_until_Suspended
                      spec:
                        appName: <+execution.steps.Parse_Rollout_Step.spec.appName>
                        agentIdentifier: <+execution.steps.Parse_Rollout_Step.spec.agentIdentifier>
                        namespace: <+execution.steps.Parse_Rollout_Step.spec.namespace>
                        rolloutName: <+execution.steps.Parse_Rollout_Step.spec.rolloutName>
                        waitUntilHealthStatus:
                          healthStatus: Suspended
                          healthMessage: CanaryPauseStep
                      timeout: 10m
                    contextType: Pipeline
              - step:
                  type: GitOpsRollout
                  name: ArgoRollout Canary 50
                  identifier: Resume_Rollout
                  spec:
                    appName: <+execution.steps.Wait_until_Suspended.spec.appName>
                    agentIdentifier: <+execution.steps.Wait_until_Suspended.spec.agentIdentifier>
                    namespace: <+execution.steps.Wait_until_Suspended.spec.namespace>
                    rolloutName: <+execution.steps.Wait_until_Suspended.spec.rolloutName>
                  timeout: 10m
              - parallel:
                  - step:
                      type: Verify
                      name: Verify_2
                      identifier: Verify_2
                      spec:
                        isMultiServicesOrEnvs: false
                        type: Canary
                        monitoredService:
                          type: Default
                          spec: {}
                        spec:
                          sensitivity: MEDIUM
                          duration: 5m
                      timeout: 2h
                      failureStrategies:
                        - onFailure:
                            errors:
                              - Verification
                            action:
                              type: ManualIntervention
                              spec:
                                timeout: 2h
                                onTimeout:
                                  action:
                                    type: StageRollback
                        - onFailure:
                            errors:
                              - Unknown
                            action:
                              type: ManualIntervention
                              spec:
                                timeout: 2h
                                onTimeout:
                                  action:
                                    type: Ignore
                  - step:
                      type: GitOpsRollout
                      name: Wait
                      identifier: Wait_until_Suspended_2
                      spec:
                        appName: <+execution.steps.Parse_Rollout_Step.spec.appName>
                        agentIdentifier: <+execution.steps.Parse_Rollout_Step.spec.agentIdentifier>
                        namespace: <+execution.steps.Parse_Rollout_Step.spec.namespace>
                        rolloutName: <+execution.steps.Parse_Rollout_Step.spec.rolloutName>
                        waitUntilHealthStatus:
                          healthStatus: Suspended
                          healthMessage: CanaryPauseStep
                      timeout: 10m
              - step:
                  type: GitOpsRollout
                  name: ArgoRollout Canary 75
                  identifier: Resume_Rollout_2
                  spec:
                    appName: <+execution.steps.Parse_Rollout_Step.spec.appName>
                    agentIdentifier: <+execution.steps.Parse_Rollout_Step.spec.agentIdentifier>
                    namespace: <+execution.steps.Parse_Rollout_Step.spec.namespace>
                    rolloutName: <+execution.steps.Parse_Rollout_Step.spec.rolloutName>
                  timeout: 10m
              - step:
                  type: Verify
                  name: Verify_3
                  identifier: Verify_3
                  spec:
                    isMultiServicesOrEnvs: false
                    type: Canary
                    monitoredService:
                      type: Default
                      spec: {}
                    spec:
                      sensitivity: HIGH
                      duration: 5m
                  timeout: 2h
                  failureStrategies:
                    - onFailure:
                        errors:
                          - Verification
                        action:
                          type: ManualIntervention
                          spec:
                            timeout: 2h
                            onTimeout:
                              action:
                                type: StageRollback
                    - onFailure:
                        errors:
                          - Unknown
                        action:
                          type: ManualIntervention
                          spec:
                            timeout: 2h
                            onTimeout:
                              action:
                                type: Ignore
              - step:
                  type: GitOpsRollout
                  name: ArgoRollout Canary 100
                  identifier: Resume_Rollout_3
                  spec:
                    appName: <+execution.steps.Parse_Rollout_Step.spec.appName>
                    agentIdentifier: <+execution.steps.Parse_Rollout_Step.spec.agentIdentifier>
                    namespace: <+execution.steps.Parse_Rollout_Step.spec.namespace>
                    rolloutName: <+execution.steps.Parse_Rollout_Step.spec.rolloutName>
                  timeout: 10m
            rollbackSteps:
              - step:
                  type: GitOpsRollout
                  name: ArgoRollout Abort
                  identifier: ArgoRollout_Abort
                  spec:
                    appName: <+execution.steps.Parse_Rollout_Step.spec.appName>
                    agentIdentifier: <+execution.steps.Wait_until_Suspended.spec.agentIdentifier>
                    namespace: <+execution.steps.Parse_Rollout_Step.spec.namespace>
                    rolloutName: <+execution.steps.Parse_Rollout_Step.spec.rolloutName>
                    autoRolloutAction: abort
                    waitUntilHealthStatus:
                      healthStatus: Unknown
                      healthMessage: Aborting
                  timeout: 10m
              - step:
                  type: RevertPR
                  name: Undo Git Changes
                  identifier: Undo_Git_Changes
                  spec:
                    commitId: <+revert>
                  timeout: 10m
              - step:
                  type: GitOpsSync
                  name: ArgoCD Sync
                  identifier: ArgoCD_Sync
                  spec:
                    prune: false
                    dryRun: false
                    applyOnly: false
                    forceApply: false
                    applicationsList: []
                    retryStrategy: {}
                    retry: false
                    syncOptions:
                      skipSchemaValidation: false
                      autoCreateNamespace: false
                      pruneResourcesAtLast: false
                      applyOutOfSyncOnly: false
                      replaceResources: false
                      prunePropagationPolicy: foreground
                      respectIgnoreDifferences: false
                      serverSideApply: false
                  timeout: 10m
          environment:
            environmentRef: Prod_NA_GitOps_Product_Demo
            deployToAll: false
            gitOpsClusters:
              - identifier: incluster
                agentIdentifier: prodnagitopsdemo
        tags: {}
        failureStrategies:
          - onFailure:
              errors:
                - AllErrors
              action:
                type: StageRollback
        gitOpsEnabled: true
    - stage:
        name: HighReg Approval Gate
        identifier: HighReg_Approval_Gate
        description: ""
        type: Approval
        spec:
          execution:
            steps:
              - step:
                  name: Approval Gate
                  identifier: Approval_Gate
                  type: HarnessApproval
                  timeout: 1d
                  spec:
                    approvalMessage: |-
                      Please review the following information
                      and approve the pipeline progression
                    includePipelineExecutionHistory: true
                    approvers:
                      minimumCount: 1
                      disallowPipelineExecutor: false
                      userGroups:
                        - account._account_all_users
                    isAutoRejectEnabled: false
                    approverInputs: []
        tags: {}
    - stage:
        name: Prod-HighReg Deploy
        identifier: Preprod_Deploy
        description: ""
        type: Deployment
        spec:
          deploymentType: Kubernetes
          gitOpsEnabled: true
          service:
            serviceRef: loansapi
            serviceInputs:
              serviceDefinition:
                type: Kubernetes
                spec:
                  manifests:
                    - manifest:
                        identifier: manifests
                        type: ReleaseRepo
                        spec:
                          store:
                            type: Github
                            spec:
                              paths: <+input>
          execution:
            steps:
              - parallel:
                  - step:
                      type: GitOpsSync
                      name: GitOps Sync
                      identifier: GitOps_Sync
                      spec:
                        prune: false
                        dryRun: false
                        applyOnly: false
                        forceApply: false
                        applicationsList:
                          - applicationName: preprod-loans-api
                            agentId: preprodgitopsdemo
                        retryStrategy: {}
                        retry: false
                        syncOptions:
                          skipSchemaValidation: false
                          autoCreateNamespace: false
                          pruneResourcesAtLast: false
                          applyOutOfSyncOnly: false
                          replaceResources: false
                          prunePropagationPolicy: foreground
                          respectIgnoreDifferences: false
                          serverSideApply: false
                        autoPromoteRolloutBehavior: promote-full
                      timeout: 10m
                  - step:
                      type: JiraUpdate
                      name: JiraUpdate - PreProd
                      identifier: JiraUpdate_PreProd
                      spec:
                        connectorRef: seenvjiratemp
                        issueKey: <+pipeline.stages.Dev_Deploy.spec.execution.steps.JiraCreate.issue.key>
                        fields:
                          - name: Comment
                            value: "PreProd-Only: Updated GitRepo, Deployed via ArgoCD"
                        issueType: Story
                        projectKey: HD
                      timeout: 10m
            rollbackSteps: []
          environment:
            environmentRef: Preprod_GitOps_Product_Demo
            deployToAll: false
            gitOpsClusters:
              - identifier: incluster
                agentIdentifier: preprodgitopsdemo
        tags: {}
        failureStrategies:
          - onFailure:
              errors:
                - AllErrors
              action:
                type: StageRollback
        gitOpsEnabled: true
  allowStageExecutions: true
  identifier: pipeloansapi_Clone
  name: pipe-loans-api - Clone
  variables:
    - name: replica
      type: Number
      description: ""
      required: false
      value: <+input>
```

</details>

**7.1 Save and Run**

1. Click **Save** to save your pipeline
2. Click **Run** to execute the pipeline
3. The pipeline will start executing

**7.2 Monitor Pipeline Execution**

Watch the pipeline execution:

1. **Service Step:** Should complete quickly (green checkmark)
2. **GitopsClusters Step:** Should complete quickly (green checkmark)
3. **GitOps Sync Step** (if added): Will sync the application if there are changes
4. **GitOps Rollout Step (Canary 10):**
   * Will wait until the rollout is paused at 10%
   * Will detect the `Suspended` status with `CanaryPauseStep` message
5. **Verify Step:**
   * Will analyze metrics and logs from the 10% canary
   * Will compare canary metrics against stable baseline
   * Will determine health status
6. **Repeat:** Process continues for 25% → 50% → 100%

**7.3 View Rollout Progression**

During execution, you can:

1. **View Step Logs:** Click on the GitOps Rollout step to see detailed logs
   * You'll see messages like: "Rollout 'loans-api' is SUSPENDED. Current weightage: 10 of 100"
   * The step will progress through stages: 10% → 25% → 50% → 100%
2. **View in GitOps UI:** Navigate to **Deployments > GitOps > Applications** to see the rollout progress in real-time
3. **View Rollout Status:** Check the rollout status in the GitOps Application Resources tab

![Rollout Status](/files/Zcukw6fSF3pXhNqDfh1C)

**7.4 Successful Completion**

When the pipeline completes successfully:

* All steps will show green checkmarks
* The GitOps Rollout steps will show progression through all canary stages
* The Verify steps will show successful validation at each stage
* The rollout will be at 100% weightage and **HEALTHY** status

**Congratulations! Your canary deployment with CV validation is working!** 🎉

#### Step 8: Understanding the Complete Workflow <a href="#step-8-understanding-the-complete-workflow" id="step-8-understanding-the-complete-workflow"></a>

Here's how the complete workflow operates:

1. **Pipeline Starts:** GitOps Sync step (if present) syncs the Rollout manifest
2. **Rollout Begins:** Argo Rollouts starts the canary deployment
3. **10% Traffic Shift:** Rollout shifts 10% of traffic to canary version (initial validation stage)
4. **Rollout Pauses:** Argo Rollouts pauses at the first canary step
5. **GitOps Rollout Step:** Detects the `Suspended` status with `CanaryPauseStep` message
6. **Verify Step Starts:** CV begins analyzing metrics and logs from the 10% canary
7. **CV Analysis:**
   * Collects data for the configured duration (e.g., 5 minutes)
   * Compares canary metrics against stable baseline
   * Applies ML algorithms to detect anomalies
   * Determines health status (Healthy, Medium Healthy, or Unhealthy)
8. **Health Decision:**
   * **If Healthy:** Verify step passes, pipeline continues
   * **If Unhealthy:** Verify step fails, pipeline can trigger rollback
   * **If Medium Healthy:** Depends on sensitivity setting
9. **Promotion:** If CV passes, GitOps Rollout step promotes to next stage (25%)
10. **Repeat:** Process repeats for 25% → 50% → 100%

#### Step 9: Configure Auto-Promotion (Optional) <a href="#step-9-configure-auto-promotion-optional" id="step-9-configure-auto-promotion-optional"></a>

To fully automate the canary progression, you can configure the GitOps Rollout step to automatically promote after CV validation:

1. In each GitOps Rollout step, set **Auto Action for Rollouts:** `Promote Full`
2. This will automatically promote to the next stage after the Verify step passes
3. The pipeline will progress through all stages without manual intervention

**Note:** Ensure your Verify steps are configured correctly, as auto-promotion will proceed even if CV detects issues (depending on sensitivity and fail settings).

#### Step 10: Configure Rollback on CV Failure <a href="#step-10-configure-rollback-on-cv-failure" id="step-10-configure-rollback-on-cv-failure"></a>

To automatically rollback when CV detects issues:

1. In your pipeline, add a **Rollback** step after each Verify step
2. Configure conditional execution:
   * **Conditional Execution:** Enable
   * **Execute on:** Select `On Failure of Previous Step`
3. Configure rollback action:
   * Use GitOps Rollout step with **Auto Action:** `Abort`
   * Or use GitOps Sync step to sync previous version from Git

Alternatively, configure the Verify step to fail the pipeline, which can trigger automatic rollback if configured in your failure strategy.

### How CV Validates Canary Deployments <a href="#how-cv-validates-canary-deployments" id="how-cv-validates-canary-deployments"></a>

#### Metrics Comparison <a href="#metrics-comparison" id="metrics-comparison"></a>

CV compares metrics from canary pods against stable pods:

* **Response Time:** Canary response times vs. stable baseline
* **Error Rate:** Error rates in canary vs. stable
* **Throughput:** Request rates and patterns
* **Resource Usage:** CPU, memory, and other resource metrics
* **Custom Metrics:** Any custom metrics configured in your health sources

#### Anomaly Detection <a href="#anomaly-detection" id="anomaly-detection"></a>

Harness uses machine learning to:

1. **Establish Baseline:** Learn normal behavior from stable pods
2. **Monitor Canary:** Collect real-time metrics from canary pods
3. **Detect Deviations:** Identify anomalies that deviate from baseline
4. **Classify Severity:** Determine if anomalies are critical, moderate, or minor
5. **Make Decision:** Based on sensitivity, decide if canary is healthy

#### Health Status Determination <a href="#health-status-determination" id="health-status-determination"></a>

CV determines health status based on:

* **Sensitivity Setting:** High, Medium, or Low
* **Anomaly Severity:** Critical, moderate, or minor deviations
* **Metric Trends:** Whether metrics are improving or degrading
* **Duration:** Analysis over the configured time window

**Health Status Values:**

* **Healthy:** No significant anomalies detected
* **Medium Healthy:** Minor anomalies detected (may pass with Medium/Low sensitivity)
* **Unhealthy:** Critical anomalies detected (always fails)

### Next Steps <a href="#next-steps" id="next-steps"></a>

You've learned how to use Continuous Verification with Argo Rollouts for canary deployments. You can now:

* [Managing Rollouts in Harness Pipeline](/continuous-delivery/use-gitops/argo-rollouts/managing-rollouts-in-harness-pipelines.md) - Learn more about GitOps Rollout steps
* [Verify Overview](/continuous-delivery/use-continuous-delivery/verify-deployments/verify-deployments-with-the-verify-step.md) - Understand Continuous Verification concepts
* [Create a Monitored Service](/service-reliability-management/use-srm/monitored-services/create-monitored-service.md) - Set up health sources for CV
* [Argo Rollouts Overview](/continuous-delivery/use-gitops/argo-rollouts/argo-rollouts-overview.md) - Learn more about Argo Rollouts
