06 - CI/CD with GitHub Actions¶
Automate build and deployment so every commit can produce a new Container App revision. This tutorial uses GitHub Actions, ACR, and Azure Container Apps deploy actions.
Infrastructure Context
Service: Container Apps (Consumption) | Network: VNet integrated | VNet: ✅
This tutorial assumes a production-ready Container Apps deployment with a custom VNet, ACR with managed identity pull, and private endpoints for backend services.
flowchart TD
INET[Internet] -->|HTTPS| CA["Container App\nConsumption\nLinux Python 3.11"]
subgraph VNET["VNet 10.0.0.0/16"]
subgraph ENV_SUB["Environment Subnet 10.0.0.0/23\nDelegation: Microsoft.App/environments"]
CAE[Container Apps Environment]
CA
end
subgraph PE_SUB["Private Endpoint Subnet 10.0.2.0/24"]
PE_ACR[PE: ACR]
PE_KV[PE: Key Vault]
PE_ST[PE: Storage]
end
end
PE_ACR --> ACR[Azure Container Registry]
PE_KV --> KV[Key Vault]
PE_ST --> ST[Storage Account]
subgraph DNS[Private DNS Zones]
DNS_ACR[privatelink.azurecr.io]
DNS_KV[privatelink.vaultcore.azure.net]
DNS_ST[privatelink.blob.core.windows.net]
end
PE_ACR -.-> DNS_ACR
PE_KV -.-> DNS_KV
PE_ST -.-> DNS_ST
CA -.->|System-Assigned MI| ENTRA[Microsoft Entra ID]
CAE --> LOG[Log Analytics]
CA --> AI[Application Insights]
style CA fill:#107c10,color:#fff
style VNET fill:#E8F5E9,stroke:#4CAF50
style DNS fill:#E3F2FD CI/CD Pipeline Flow¶
graph LR
PUSH[Push to main] --> GHA[GitHub Actions]
GHA --> ACR[ACR Build]
ACR --> DEPLOY[Deploy Revision]
DEPLOY --> HEALTH[Health Check] Prerequisites¶
- Completed 05 - Infrastructure as Code with Bicep
- GitHub repository with Actions enabled
- Azure service principal stored as GitHub secret
Never expose credentials in workflow logs
Keep all credential material in GitHub Secrets and avoid printing secret-derived values in shell steps. Use masked placeholders in documentation and workflow examples.
Step-by-step¶
-
Configure repository variables and secrets
-
Variables:
RESOURCE_GROUP,APP_NAME,ACR_NAME - Secrets:
AZURE_CREDENTIALS,REGISTRY_USERNAME,REGISTRY_PASSWORD
Example AZURE_CREDENTIALS JSON (masked):
{
"clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"clientSecret": "<client-secret>",
"subscriptionId": "<subscription-id>",
"tenantId": "<tenant-id>"
}
- Create workflow file
name: Deploy to Azure Container Apps
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Azure Login
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: ACR Login
uses: azure/docker-login@v2
with:
login-server: ${{ vars.ACR_NAME }}.azurecr.io
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build and push image
run: |
docker build --tag ${{ vars.ACR_NAME }}.azurecr.io/${{ vars.APP_NAME }}:${{ github.sha }} .
docker push ${{ vars.ACR_NAME }}.azurecr.io/${{ vars.APP_NAME }}:${{ github.sha }}
- name: Deploy Container App
uses: azure/container-apps-deploy-action@v1
with:
imageToDeploy: ${{ vars.ACR_NAME }}.azurecr.io/${{ vars.APP_NAME }}:${{ github.sha }}
resourceGroup: ${{ vars.RESOURCE_GROUP }}
containerAppName: ${{ vars.APP_NAME }}
- Add infrastructure deployment (optional but recommended)
- name: Deploy Infrastructure
uses: azure/arm-deploy@v2
with:
resourceGroupName: ${{ vars.RESOURCE_GROUP }}
template: ./infra/main.bicep
parameters: appName=${{ vars.APP_NAME }} acrName=${{ vars.ACR_NAME }}
-
Validate rollout behavior
- Trigger workflow from a commit to
main. - Confirm a new revision was created.
- Confirm traffic moved to healthy revision.
az containerapp revision list \ --name "$APP_NAME" \ --resource-group "$RG" \ --query "[].{name:name,active:properties.active,trafficWeight:properties.trafficWeight,replicas:properties.replicas,healthState:properties.healthState,runningState:properties.runningState}"Expected output
- Trigger workflow from a commit to
Advanced Topics¶
- Add pre-deploy tests and security scanning gates.
- Implement staged deployment with manual approval.
- Use multiple active revisions for canary rollout in pipeline.
Use immutable image tags in pipelines
Prefer commit SHA or release-based tags for image versions. Immutable tags make revision-to-commit tracing straightforward during incident response.