Azure Container Apps: CI/CD with GitHub Actions

Automate your container deployments seamlessly.

Introduction

Continuous Integration and Continuous Deployment (CI/CD) is a crucial practice for modern software development. This tutorial will guide you through setting up an automated CI/CD pipeline for your containerized applications deployed on Azure Container Apps using GitHub Actions. We'll cover building Docker images, pushing them to a container registry, and deploying to Azure.

By the end of this tutorial, you will have a GitHub Actions workflow that automatically builds and deploys your application whenever code changes are pushed to your repository.

Prerequisites

  • An Azure subscription with an active account.
  • A GitHub account.
  • Docker installed locally (optional, for local testing).
  • A sample containerized application (e.g., a simple web application). Ensure you have a Dockerfile for it.

Setup GitHub Repository

If you don't already have one, create a new GitHub repository for your application. Make sure your application code, including the Dockerfile, is pushed to this repository.

  1. Navigate to GitHub and create a new repository.
  2. Clone the repository to your local machine.
  3. Add your application code and Dockerfile.
  4. Commit and push your changes:
    git add .
    git commit -m "Initial commit with app and Dockerfile"
    git push origin main

Create Azure Container App

First, we need to set up an Azure Container App environment and the application itself. You can do this via the Azure portal, Azure CLI, or ARM templates. For this tutorial, we'll assume you've created a basic Container App instance.

Key considerations:

  • You'll need a Container Registry (like Azure Container Registry - ACR) to store your Docker images.
  • Your Container App will need to be configured to pull images from this registry.

Using Azure CLI for quick setup:

# Install Azure CLI if you haven't already
# az extension add --name containerapp

# Login to Azure
az login

# Create a resource group
az group create --name MyContainerAppRG --location eastus

# Create an Azure Container Registry
az acr create --resource-group MyContainerAppRG --name mycontainerregistryxxx --sku Basic --admin-enabled true

# Get login server for ACR
ACR_NAME=$(az acr list --resource-group MyContainerAppRG --query "[].name" --output tsv)
ACR_LOGIN_SERVER=$(az acr show --resource-group MyContainerAppRG --name $ACR_NAME --query "loginServer" --output tsv)

# Create a Container App Environment
az containerapp env create --name MyContainerAppEnv --resource-group MyContainerAppRG --location eastus

# Create the Container App (initially without a specific image for CI/CD setup)
az containerapp create \
  --name my-container-app \
  --resource-group MyContainerAppRG \
  --environment MyContainerAppEnv \
  --target-port 80 \
  --ingress external \
  --registry-server $ACR_LOGIN_SERVER \
  --query configuration.ingress.fqdn --output tsv

Note down the ACR_LOGIN_SERVER and your Container App's FQDN (Fully Qualified Domain Name).

Configure GitHub Actions

GitHub Actions are configured using YAML files placed in the .github/workflows/ directory of your repository.

Create a new file named .github/workflows/deploy.yml in your repository and paste the following content:

name: Build and Deploy to Azure Container Apps

on:
  push:
    branches:
      - main # Or your default branch

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v3

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

    - name: Build and push Docker image to ACR
      uses: azure/docker-login@v1
      with:
        login-server: ${{ secrets.ACR_LOGIN_SERVER }}
        username: ${{ secrets.ACR_USERNAME }}
        password: ${{ secrets.ACR_PASSWORD }}

    - name: Build and push Docker image
      id: build-push
      run: |
        docker build -t ${{ secrets.ACR_LOGIN_SERVER }}/${{ github.repository_owner }}/my-container-app:${{ github.sha }} .
        docker push ${{ secrets.ACR_LOGIN_SERVER }}/${{ github.repository_owner }}/my-container-app:${{ github.sha }}

    - name: Deploy to Azure Container Apps
      uses: azure/container-apps-deploy-action@v1
      with:
        container-app-name: 'my-container-app' # Replace with your Container App name
        resource-group: 'MyContainerAppRG'      # Replace with your Resource Group name
        image: '${{ secrets.ACR_LOGIN_SERVER }}/${{ github.repository_owner }}/my-container-app:${{ github.sha }}'
        registry-url: ${{ secrets.ACR_LOGIN_SERVER }}
        registry-username: ${{ secrets.ACR_USERNAME }}
        registry-password: ${{ secrets.ACR_PASSWORD }}
        tag: ${{ github.sha }} # Ensure the tag is unique

    - name: Azure logout
      run: |
        az logout
        az cache purge
        az account clear

Setting up GitHub Secrets

You need to provide your Azure credentials and ACR details as GitHub secrets:

  1. Go to your GitHub repository settings.
  2. Navigate to Secrets and variables > Actions.
  3. Click New repository secret.
  4. Add the following secrets:
    • AZURE_CREDENTIALS: A JSON string containing your Azure service principal credentials. You can create a service principal using `az ad sp create-for-rbac --sdk-auth`.
    • ACR_LOGIN_SERVER: Your Azure Container Registry login server (e.g., `mycontainerregistryxxx.azurecr.io`).
    • ACR_USERNAME: Your Azure Container Registry admin username.
    • ACR_PASSWORD: Your Azure Container Registry admin password.

Workflow Explained

  • on: push: branches: - main: This triggers the workflow whenever a push event occurs on the main branch.
  • jobs: build-and-deploy: runs-on: ubuntu-latest: Defines a job named build-and-deploy that runs on the latest Ubuntu runner.
  • actions/checkout@v3: Checks out your repository code so the workflow can access it.
  • azure/login@v1: Logs into your Azure account using the credentials stored in the AZURE_CREDENTIALS secret.
  • azure/docker-login@v1: Logs into your Azure Container Registry.
  • Build and push Docker image step: Builds your Docker image using the Dockerfile in your repository and tags it with the commit SHA for uniqueness. Then, it pushes the image to your ACR.
  • azure/container-apps-deploy-action@v1: This is the core deployment step. It takes your image and deploys it to the specified Azure Container App.
  • Azure logout: Cleans up the Azure session.

Testing the Deployment

To test the pipeline, simply push a new commit to your main branch:

git commit -m "Test CI/CD pipeline"
git push origin main

You can monitor the workflow's progress in the Actions tab of your GitHub repository. Once the workflow completes successfully, navigate to your Azure Container App's FQDN to see your deployed application.

Conclusion

Congratulations! You have successfully set up a CI/CD pipeline for Azure Container Apps using GitHub Actions. This automation significantly speeds up your development and deployment cycles, allowing you to deliver features faster and more reliably.

You can further enhance this pipeline by adding steps for running unit tests, integration tests, managing different deployment environments (staging, production), and implementing rollbacks.