Skip to main content

Command Palette

Search for a command to run...

Deploying To Azure Container Apps Using Github Actions.

Updated
5 min read
Deploying To Azure Container Apps Using Github Actions.

Azure Container App Deployment

With the growing popularity of microservices and containerized workloads, Azure Container Apps offers a fully managed platform for deploying modern apps without managing infrastructure. Azure Container Apps is a serverless platform that allows you to maintain less infrastructure and save costs while running containerized applications. Instead of worrying about server configuration, container orchestration, and deployment details, Container Apps provides all the up-to-date server resources required to keep your applications stable and secure.

Common uses of Azure Container Apps include:

  • Deploying API endpoints

  • Hosting background processing jobs

  • Handling event-driven processing

  • Running microservices

This guide walks you through deploying an application to Azure Container Apps using GitHub Actions. Also it would show how to integrate Dapr connect with CosmosDB and Azure Service Bus.

🧱 Prerequisites

Before you begin, ensure you have the following:

  • An Azure subscription

  • A GitHub repository with your containerized app (e.g., Node.js, Python, .NET, etc.)

  • Dockerfile in your project root

  • Azure CLI installed locally (for initial setup)

  • Azure Container Registry (ACR) or Docker Hub (for container image hosting)

  • CosmosDB (You can use any Databases)

  • Azure Service Bus

⚙️Get the connection values for the following

  • Cosmos DB yaml file
##daprstatedatabase.yml
# statestore for Azure Cosmos DB component
componentType: state.azure.cosmosdb
version: v1
metadata:
  - name: masterKey
    value: {masterKey} 
  - name: database
    value: {database} 
  - name: collection
    value: {collection} 
secrets:
  - name: url
    value: {ComosDb_url} 
scopes:
  - {API_NAME}
  • Azure Service Bus yaml file
#daprstateservicebus.yml
# statestore for Azure Service Bus component
componentType: pubsub.azure.servicebus
version: v1
metadata:
  - name: connectionString
    value: {SBConnectionString} 
scopes:
  - {API_NAME}

You can get more of the Dapr component connection parameters from Dapr Docs.

  • Container App Yaml file
##containerapp.yaml
kind: containerapp
location: {LOCATION}
name: {API_NAME}
resourceGroup: {RESOURCE_GROUP}
type: Microsoft.App/containerApps
tags:
  tagname: {API_NAME}
properties:
  managedEnvironmentId: /subscriptions/{subscription_id}/resourceGroups/{RESOURCE_GROUP}/providers/Microsoft.App/managedEnvironments/{ENVIRONMENT}
  configuration:
    activeRevisionsMode: Multiple
    clientCertificateMode: accept
    secrets:
      - name: mysecret
        value: thisismysecret
    ingress:
      external: true
      allowInsecure: false
      targetPort: 80
      traffic:
        - latestRevision: true
          weight: 100
      transport: Auto
    registries:
      - passwordSecretRef: myregistrypassword
        server: {REGISTRY_LOGIN_SERVER} 
        username: {REGISTRY_USERNAME} 
    dapr:
      appId: {API_NAME}
      appPort: 80
      appProtocol: http
      enabled: true
  template:
    revisionSuffix: revision-{BuildNumber}
    containers:
      - image: {REGISTRY_LOGIN_SERVER}/{API_NAME}:{BuildNumber}
        name: {API_NAME}
        env:
          - name: HTTP_PORT
            value: 80
          - name: secret_name
            secretRef: mysecret
        resources:
          cpu: 0.5
          memory: 1Gi
        probes:
          - type: liveness
            httpGet:
              path: "/health"
              port: 8080
              httpHeaders:
                - name: "Custom-Header"
                  value: "liveness probe"
            initialDelaySeconds: 7
            periodSeconds: 3
          - type: readiness
            tcpSocket:
              port: 8081
            initialDelaySeconds: 10
            periodSeconds: 3
          - type: startup
            httpGet:
              path: "/startup"
              port: 8080
              httpHeaders:
                - name: "Custom-Header"
                  value: "startup probe"
            initialDelaySeconds: 3
            periodSeconds: 3
    scale:
      minReplicas: 1
      maxReplicas: 3

🧩Github Actions yaml file for the CI/CD pipeline


name: Build and Deploy
on:
  push:
    branches: [main]
  workflow_dispatch:


