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

# Azure Container Instances Worker Guide

> Run Prefect flows on Azure Container Instances with a hybrid work pool, from Azure setup through deployment and execution.

## Why use ACI for flow run execution?

ACI (Azure Container Instances) is a fully managed compute platform that streamlines running your Prefect flows on scalable, on-demand infrastructure on Azure.

In this guide, you will:

* Create the Azure resources needed to run an ACI worker
* Start a Prefect worker in Azure Container Instances
* Configure an Azure Container Registry (ACR) for your flow images
* Deploy a sample flow with either Python or `prefect.yaml`
* Run the deployment from the Prefect UI or CLI

## Prerequisites

Before starting this guide, make sure you have:

* Prefect connected to either Prefect Cloud or a Prefect server that is reachable from Azure Container Instances.
* `prefect` and `prefect-azure` installed in your local Python environment.
* An Azure account and user permissions for provisioning resource groups and container instances.
* The Azure CLI installed on your local machine. You can follow Microsoft's [installation guide](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli).
* Docker installed on your local machine.

Install the required Python packages:

```bash theme={null}
pip install -U "prefect[azure]"
```

Authenticate with Azure:

```bash theme={null}
az login
```

If you're using a self-hosted Prefect server, make sure it is reachable from the Azure container instance that will run your worker. Starting `prefect server start` on your local machine is not sufficient unless that server is exposed to Azure.

For example, if you're running a local server for development, you can start it with:

```bash theme={null}
prefect server start
```

Before continuing, confirm which Prefect profile is active:

```bash theme={null}
prefect config view
```

If you're using Prefect Cloud, make sure your `PREFECT_API_URL` and `PREFECT_API_KEY` point at your workspace.

## Step 1. Create a resource group

Azure resource groups serve as containers for managing groupings of Azure resources.

Replace `<resource-group-name>` with the name of your choosing, and `<location>` with a valid Azure location name, such as `eastus`.

```bash theme={null}
export RG_NAME=<resource-group-name> && \
az group create --name $RG_NAME --location <location>
```

Throughout the rest of the guide, we'll need to refer to the **scope** of the created resource group, which is a string describing where the resource group lives in the hierarchy of your Azure account. To save the scope of your resource group as an environment variable, run the following command:

```bash theme={null}
RG_SCOPE=$(az group show --name $RG_NAME --query id --output tsv)
```

You can check that the scope is correct before moving on by running `echo $RG_SCOPE` in your terminal. It should be formatted as follows:

```
/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>
```

## Step 2. Prepare ACI permissions

In order for the worker to create, monitor, and delete the other container instances in which flows will run, we'll need to create a **custom role** and an **identity**, and then affiliate that role to the identity with a **role assignment**. When we start our worker, we'll assign that identity to the container instance it's running in.

### 1. Create a role

The custom `Container Instances Contributor` role has all the permissions your worker will need to run flows in other container instances. Create it by running the following command:

```bash theme={null}
az role definition create --role-definition '{
  "Name": "Container Instances Contributor",
  "IsCustom": true,
  "Description": "Can create, delete, and monitor container instances.",
  "Actions": [
    "Microsoft.ManagedIdentity/userAssignedIdentities/assign/action",
    "Microsoft.Resources/deployments/*",
    "Microsoft.ContainerInstance/containerGroups/*"
  ],
  "NotActions": [
  ],
  "AssignableScopes": [
    '"\"$RG_SCOPE\""'
  ]
}'
```

### 2. Create an identity

Create a user-managed identity with the following command, replacing `<identity-name>` with the name you'd like to use for the identity:

```bash theme={null}
export IDENTITY_NAME=<identity_name> && \
az identity create -g $RG_NAME -n $IDENTITY_NAME
```

We'll also need to save the principal ID and full object ID of the identity for the role assignment and container creation steps, respectively:

```bash theme={null}
IDENTITY_PRINCIPAL_ID=$(az identity list --query "[?name=='$IDENTITY_NAME'].principalId" --output tsv) && \
IDENTITY_ID=$(az identity list --query "[?name=='$IDENTITY_NAME'].id" --output tsv)
```

### 3. Assign roles to the identity

Now let's assign the `Container Instances Contributor` role we created earlier to the new identity:

```bash theme={null}
az role assignment create \
    --assignee $IDENTITY_PRINCIPAL_ID \
    --role "Container Instances Contributor" \
    --scope $RG_SCOPE
```

