> ## Documentation Index
> Fetch the complete documentation index at: https://docs.envzero.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Autoscaling Self-Hosted Agents on Azure Container Apps

> Run env zero self-hosted agents as ephemeral Azure Container Apps Jobs that scale to zero when idle and spin up on demand, using KEDA autoscaling.

Run env zero self-hosted agents as ephemeral Azure Container Apps (ACA) Jobs that scale to zero when idle and spin up automatically when deployments are queued. Scaling is driven by KEDA, which is built into the Azure Container Apps managed environment, so no separate KEDA installation is required.

<Note>
  Self-hosted agents are available to Enterprise customers only. See [pricing](https://www.env0.com/pricing) for details.
</Note>

## How It Works

KEDA polls the env zero agent queue state endpoint on a fixed interval and creates ACA job executions when deployment tasks are queued. Each container picks up one task, runs it to completion, and exits. When the queue is empty, no containers run.

## Prerequisites

* Azure CLI installed and authenticated (`az login`)
* Azure subscription with Contributor access
* An env zero agent pool with a valid agent access token. See [Self-Hosted Agents Overview](/guides/admin-guide/self-hosted-kubernetes-agent/overview) for how to create an agent pool and generate a secret.

## Setup

<Steps>
  <Step title="Create a resource group">
    ```bash theme={null}
    az group create -n env0-keda -l <YOUR_REGION>
    ```
  </Step>

  <Step title="Create a Container Apps environment">
    ```bash theme={null}
    az containerapp env create \
      -n env0-keda-env \
      -g env0-keda \
      -l <YOUR_REGION>
    ```

    This creates a managed environment with KEDA built in. No KEDA installation is needed.
  </Step>

  <Step title="Create the job configuration file">
    Save the following as `env0-aca-job.yaml`. Replace `<YOUR_AGENT_ACCESS_TOKEN>` with the agent access token generated for your agent pool, `<YOUR_STATE_ENCRYPTION_KEY_BASE64>` with a base64-encoded encryption key, and `<X.Y.Z>` with the agent version you want to pin to.

    ```yaml env0-aca-job.yaml theme={null}
    properties:
      configuration:
        triggerType: Event
        replicaTimeout: 3600
        replicaRetryLimit: 0
        secrets:
        - name: agent-token
          value: "<YOUR_AGENT_ACCESS_TOKEN>"
        eventTriggerConfig:
          parallelism: 1
          replicaCompletionCount: 1
          scale:
            minExecutions: 0
            maxExecutions: 10
            pollingInterval: 30
            rules:
            - name: env0-pending-tasks
              type: metrics-api
              metadata:
                url: "https://agent.api.env0.com/deployment-tasks/queue-state"
                valueLocation: "pendingCount"
                targetValue: "1"
                activationTargetValue: "0"
                authMode: "apiKey"
                method: "header"
                keyParamName: "Authorization"
              auth:
              - secretRef: agent-token
                triggerParameter: apiKey
      template:
        containers:
        - name: env0-agent
          image: ghcr.io/env0/deployment-agent:<X.Y.Z>
          command: ["/bin/sh", "-c"]
          args: ["update-ca-certificates; node --enable-source-maps start-agent.js;"]
          resources:
            cpu: 2
            memory: 4Gi
          env:
          - name: AGENT_ACCESS_TOKEN
            secretRef: agent-token
          - name: ENV0_STATE_ENCRYPTION_KEY
            value: "<YOUR_STATE_ENCRYPTION_KEY_BASE64>"
          - name: ENV0_STAGE
            value: "prod"
    ```
  </Step>

  <Step title="Create the job">
    ```bash theme={null}
    az containerapp job create \
      -n env0-agent-job \
      -g env0-keda \
      --environment env0-keda-env \
      --yaml env0-aca-job.yaml
    ```
  </Step>
</Steps>

<Warning>
  `ENV0_STATE_ENCRYPTION_KEY` must be a base64-encoded value and identical across all agent replicas. Mismatched keys make encrypted deployment state unreadable, which results in data loss.
</Warning>

<Info>
  Pin `image` to a specific agent version rather than `:latest` to avoid silent upgrades during a running deployment. See the [env0 deployment agent releases](https://github.com/env0/agent/releases) for current tags.
</Info>

## Configuration Reference

### KEDA Scaling Parameters

| Parameter               | Default | Description                                                    |
| ----------------------- | ------- | -------------------------------------------------------------- |
| `pollingInterval`       | `30`    | Seconds between KEDA polls of the queue state endpoint.        |
| `maxExecutions`         | `10`    | Maximum concurrent agent containers.                           |
| `minExecutions`         | `0`     | Set to 1 or higher to keep warm containers running.            |
| `replicaTimeout`        | `3600`  | Maximum seconds a container can run before forced termination. |
| `targetValue`           | `1`     | Tasks per container. `1` means one container per pending task. |
| `activationTargetValue` | `0`     | Metric threshold that activates scaling from zero.             |

### Container Resources

| Parameter | Default | Description              |
| --------- | ------- | ------------------------ |
| `cpu`     | `2`     | CPU cores per container. |
| `memory`  | `4Gi`   | Memory per container.    |

### Environment Variables

| Variable                    | Required | Description                                                                                      |
| --------------------------- | -------- | ------------------------------------------------------------------------------------------------ |
| `AGENT_ACCESS_TOKEN`        | Yes      | Agent authentication token. Stored as an ACA secret and referenced by `secretRef`.               |
| `ENV0_STAGE`                | Yes      | Determines which env zero API endpoint the agent connects to. Use `prod` for production.         |
| `ENV0_STATE_ENCRYPTION_KEY` | Yes      | Base64-encoded encryption key for deployment state. Must be identical across all agent replicas. |
| `DEPLOYMENT_LOGS_LOG_LEVEL` | No       | Set to `debug` for verbose agent logging.                                                        |

## Monitoring

List running and completed executions:

```bash theme={null}
az containerapp job execution list -n env0-agent-job -g env0-keda -o table
```

View logs for a specific execution:

```bash theme={null}
az containerapp job logs show \
  -n env0-agent-job -g env0-keda \
  --container env0-agent \
  --execution <EXECUTION_NAME> \
  --follow false
```

Stop a running execution:

```bash theme={null}
az containerapp job stop \
  -n env0-agent-job -g env0-keda \
  --job-execution-name <EXECUTION_NAME>
```

## Troubleshooting

### No containers start when deployments are queued

Check the KEDA system logs for the Container Apps environment:

```bash theme={null}
az containerapp env show -n env0-keda-env -g env0-keda \
  --query 'properties.appLogsConfiguration.logAnalyticsConfiguration.customerId' -o tsv

az monitor log-analytics query -w <WORKSPACE_ID> \
  --analytics-query "ContainerAppSystemLogs_CL | order by TimeGenerated desc | take 20" \
  -o table
```

Common causes:

* `api returned 401`: the agent access token is incorrect or has been revoked. Generate a new secret and update the job configuration.
* No KEDA activity logged: verify the job was created with `triggerType: Event`.

### A container starts but fails immediately

Check the container logs for the specific error. Common causes:

* Missing `ENV0_STAGE`: deployment commands build URLs from this variable and produce broken hosts when it is unset. Set it explicitly to `prod` for production.
* Missing `ENV0_STATE_ENCRYPTION_KEY`: the agent exits immediately with an error.
* Wrong `AGENT_ACCESS_TOKEN`: the agent starts but receives 401 on API calls.

## Cleanup

To remove all resources created for this setup:

```bash theme={null}
az group delete -n env0-keda -y
```

## Next Steps

* [Self-Hosted Agents Overview](/guides/admin-guide/self-hosted-kubernetes-agent/overview) - Create agent pools and manage authentication secrets.
* [Custom/Optional Configuration](/guides/admin-guide/self-hosted-kubernetes-agent/custom-optional-configuration) - Additional agent configuration options.
* [Self-Hosted Agents Monitoring](/guides/admin-guide/self-hosted-kubernetes-agent/self-hosted-agents-monitoring) - Monitor agent health and deployments.
