DEV Community

Cover image for GitHub Actions - Azure Container Apps build/deploy
Richard Basson
Richard Basson

Posted on

GitHub Actions - Azure Container Apps build/deploy

This is a tutorial on how to deploy Azure Container Apps using GitHub Actions. I will provide examples and step-by-step instructions on how to build custom Github Actions workflows for deploying container apps to Azure. This will show you how to create your own actions for container deployments based on your needs.

Some assumptions:

  • You have an Azure account.
  • You have a GitHub account.
  • You have the Azure CLI.
  • You have access to create resources and service principles in the Azure subscription you’re going to deploy to.
  • You have an image repository where you can store container images.
  • You have code to deploy.

Here is an example of an action workflow that I use to deploy my container apps:

# The name of the deployment
name: Trigger auto deployment for containerapps

# When this action will be executed
on:
  # Automatically trigger it when detected changes in repo
  push:
    # Branched to look out for changes on
    branches: 
      [ main ]

  # Allow manually trigger of the jobs
  workflow_dispatch:      

jobs:
  # Job run image.
    build:
      runs-on: ubuntu-latest

   # Steps that need to happen in this job run.
      steps:
        # Check out the code
        - name: Check out code
          uses: actions/checkout@v2

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

        # Build and deploy the container app
        - name: Build and deploy Container App
          uses: azure/container-apps-deploy-action@v0
          with:
            appSourcePath: ${{ github.workspace }}
            acrName: <Container-Registery-Name>
            acrUsername: ${{ secrets.REGISTRY_USERNAME }}
            acrPassword: ${{ secrets.REGISTRY_PASSWORD }}
            containerAppName: <Container-App-Name>
            containerAppEnvironment: <Container-App-Environment-Name>
            resourceGroup: <Container-App-Resource-Group>
            imageToBuild: <Container-Registry>/<Image-Name>:<Tag e.g. ${{ github.sha }}>
            dockerfilePath: /Path/to/Dockerfile
Enter fullscreen mode Exit fullscreen mode

This is quite a lot so let’s unpack it.

GitHub Actions File structure

Workflow Name

name: Trigger auto deployment for containerapps

This is the name you want to give your deployment run.

Workflow triggers

# When this action will be executed
on:
  # Automatically trigger it when detected changes in repo
  push:
    # Branched to look out for changes on
    branches: 
      [ main ]

  # Allow manually trigger of the jobs
  workflow_dispatch:
Enter fullscreen mode Exit fullscreen mode

The worflow trigger is how you choose to trigger your deploy. This example creates a trigger based on me pushing code to my main branch; you can set this based on the branch you trigger deploys from. It’s also possible to use wildcards, for example:

branches:
      - main
      - 'releases/**'
Enter fullscreen mode Exit fullscreen mode

The workflow_dispatch allows you to manually trigger the workflow in GitHub actions. I found this particularly useful when I’ve made changes to the infrastructure and I need to trigger a deployment again.

You can read more about workflow triggers here:

Events that trigger workflows - GitHub Docs

Jobs

This is a grouping of steps that need to run. You can have one or multiple jobs. 

The example above only has 1 job called "build" which builds and deploys the project and runs on the ubuntu image.

These jobs run in parallel by default but you can create a dependency on other jobs by using the needs: keyword. You can also conditionally run jobs.

jobs:
  review:
    name: Deploy/Review

  staging:
    name: Deploy/Staging

  production:
    name: Deploy/Production
    if: ${{ always() }}
    needs: [staging, review]
Enter fullscreen mode Exit fullscreen mode

Image description

In the above image the Deploy/Staging, Deploy/Review and Deploy/Production blocks are jobs.

You can read more about jobs here:

Using jobs in a workflow - GitHub Docs

Steps

These are tasks that need to run as part of the job. In this case, we have 3 steps that need to run as part of the job.

  1. Check out code
  2. Log in to Azure
  3. Build and deploy Container App

These can consist of actions from the marketplace or custom actions, but in this case, we are using standard marketplace actions.

The “Check out code” step checks out the code from the repo you’re running this action from into the container that the build/deploy is running in.

The“ Log in to Azure” step logs you into the azure CLI and gives the deployment an access token to deploy the container app.

The “Build and deploy Container App” builds and deploys the container app in the coming section we’ll get into more detail on what that does.

Credentials and secret setup

We need to first of all, create a service principal in Azure. The best way would be to use this Azure CLI.

Make sure you’re logged into the subscription you want to deploy the container app.

You then run the following command to create the service principle:

az ad sp create-for-rbac --name "myApp" --role contributor \
                            --scopes /subscriptions/{subscription-id}/resourceGroups/{resource-group} \
                            --sdk-auth
Enter fullscreen mode Exit fullscreen mode

Replace the {subscription-id} and {resource-group} with the subscription Id and the resource group, you want to deploy to respectively. You should also replace myApp with your service principles name.

