Shipping a containerized app to the cloud doesn’t have to be complicated.

In this blog post, I’ll walk you through deploying a Dockerized application to Azure step-by-step from pushing your image to Azure Container Registry (ACR) to automating your deployments with GitHub Actions.

Whether you're building your first cloud native app or just need a quick blueprint for setting up Azure CI/CD, this walkthrough has you covered with screenshots, code snippets, and tips to avoid common pitfalls.

Prerequisites

Before starting, ensure you have the Azure CLI installed and you're logged in. Follow the installation guidehere

A GitHub repository containing your Dockerfile & FastAPI code.

Step 1. Create an Azure Container Registry (ACR)

We'll:

  1. Create a Container Registry.
  2. Push our Docker image to ACR
  3. Take note of the login server, username, and password

Create Container Registry

In the Azure Portal, click Create a resource > Container Registry.

createresource

createcontainer

Use these settings.

Subscription: Your Azure subscription
Resource group: Create or use an existing one
Registry name: Give your container a unique name
Location: Choose your region
Pricing plan: Basic

networking

Skip Networking, Encryption, and Tags.

Click Create after "Validation passed" appears.

Push Your Image

Your ACR deployment is now created and completed we have to push our image store in local machine (VSCode) to the remote container.

Make sure you are in the folder/path that contains the image

Once deployed:

Click Go to resource.

Image description

Scroll down and select Pushing a container image

Image description

You'll see instructions like these (note: Azure provides generic hello-world example commands that we'll need to modify):

Image description

To push your FastAPI application instead of the hello-world example, use these commands modify the example commands to fit your project:

# Login to your Azure Container Registry
az acr login --name 

# Build your FastAPI Docker image (if not already built)
docker build -t  .

# Tag your local image with your ACR address
docker tag fastapidemo myfastapidemo.azurecr.io/fastapidemo:latest

# Push your tagged image to Azure Container Registry
docker push myfastapidemo.azurecr.io/fastapidemo:latest

Best practice: use explicit version tags (v1.0, v2025‑04‑23, etc.).

You should see an output similar to mines.

Image description

Verify your image was pushed successfully with:

az acr repository list --name  --output table

repository-list

You can also see it from the Azure portal.

azure-portal

Step 2. Create an APP Service & Web App

In this Section you will:

  1. Create an App Service Plan (Linux)
  2. Create a Web App for Containers
  3. Link it to ACR

An AppService is an HTTP-based service for hosting web applications, REST APIs, and mobile back ends.

A WebApp is an AppService that focuses on hosting web applications.

In Azure Portal, search App Services > Create > Web App

create-webapp

Basics

Every Field with an (* = required) must be filled

Use these Settings:
Resource Group: Select your resource group
Name: Create a Unique name
Publish(*): Container
Operating System(*): Linux
Region: Select your region
Pricing plan: Free F1 (to keep cost low)

Example.

webapp-settings

Hit Next and skip for the Database page

Configure the container

Use the settings:

Image Source: Azure Container Registry
Registry: Select the ACR registry
Authentication: Managed identity
Image: fastapidemo (your image name)
Tag: latest (your image tag)

For the tag its best practice to avoid generic tags such as :latest instead use 1.O I only use latest for demonstration purposes

webapp-container

Hit Next

Networking

Enable public access: On

Hit Next

Monitor + secure

Enable Application Insights: No

In production its best to turn on to track and logs your apps data
Enable Defender for App Service: leave blank

Hit Next and Skip the Tags page

Review + Create -> Create

webapp-create

You should now see your basic web app all you have to do is verify your configurations now click Create

If you receive any failed deployments error switch to a different region and redeploy

created-webapp

Access & Verify Web App

On success, select Go to resource and open the Default Domain to confirm the app loads.

default-domain

If you set everything up right you should see your containers page.

container-page

If you have any issues on the resource page under Deployment Center > View logs you will see where your deployment failed.

deployment-log

Step 3. Set Up GitHub Actions CI/CD

We will:

  1. Enable Deployment Center
  2. Generate a workflow file
  3. Add GitHub secrets

Enable deployment Center

In your Web App portal on the left side select Deployment > Deployment Center

Image description

If you see the red "SCM basic authentication is disabled for your app. Click here to go to your configuration settings to enable." it needs to be enabled.

Click it and under Platform settings toggle SCM Basic Auth Publishing: On

Save the changes above and continue to update the app.

Connect to GitHub

Source: Github Actions

Image description

Authorize GitHub, select repo + branch once completed fill in your repos details.

The rest of your Registry settings should auto‑populate (note the managed identity it shows).

Image description

In a new tab access your container registry.

Azure Portal > your ACR > Settings > Identity > User Assigned.

Image description

Add the user assigned managed identity you have listed in Deployment Center.

Now head on back to your deployment center

Hit the Save button up above

Our build will fail we will resolve this issue in the next.

✏️ Fix the generated workflow

Head over to your GitHub repo — you'll see a new folder named .github/workflows.

