> 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/3.0/use-deployments/overview-3/basic/canary.md).

# Canary deployment

Deploy a new Cloud Run revision, shift traffic gradually, then promote using the Canary deployment strategy.

The Canary deployment strategy deploys a new Cloud Run revision and lets you control how traffic shifts to it. By default, the Deploy step routes 100% of traffic to the new revision immediately; enable **Skip Traffic Update** on the Deploy step to hold traffic on the stable revision and use the Traffic Shift step to move traffic gradually. If the stage fails at any point, the Rollback step restores traffic to the distribution from the last successful deployment.

***

### What you will learn <a href="#what-you-will-learn" id="what-you-will-learn"></a>

* How the Canary strategy step sequence works, including the Deploy, Traffic Shift, and Rollback steps.
* How to configure the Traffic Shift step to split traffic between the stable and canary revisions.
* How rollback uses the last successful deployment state to restore traffic to the stable revision.
* The exact `gcloud` commands Harness runs at each stage of a canary deployment and rollback.

***

### Before you begin <a href="#before-you-begin" id="before-you-begin"></a>

* **A Google Cloud Run service:** Go to [Google Cloud Run services](/continuous-delivery/3.0/use-deployments/overview-3/google-cloud-run-services.md) to set up a service with a manifest and artifact source.
* **A Google Cloud Run infrastructure:** Go to [Google Cloud Run infrastructure](/continuous-delivery/3.0/use-deployments/overview-3/google-cloud-run-infrastructure.md) to connect a GCP project and region.

***

### Canary strategy step sequence <a href="#canary-strategy-step-sequence" id="canary-strategy-step-sequence"></a>

When you select **Google Cloud Run Canary Deploy Strategy**, Harness adds the following steps to your stage execution:

1. **Google Cloud Run Deploy**: applies the manifest via `gcloud run services replace`, then fetches the resulting revision metadata and saves it to rollback data. By default, traffic shifts to the new revision unless you enable **Skip Traffic Update**.
2. **Google Cloud Run Traffic Shift**: routes a specified percentage of traffic to the new revision using `gcloud run services update-traffic`.

A **Google Cloud Run Rollback** step is automatically added to the stage's rollback phase. Harness triggers it when the failure strategy calls for stage rollback.

Add approval steps, tests, or additional Traffic Shift steps between the Deploy step and the final full-traffic promotion as needed.

***

### Configure the Deploy step <a href="#configure-the-deploy-step" id="configure-the-deploy-step"></a>

The Google Cloud Run Deploy step applies your service manifest and updates the container image. Configure the following fields:

| Field                       | Default                     | Description                                                                                                                                                       |
| --------------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name**                    | Google Cloud Run Deploy     | The step name.                                                                                                                                                    |
| **GCP Connector**           | —                           | The GCP connector used to authenticate with Cloud Run. Defaults to the connector configured in the infrastructure definition.                                     |
| **GCP Region**              | `${{infra.region}}`         | The region of the Cloud Run service. Automatically resolved from the infrastructure definition.                                                                   |
| **GCP Project**             | `${{infra.project}}`        | The GCP project of the Cloud Run service. Automatically resolved from the infrastructure definition.                                                              |
| **Service Manifest Path**   | `${{runtime.manifestPath}}` | The path to the downloaded service manifest. Automatically resolved at runtime.                                                                                   |
| **Service Container Image** | `${{artifact.image}}`       | The container image to deploy. Automatically resolved from the artifact source.                                                                                   |
| **Command Options**         | —                           | Additional flags passed to `gcloud run services replace` (for example, `--port=8080`).                                                                            |
| **Skip Traffic Update**     | `false`                     | When `true`, the Deploy step creates a new revision without shifting any traffic. Use this in Canary stages where a separate Traffic Shift step controls traffic. |
| **Command Timeout**         | `10m`                       | Maximum time for the step to complete.                                                                                                                            |
| **Log Level**               | `info`                      | Log verbosity for the step execution.                                                                                                                             |

{% hint style="info" %}
**Post-deploy rollback data**

After deploying, the Deploy step runs `gcloud run services describe` to capture the resulting revision and traffic state, then saves it to rollback data. The step also performs a Google Cloud Monitoring instance sync. If no data is available yet it retries every 60 seconds, up to 10 times; factor up to 10 minutes of instance sync into your expected step duration. There is no separate Prepare Rollback step.
{% endhint %}

***

### Configure the Traffic Shift step <a href="#configure-the-traffic-shift-step" id="configure-the-traffic-shift-step"></a>

The Traffic Shift step routes traffic to specific revisions using `gcloud run services update-traffic`. Add it once to send a percentage of traffic to the canary revision, then again at the end of the stage to promote the canary to 100%.

