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
On my Next Write-Up, i`ll be writing on how to perform the deployment using terraform.