env:  
  subscription_id:        ${{ secrets.subscription_id }}
  client_id:              ${{ secrets.client_id }}
  client_secret:          ${{ secrets.client_secret }}
  tenant_id:              ${{ secrets.tenant_id }}
  BuildNumber:            ${{github.run_number}} 

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

      - name: Azure Login
        run: az login --service-principal -u ${{ secrets.CLIENT_ID }} -p ${{ secrets.CLIENT_SECRET }} --tenant ${{ secrets.TENANT_ID }}

      - name: Replace tokens for containerapp.yaml
        uses: cschleiden/replace-tokens@v1.0
        with:
          tokenPrefix: '{'
          tokenSuffix: '}'
          files: '["**/containerapp.yaml"]'
        env: 
          BuildNumber:            ${{github.run_number}}
          API_NAME:               ${{env.API_NAME}} #Image Name
          REGISTRY_LOGIN_SERVER:  ${{ env.REGISTRY_LOGIN_SERVER }}  #Example: myregistry.azurecr.io
          REGISTRY_USERNAME:      ${{ env.REGISTRY_USERNAME }} #Container Registry Username
          REGISTRY_PASSWORD:      ${{ env.REGISTRY_PASSWORD }} 
          RESOURCE_GROUP:         ${{env.RESOURCE_GROUP}} # RG
          ENVIRONMENT:            ${{env.ENVIRONMENT}}
          LOCATION:               ${{env.LOCATION}}

      - name: Replace tokens for daprstatedatabase.yml
        uses: cschleiden/replace-tokens@v1.0
        with:
          tokenPrefix: '{'
          tokenSuffix: '}'
          files: '["**/daprstatedatabase.yml"]'
        env: 
          ComosDb_url:    ${{env.ComosDb_url}}
          masterKey:      ${{env.masterKey}}
          database:       ${{env.database}}
          collection:     ${{env.collection}}
          API_NAME:       ${{env.API_NAME}} #Image Name

      - name: Replace tokens for daprstateservicebus.yml
        uses: cschleiden/replace-tokens@v1.0
        with:
          tokenPrefix: '{'
          tokenSuffix: '}'
          files: '["**/daprstateservicebus.yml"]'
        env: 
          SBConnectionString:   ${{env.SBConnectionString}}
          API_NAME:             ${{env.API_NAME}} 

        #In some senarios the replace token task doen`t take effect, you can use this bash script instead
      - name: update tokens 
        run: |
         bash -c "sed -i 's/BuildNumber/${{github.run_number}}/g'  containerapp.yaml"
         bash -c "sed -i 's/REGISTRY_LOGIN_SERVER/${{env.REGISTRY_LOGIN_SERVER}}/g'  containerapp.yaml"
         bash -c "sed -i 's/REGISTRY_USERNAME/${{env.REGISTRY_USERNAME}}/g'  containerapp.yaml"
         bash -c "sed -i 's/REGISTRY_PASSWORD/${{env.REGISTRY_PASSWORD}}/g'  containerapp.yaml"
         bash -c "sed -i 's/API_NAME/${{env.API_NAME}}/g'  containerapp.yaml"
         bash -c "sed -i 's/RESOURCE_GROUP/${{env.RESOURCE_GROUP}}/g'  containerapp.yaml"
         bash -c "sed -i 's/ENVIRONMENT/${{env.ENVIRONMENT}}/g'  containerapp.yaml"
         bash -c "sed -i 's/LOCATION/${{env.LOCATION}}/g'  containerapp.yaml"
         bash -c "sed -i 's/API_NAME/${{env.API_NAME}}/g'  daprstatedatabase.yml"
         bash -c "sed -i 's/API_NAME/${{env.API_NAME}}/g'  daprstateservicebus.yml"
         bash -c "sed -i 's/API_NAME/${{env.API_NAME}}/g'  daprstateservicebus.yml"     

      - name: 'Publish Artifact'
        uses: actions/upload-artifact@v3
        with:
          name: artifact-containerapp-yaml
          path: containerapp.yaml

      - name: 'Publish Artifact'
        uses: actions/upload-artifact@v3
        with:
          name: artifact-daprstatedatabase.yml
          path: daprstatedatabase.yml

      - name: 'Publish Artifact'
        uses: actions/upload-artifact@v3
        with:
          name: artifact-daprstatedatabase.yml
          path: daprstatedatabase.yml


  #Build image and push to Container Registry
      - name: 'Build and Push image'
        uses: azure/docker-login@v1
        with:
          login-server: ${{ env.REGISTRY_LOGIN_SERVER }}
          username: ${{ env.REGISTRY_USERNAME }}
          password: ${{ env.REGISTRY_PASSWORD }}
      - run: |
          docker build . -t ${{ env.REGISTRY_LOGIN_SERVER }}/${{env.API_NAME}}:${{github.run_number}}
          docker push ${{ env.REGISTRY_LOGIN_SERVER }}/${{env.API_NAME}}:${{github.run_number}}

      - name: 'Pull image'
        uses: azure/docker-login@v1
        with:
          login-server: ${{ env.REGISTRY_LOGIN_SERVER }}
          username: ${{ env.REGISTRY_USERNAME }}
          password: ${{ env.REGISTRY_PASSWORD }}
      - run: |
          az config set extension.use_dynamic_install=yes_without_prompt

  #Dapr Connection for CosmosDB
      - run: |
          az containerapp env dapr-component set \
            --name ${{env.ENVIRONMENT}} --resource-group ${{env.RESOURCE_GROUP}} \
            --dapr-component-name statestoredbconnection \
            --yaml "daprstatedatabase.yml"

  #Dapr Connection for Service Bus
      - run: |
          az containerapp env dapr-component set \
            --name ${{env.ENVIRONMENT}} --resource-group ${{env.RESOURCE_GROUP}} \
            --dapr-component-name stateservicebusconnection \
            --yaml "daprstateservicebus.yml"

      - name: Resource group list
        run: az containerapp env list --resource-group ${{env.RESOURCE_GROUP}} 

  #Create Conatiner Apps/Revisions
      - run: |
          az containerapp create -n ${{env.API_NAME}}   -g ${{env.RESOURCE_GROUP}}  --environment ${{env.ENVIRONMENT}} \
            --yaml "containerapp.yaml"

🎉 Conclusion

Using GitHub Actions with Azure Container Apps creates a powerful and flexible CI/CD pipeline with minimal effort. With every commit to your main branch, your app will automatically build and deploy — accelerating your development cycle and ensuring consistent deployments.

Referrences

Microsoft Learn

Dapr Docs

On my Next Write-Up, i`ll be writing on how to perform the deployment using terraform.

M
Muh'd Bello11mo ago

Good read. Many thanks for sharing

Deploying To Azure Container Apps Using Github Actions.