Since we'll be using ACR to host a custom Docker image containing a Prefect flow later in the guide, let's also assign the built in `AcrPull` role to the identity:

```bash theme={null}
az role assignment create \
    --assignee $IDENTITY_PRINCIPAL_ID \
    --role "AcrPull" \
    --scope $RG_SCOPE
```

## Step 3. Create the worker container instance

Before running this command, set your `PREFECT_API_URL` and `PREFECT_API_KEY` as environment variables.

Use a `PREFECT_API_URL` that the ACI worker container can actually reach:

* For Prefect Cloud, use your workspace API URL.
* For Prefect server, use a publicly reachable or privately networked hostname/IP for your server's `/api` endpoint.

Do not use `http://127.0.0.1:4200/api` or another localhost address here. Inside ACI, `127.0.0.1` resolves to the worker container itself, not to a Prefect server running on your local machine.

```bash theme={null}
export PREFECT_API_URL=<PREFECT_API_URL_HERE> PREFECT_API_KEY=<PREFECT_API_KEY_HERE>
```

Running the following command will create a container instance in your Azure resource group that will start a Prefect ACI worker. If there is not already a work pool in Prefect with the name you chose, a work pool will also be created.

Replace `<work-pool-name>` with the name of the ACI work pool you want to create in Prefect. Here we're using the work pool name as the name of the container instance in Azure as well, but you may name it something else if you prefer.

```bash theme={null}
az container create \
    --name <work-pool-name> \
    --resource-group $RG_NAME \
    --assign-identity $IDENTITY_ID \
    --image "prefecthq/prefect-azure:latest" \
    --secure-environment-variables PREFECT_API_URL=$PREFECT_API_URL PREFECT_API_KEY=$PREFECT_API_KEY \
    --command-line "/bin/bash -c 'prefect worker start --pool <work-pool-name> --type azure-container-instance'"
```

<Tip>
  This example uses `prefecthq/prefect-azure:latest` which includes both `prefect` and `prefect-azure` pre-installed. For production deployments,
  consider pinning to a specific version tag (e.g., `prefecthq/prefect-azure:0.4.9-python3.12-prefect3.6.19`).
</Tip>