The primary field you configure is **Revision Metadata**.

#### Metadata <a href="#metadata" id="metadata"></a>

The **Metadata** field takes a JSON object that describes the target traffic distribution. The format mirrors the Cloud Run service status traffic structure:

```json
{"status":{"traffic":[{"revisionName":"LATEST","percent":100}]}}
```

To send 20% of traffic to the latest revision and keep 80% on the previous revision, use:

```json
{"status":{"traffic":[{"revisionName":"LATEST","percent":20},{"revisionName":"<previous-revision>","percent":80}]}}
```

Use `LATEST` to refer to the most recently deployed revision. Use a specific revision name (for example, `gcrrkh-00003-w4t`) to pin traffic to a named revision.

The other Traffic Shift fields are auto-populated from the service and infrastructure configuration:

| Field                     | Default                                                            | Description                                                            |
| ------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------- |
| **Metadata**              | `{"status":{"traffic":[{"revisionName":"LATEST","percent":100}]}}` | JSON object defining the target traffic distribution across revisions. |
| **Service Manifest Path** | `${{runtime.manifestPath}}`                                        | Derived from service configuration. Resolved at runtime.               |
| **GCP Connector**         | —                                                                  | Derived from infrastructure configuration.                             |
| **GCP Region**            | `${{infra.region}}`                                                | Derived from infrastructure configuration.                             |
| **GCP Project**           | `${{infra.project}}`                                               | Derived from infrastructure configuration.                             |
| **Command Timeout**       | `10m`                                                              | Maximum time for the step to complete.                                 |
| **Log Level**             | `info`                                                             | Log verbosity.                                                         |

***

### Stage YAML <a href="#stage-yaml" id="stage-yaml"></a>

A minimal canary deployment stage looks like this. The Deploy and Traffic Shift steps use defaults from the service and infrastructure definition. Override fields in a `with:` block only when you need non-default values.

```yaml
- name: google-cloud-run
  id: googleCloudRun
  service:
    type: google-cloud-run
    items:
    - <service-id>
  environment:
    items:
    - id: <environment-id>
      deploy-to: all
  steps:
  - name: Google Cloud Run Deploy
    id: googleCloudRunDeployStep
    template:
      uses: googleCloudRunDeployStep
      with:
        skip_traffic_update: true
  - name: Google Cloud Run Traffic Shift 20
    id: googleCloudRunTrafficShift20
    template:
      uses: googleCloudRunTrafficShiftStep
      with:
        metadata: <provide the traffic details>
  - name: Google Cloud Run Traffic Shift 100
    id: googleCloudRunTrafficShift100
    template:
      uses: googleCloudRunTrafficShiftStep
      with:
        metadata: <provide the traffic details>
  rollback:
  - group:
      steps:
      - name: Google Cloud Run Rollback
        id: googleCloudRunRollbackStep
        template:
          uses: googleCloudRunRollbackStep
    id: googleCloudRunCanaryRollback
    name: Google Cloud Run Canary Rollback
  on-failure:
    errors: all
    action: stage-rollback
```

***

### Rollback behavior <a href="#rollback-behavior" id="rollback-behavior"></a>

When the stage failure strategy triggers rollback, the **Google Cloud Run Rollback** step inside the **Google Cloud Run Canary Rollback** step group runs.

#### How canary rollback works <a href="#how-canary-rollback-works" id="how-canary-rollback-works"></a>

Rollback uses the revision state saved by the last successful deployment of this stage. If the current execution fails at any point (during Deploy, Traffic Shift, or a later step), Harness restores traffic to the distribution that was live at the end of the last successful stage execution. If this is the first deployment of the service, there is no prior successful state, so Harness deletes the newly created service.

The Rollback step requires no configuration inputs. Harness reads rollback state from the last successful deployment automatically. The Rollback step:

1. Runs `gcloud run revisions list` to inspect all revisions.
2. Reads `rollback.data.REVISION_METADATA` to identify the target stable revision (for example, `gcrrkh-00003-w4t` at 100%).
3. Describes the current service to inspect live traffic state.
4. Runs `gcloud run services update-traffic <service> --to-revisions=<stable-revision>=100` to restore full traffic to the stable revision.
5. Runs instance sync via the Google Cloud Monitoring SDK with a 60-second stabilization wait.

Rollback behavior differs by deployment history:

* **First deployment:** no prior successful state exists. Harness deletes the newly created service using `gcloud run services delete`.
* **Subsequent deployments:** Harness runs `gcloud run services update-traffic` to route 100% of traffic back to the stable revision from the last successful execution.

{% hint style="info" %}
**Rollback does not delete revisions**