This was automatically created by Azure Deployment Center when you enabled CI/CD.

Open the .yml file inside (e.g., azure-webapps.yml) — and click the ✏️ pencil icon to edit it directly in GitHub.

The code is a general-purpose template — we’ll customize it to match our actual Azure setup.

Replace the Docker login block with Azure‑based auth:


🐳 Original Build & Login Block:

You'll see something like this:

jobs:
  build:
    runs-on: 'ubuntu-latest'

    steps:
    - uses: actions/checkout@v2

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v2

    - name: Log in to registry
      uses: docker/login-action@v2
      with:
        registry: https://myfastapidemo.azurecr.io/
        username: ${{ secrets.AzureAppService_ContainerUsername_dac00c4d6aa44559aceb4c95969103fb }}
        password: ${{ secrets.AzureAppService_ContainerPassword_acd4866e025148088786c136581277b5 }}

    - name: Build and push container image to registry
      uses: docker/build-push-action@v3
      with:
        push: true
        tags: myfastapidemo.azurecr.io/${{ secrets.AzureAppService_ContainerUsername_dac00c4d6aa44559aceb4c95969103fb }}/fastapidemo:${{ github.sha }}
        file: ./Dockerfile

This login method assumes credentials for Docker Hub or a public registry — but we’re using Azure Container Registry (ACR) with Azure credentials.

✅ Replace It With:

jobs:
  build:
    runs-on: 'ubuntu-latest'

    steps:
    - uses: actions/checkout@v2

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v2

    - name: Azure Login
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: 'Build and push image'
      uses: azure/docker-login@v1
      with:
        login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
        username: ${{ secrets.REGISTRY_USERNAME }}
        password: ${{ secrets.REGISTRY_PASSWORD }}
    - run: |
        docker build . -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/:${{ github.sha }}
        docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}//:${{ github.sha }}

This uses the Azure CLI to securely authenticate to ACR using a service principal instead of Docker username/password.

Add GitHub secrets

In this section we will be setting the AZURE_CREDENTIALS secret.

Open your terminal and run the following commands

This command shows all your active resource groups look for you resource group related to your ACR/webapp. Copy the resource group "id".

az group list

Create a service principal:

az ad sp create-for-rbac --scopes  --role Contributor --sdk-auth

example

az ad sp create-for-rbac \
  --scopes /subscriptions/88888839283023/resourceGroups/FastApI \
  --role Contributor \
  --sdk-auth

Your output will look similar to:

{
  "clientId": "xxxx6ddc-xxxx-xxxx-xxx-ef78a99dxxxx",
  "clientSecret": "xxxx79dc-xxxx-xxxx-xxxx-aaaaaec5xxxx",
  "subscriptionId": "aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e",
  "tenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
  "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
  "resourceManagerEndpointUrl": "https://management.azure.com/",
  "activeDirectoryGraphResourceId": "https://graph.windows.net/",
  "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
  "galleryEndpointUrl": "https://gallery.azure.com/",
  "managementEndpointUrl": "https://management.core.windows.net/"
}

Save the JSON output because it's used in a later step.

Take note of the clientId, which you need to update the service principal in the next section.

Now we need to update the service principal to allow ACR to push and pull

Lets get our registry name.

az acr list --query "[].{Name:name}" --output table

Get the resource ID of your container registry. Replace and .

registryId=$(az acr show --name  --resource-group  --query id --output tsv)

Assign AcrPush to the service principal, which gives push and pull access to the registry. Substitute the client ID of your service principal:

az role assignment create --assignee  --scope $registryId --role AcrPush

Save the credentials to your GitHub repo, go to your repository Settings under Security > Secrets and variables > Actions > New repository secret.

Add the following secrets:

Image description

AZURE_CREDENTIALS paste full JSON including "{}"

For enterprise-grade setups, consider using Workload Identity Federation or certificate-based service principals to avoid storing long-term secrets.

Test the Pipeline

Lets make a change to our code to see if any changes made in our code will build and deploy and show on our Azure app service.

Any changes to the repo will automatically trigger our GitHub action to Build and deploy to Azure.

For me I will be making the changes to my fastapi code from {"Welcome": "To Azure"} to {"Novice": "To Azure"} and commit the code.

After you have made the changes wait for your actions to deploy than check back to you app service domain.

novice

As you can see the change have been reflected Automatically.

Cleanup resources

Now that we have deployed everything we need to cleanup the resources to not accrue charges.

Delete the resource group to stop charges:

az group delete --name ExampleResourceGroup -y

Replace ExampleResourceGroup with your resource group name you can locate your resource groups using

az group list

Or remove it via Azure Portal.

Search for Resource groups in the azure portal and locate the resource group you create and select it and just hit Delete resource group

Conclusion

If you followed along, you now have:

  • A Docker image safely stored in Azure Container Registry (ACR)
  • A FastAPI web app running live on Azure App Service
  • An end‑to‑end CI/CD pipeline powered by GitHub Actions that redeploys on every push