This container instance uses default networking and security settings. For advanced configuration, refer to the `az container create` [CLI reference](https://learn.microsoft.com/en-us/cli/azure/container?view=azure-cli-latest#az-container-create).

## Step 4. Create an ACR registry

In order to build and push images containing flow code to Azure, we'll need a container registry. Create one with the following command, replacing `<registry-name>` with the registry name of your choosing:

```bash theme={null}
export REGISTRY_NAME=<registry-name> && \
az acr create --resource-group $RG_NAME \
  --name <registry-name> --sku Basic
```

## Step 5. Update your ACI work pool configuration

Once your work pool is created, navigate to the Edit page of your ACI work pool. You will need to update the following fields:

### Identities

This will be your `IDENTITY_ID`. You can get it from your terminal by running `echo $IDENTITY_ID`. When adding it to your work pool, it should be formatted as a JSON array:

```
["/subscriptions/<subscription-id>/resourcegroups/<resource-group-name>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<identity-name>"]
```

<img src="https://mintcdn.com/prefect-bd373955/61rCXJ5a7pFAZAcb/images/integrations/aci-worker-identities.png?fit=max&auto=format&n=61rCXJ5a7pFAZAcb&q=85&s=5b6a19d6b2a5a742fb8587da6941d606" alt="Configuring an ACI work pool's identities." width="2860" height="426" data-path="images/integrations/aci-worker-identities.png" />

### ACRManagedIdentity

ACRManagedIdentity is required for your flow code containers to be pulled from ACR. It consists of the following:

* Identity: the same `IDENTITY_ID` as above, as a string

```
/subscriptions/<subscription-id>/resourcegroups/<resource-group-name>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<identity-name>
```

* Registry URL: your `<registry-name>`, followed by `.azurecr.io`

```
<registry-name>.azurecr.io
```

<img src="https://mintcdn.com/prefect-bd373955/61rCXJ5a7pFAZAcb/images/integrations/aci-worker-acridentity.png?fit=max&auto=format&n=61rCXJ5a7pFAZAcb&q=85&s=c5d86b7c9e8dc2dce48c264f9a1f9bda" alt="Configuring an ACI work pool's ACR Managed Identity." width="2824" height="552" data-path="images/integrations/aci-worker-acridentity.png" />

### Subscription ID and resource group name

Both the subscription ID and resource group name can be found in the `RG_SCOPE` environment variable created earlier in the guide. View their values by running `echo $RG_SCOPE`:

```
/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>
```

<img src="https://mintcdn.com/prefect-bd373955/61rCXJ5a7pFAZAcb/images/integrations/aci-worker-subscription.png?fit=max&auto=format&n=61rCXJ5a7pFAZAcb&q=85&s=9f9351730b058bea5fd23ee474630bf8" alt="Configuring an ACI work pool." width="1256" height="468" data-path="images/integrations/aci-worker-subscription.png" />

Then click Save.

## Step 6. Pick up a flow run with your new worker

This guide uses ACR to store a Docker image containing your flow code.

### 1. Confirm that the worker is online

In the Prefect UI, open your work pool and verify that the worker you started in Azure shows as online before deploying a flow.

### 2. Log in to ACR

Use the following commands to log in to ACR:

```bash theme={null}
TOKEN=$(az acr login --name $REGISTRY_NAME --expose-token --output tsv --query accessToken)
```

```bash theme={null}
docker login $REGISTRY_NAME.azurecr.io --username 00000000-0000-0000-0000-000000000000 --password-stdin <<< $TOKEN
```

### 3. Create a simple flow

Create a file named `my_flow.py`:

```python my_flow.py theme={null}
from prefect import flow
from prefect.logging import get_run_logger

@flow
def my_flow():
    logger = get_run_logger()
    logger.info("Hello from ACI!")
```

### 4. Create a deployment

Choose either the Python-based deployment flow or a `prefect.yaml`-based deployment flow.

<Tabs>
  <Tab title="Deploy with Python">
    Add a deployment section to `my_flow.py` and run the file:

    ```python my_flow.py theme={null}
    from prefect import flow
    from prefect.docker import DockerImage
    from prefect.logging import get_run_logger


    @flow
    def my_flow():
        logger = get_run_logger()
        logger.info("Hello from ACI!")


    if __name__ == "__main__":
        my_flow.deploy(
            name="aci-deployment",
            work_pool_name="<work-pool-name>",
            image=DockerImage(
                name="<registry-name>.azurecr.io/example:latest",
                platform="linux/amd64",
            ),
        )
    ```

    ```bash theme={null}
    python my_flow.py
    ```

    This builds the image, pushes it to ACR, and creates a deployment in Prefect.
  </Tab>

  <Tab title="Deploy with prefect.yaml">
    If you want to use the Docker build and push steps shown below, install `prefect-docker` first:

    ```bash theme={null}
    pip install prefect-docker
    ```

    Create a `prefect.yaml` file in the same directory:

    ```yaml prefect.yaml theme={null}
    build:
      - prefect_docker.deployments.steps.build_docker_image:
          id: build-image
          image_name: <registry-name>.azurecr.io/example
          tag: latest
          dockerfile: auto

    push:
      - prefect_docker.deployments.steps.push_docker_image:
          image_name: "{{ build-image.image_name }}"
          tag: "{{ build-image.tag }}"

    pull:
      - prefect.deployments.steps.set_working_directory:
          directory: /opt/prefect

    deployments:
      - name: aci-deployment
        entrypoint: my_flow.py:my_flow
        work_pool:
          name: <work-pool-name>
          job_variables:
            image: "{{ build-image.image }}"
    ```

    Then create the deployment:

    ```bash theme={null}
    prefect deploy --prefect-file prefect.yaml --all
    ```
  </Tab>
</Tabs>

### 5. Run the deployment

Once the deployment is created, you can run it from either the Prefect UI or the CLI:

```bash theme={null}
prefect deployment run "my-flow/aci-deployment"
```

If everything is configured correctly, the worker will pull the image from ACR and start a new Azure Container Instance for the flow run.

## Next steps

* For more deployment options, see [How to deploy flows with Python](/v3/how-to-guides/deployments/deploy-via-python)
* For more YAML options, see [Define deployments with prefect.yaml](/v3/how-to-guides/deployments/prefect-yaml)
* If you're using Prefect Cloud, consider whether an [ACI push work pool](/v3/how-to-guides/deployment_infra/serverless#azure-container-instances) better fits your setup