This command will create an RBAC (role-based access control) service principle which then has contributor access to the subscription and resource group.

You will then get an output that looks like the one below. You should be careful not to share this as it is sensitive information. You will need to keep this as you will use it soon.

{
   "clientId": "<GUID>",
   "clientSecret": "<STRING>",
   "subscriptionId": "<GUID>",
   "tenantId": "<GUID>",
   "resourceManagerEndpointUrl": "<URL>"
   (...)
 }
Enter fullscreen mode Exit fullscreen mode

Now to create the Secret in GitHub on the repo so it can be used for the action.

  1. Click on the repo you want to deploy.
  2. Navigate to Settings
  3. Then under Security expand Secrets and variables
  4. Click “Actions”
  5. While on the secrets tab click on “New repository secret”
  6. Create a secret called “AZURE_CREDENTIALS
  7. Make the secret value the value you got above from creating the service principle.

Image description

Image description

Image description

This part is only required if you want to use a container registry.

While you are creating secrets you will need 2 more. The “REGISTRY_USERNAME” and “REGISTRY_PASSWORD”. This can be obtained from your Azure container registry.

REGISTRY_USERNAME is the username of the registry user.

REGISTRY_PASSWORD is the password of the registry user.

The bare minimum

Your first half of the workflow page should look something like this:

# The name of the deployment
name: Trigger auto deployment for containerapps

# When this action will be executed
on:
  # Automatically trigger it when detected changes in repo
  push:
    # Branched to look out for changes on
    branches: 
      [ main ]

  # Allow mannually trigger of the jobs
  workflow_dispatch:      

jobs:
        # Job run image.
    build:
      runs-on: ubuntu-latest
Enter fullscreen mode Exit fullscreen mode

The following steps you add will be based on different scenarios.
So lets start with the first three.

1.) You are deploying an existing container image with public registry access.

steps:

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

  - name: Build and deploy Container App
    uses: azure/container-apps-deploy-action@v0
    with:
      imageToDeploy: mcr.microsoft.com/azuredocs/containerapps-helloworld:latest
Enter fullscreen mode Exit fullscreen mode

2.) You are building and deploying an image.

steps:

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

  - name: Build and deploy Container App
    uses: azure/container-apps-deploy-action@v0
    with:
      appSourcePath: ${{ github.workspace }}
      acrName: mytestacr
Enter fullscreen mode Exit fullscreen mode

3.) You don’t have a dockerfile or built image but you have the runtime stack.

steps:

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

  - name: Build and deploy Container App
    uses: azure/container-apps-deploy-action@v0
    with:
      appSourcePath: ${{ github.workspace }}
      acrName: mytestacr
      runtimeStack: 'dotnetcore:7.0'
Enter fullscreen mode Exit fullscreen mode

With these scenarios if you don’t have the container app, container environment, or resource group created either manually or by a previous run, it will create these resources for you.

The resources will be named as follows:

  • Container App: github-action-container-app-<github-run-id>-<github-run-attempt>
  • Resource Group: <container-app-name>-rg
  • Container App Environment: <container-app-name>-env

I have found this to not be ideal in most cases, so let’s see what we need to give it to not create these.

Additional arguments

So to prevent the action from creating these resources, you will need to give it the name of existing resources or give it names of resources you want to initally create and subsequently re-use.

You can then add these arguments to your “Build and deploy Container App” step.

containerAppName: <Container-App-Name>
containerAppEnvironment: <Container-App-Environment-Name>
resourceGroup: <Container-App-Resource-Group>
Enter fullscreen mode Exit fullscreen mode

If you have a custom Docker image you want to build and deploy, you need to use these arguments to build the image and deploy it. This is if you have an existing Dockerfile

imageToBuild: <Container-Registry>/<Image-Name>:<Tag e.g. ${{ github.sha }}>
dockerfilePath: /Path/to/Dockerfile
Enter fullscreen mode Exit fullscreen mode

You will also need to log into your container registry to push the image, so you will need these below arguments as well. You will also need these if you’re pulling an image from a private image repository.

acrName: <Container-Registery-Name>
acrUsername: ${{ secrets.REGISTRY_USERNAME }}
acrPassword: ${{ secrets.REGISTRY_PASSWORD }}
Enter fullscreen mode Exit fullscreen mode

Some of the other ones I have not used but can be useful are:

  • environmentVariables A list of environment variable(s) for the container. Space-separated values in 'key=value' format. Empty string to clear existing values. Prefix value with 'secretref:' to reference a secret.
  • targetPort The target port that the Container App will listen on. If not provided, this value will be "80" for Python applications and "8080" for all other supported platforms.

Well done! You’ve made it all the way to the end.

You’ve now unlocked the skill to deploy Azure container apps using GitHub action

If you like this post consider following me here or on Twitter @bassonrichard

If you want to do some more reading here is the documentation for the GitHub Action

Azure Container Apps Build and Deploy - GitHub Marketplace

Top comments (0)