Google Cloud Run does not support deleting a specific revision. Rollback on subsequent deployments diverts traffic to a previous revision rather than deleting the canary revision.
{% endhint %}

***

### Deployment execution <a href="#deployment-execution" id="deployment-execution"></a>

The following sequence shows what happens when a canary deployment stage runs.

**Successful deployment:**

1. Harness fetches the service manifest from the configured manifest store and writes it to `/harness/manifest/GoogleCloudRun/ServiceManifest.yaml`.
2. The Deploy step authenticates to GCP (`gcloud auth activate-service-account --key-file sa_key.json`), sets the project (`gcloud config set project <project>`), and sets the region (`gcloud config set run/region <region>`).
3. The Deploy step injects the container image URL into the manifest and runs `gcloud run services replace /harness/manifest/GoogleCloudRun/ServiceManifest.yaml`. Cloud Run creates the new revision (for example, `my-svc-00004-xyz`).
4. If **Skip Traffic Update** is disabled (the default), Cloud Run routes 100% of traffic to the new revision immediately after creation. If **Skip Traffic Update** is enabled, traffic stays on the stable revision and the Traffic Shift step controls the initial shift.
5. The Deploy step runs `gcloud run services describe <service> --format json` to capture the post-deploy state. It saves the resulting revision name and traffic distribution as `SERVICE` and `REVISION_METADATA` in rollback data. For example:

   ```json
   {"status":{"traffic":[{"percent":100,"revisionName":"my-svc-00004-xyz"}],"latestCreatedRevisionName":"my-svc-00004-xyz"}}
   ```
6. The Deploy step performs instance sync using the Google Cloud Monitoring SDK with filter `metric.type="run.googleapis.com/container/instance_count"`. If data is available, it waits an additional 60 seconds for a stable read.
7. The Traffic Shift step authenticates to GCP, then runs `gcloud run services update-traffic <service> --to-revisions=LATEST=<percent>,<stable-revision>=<remaining-percent>`. For a 50% canary shift the command is:

   ```
   gcloud run services update-traffic my-svc --to-revisions=LATEST=50,my-svc-00003-abc=50
   ```

   Cloud Run confirms the split: `50% my-svc-00003-abc / 50% LATEST (currently my-svc-00004-xyz)`.
8. The Traffic Shift step runs `gcloud run services describe` to capture the post-shift traffic state and saves it as `REVISION_METADATA` in its output. It then performs instance sync with a 60-second stabilization wait.
9. Any approval or test steps run. If they pass, a second Traffic Shift step promotes the canary to 100% using `--to-revisions=LATEST=100`.
10. The stage completes successfully.

**Failed deployment:**

1. If any step fails, the `on-failure: action: stage-rollback` failure strategy triggers the rollback phase.
2. The **Google Cloud Run Rollback** step runs inside the **Google Cloud Run Canary Rollback** group.
3. The Rollback step authenticates to GCP, then runs `gcloud run revisions list --service <service> --format json` to enumerate all revisions, including retired ones.
4. The Rollback step reads `rollback.data.REVISION_METADATA`, which contains the revision state from the last successful deployment of this stage. This is the stable revision at 100%. For example:

   ```json
   {"status":{"latestCreatedRevisionName":"my-svc-00003-abc","traffic":[{"percent":100,"revisionName":"my-svc-00003-abc"}]}}
   ```
5. The Rollback step runs `gcloud run services describe <service> --format json` to inspect the live traffic distribution (for example, 50% stable / 50% canary at the point of failure).
6. The Rollback step checks for any Cloud Run URL tags on the service that need to be removed. If none exist, it logs "No tags to remove" and proceeds.
7. The Rollback step runs `gcloud run services update-traffic <service> --to-revisions=<stable-revision>=100`. For example:

   ```
   gcloud run services update-traffic my-svc --to-revisions=my-svc-00003-abc=100
   ```

   Cloud Run confirms: `100% my-svc-00003-abc`.
8. The Rollback step runs `gcloud run services describe` to confirm the restored traffic state, then saves the result to its output.
9. The canary revision (`my-svc-00004-xyz`) remains in Cloud Run but receives no traffic. Cloud Run does not support deleting individual revisions.
10. The Rollback step performs instance sync with a 60-second stabilization wait. The stage ends in a failed state.

***

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

* Go to [Google Cloud Run basic deployment](/continuous-delivery/3.0/use-deployments/overview-3/basic.md) for immediate full-traffic deployment.
* Go to [Blank canvas](/continuous-delivery/3.0/use-deployments/overview-3/basic/blank-canvas.md) to compose steps manually without a managed strategy.

{% @harness-feedback/feedback %}
