Skip to content

Latest commit

 

History

History
351 lines (255 loc) · 20.2 KB

tutorial-deploy-python-web-app-azure-container-apps-03.md

File metadata and controls

351 lines (255 loc) · 20.2 KB
title description ms.topic ms.date ms.custom ms.prod author ms.author
Configure CI/CD for a Python web app in Azure Container Apps
Set up CI/CD for a Python web app container in Azure Container Apps using GitHub Actions triggered on changes (like PRs) to the main branch of a repo.
conceptual
09/21/2022
devx-track-python
azure-python
jessmjohnson
jejohn

Configure continuous deployment for a Python web app in Azure Container Apps

This article is part of a tutorial about how to containerize and deploy a Python web app to Azure Container Apps. Container Apps enables you to deploy containerized apps without managing complex infrastructure.

In this part of the tutorial, you learn how to configure continuous deployment or delivery (CD) for the container app. CD is part of the DevOps practice of continuous integration / continuous delivery (CI/CD), which is automation of your app development workflow. Specifically, you use GitHub Actions for continuous deployment.

The service diagram shown below highlights the components covered in this article: configuration of CI/CD.

:::image type="content" source="./media/tutorial-container-apps/service-diagram-overview-for-tutorial-deploy-python-azure-container-apps-cicd.png" alt-text="A screenshot of the services in the Tutorial - Deploy a Python App on Azure Container Apps. Sections highlighted are parts related to continuous integration - continuous delivery (CI/CD)." lightbox="./media/tutorial-container-apps/service-diagram-overview-for-tutorial-deploy-python-azure-container-apps-cicd.png":::

Note

Command lines in this tutorial are shown in the Bash shell, on multiple lines for clarity. For other shell types, change the line continuation characters as appropriate. For example, for PowerShell, use back tick ("`"). Or, remove the continuation characters and enter the command on one line.

Prerequisites

To set up continuous deployment, you'll need:

  • The resources and their configuration created in the [previous article][./tutorial-deploy-python-web-app-azure-container-apps-02.md] of this tutorial series, which includes an Azure Container Registry and a container app in Azure Container Apps.

  • A GitHub account where you forked the sample code (Django or Flask) and you can connect to from Azure Container Apps. (If you downloaded the sample code instead of forking, make sure you push your local repo to your GitHub account.)

  • Optionally, Git installed in your development environment to make code changes and push to your repo in GitHub. Alternatively, you can make the changes directly in GitHub.

Configure CD for a container

In a previous article of this tutorial, you created and configured a container app in Azure Container Apps. Part of the configuration was pulling a Docker image from an Azure Container Registry. The container image is pulled from the registry when creating a container revision, such as when you first set up the container app.

In the steps below, you'll set up continuous deployment, which means a new Docker image and container revision are created based on a trigger. The trigger in this tutorial is any change to the main branch of your repository, such as with a pull request (PR). When triggered, the workflow creates a new Docker image, pushes it to the Azure Container Registry, and updates the container app to a new revision using the new image.

:::row::: :::column span="2"::: Step 1. In the Azure portal, go to the Container App you want to configure continuous deployment for and select the Continuous deployment resource. :::column-end::: :::column::: :::image type="content" source="media/tutorial-container-apps/azure-portal-continuous-deployment-signin-github.png" alt-text="Screenshot showing the continuous deployment resource of a Container App and where to sign in with GitHub in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-continuous-deployment-signin-github.png"::: :::column-end::: :::row-end::: :::row::: :::column span="2"::: Step 2. Authorize Azure Container Apps to access your GitHub account.

    * Select **Sign in with GitHub**.
    * In the authorization pop up, select **AuthorizeAppService**.

    Container App access to the GitHub accont can be revoked by going to the your account's security section and revoking access.

:::column-end:::
:::column:::
    :::image type="content" source="media/tutorial-container-apps/azure-portal-continuous-deployment-authorize-github.png" alt-text="Screenshot showing authorizing Container App to access your repo in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-continuous-deployment-authorize-github.png":::
:::column-end:::

:::row-end::: :::row::: :::column span="2"::: Step 3. After sign-in with GitHub, configure the continuous deployment details.

    * **Organization** → Use your GitHub user name.
    * **Repository** → Select the fork of the sample app. (If you originally downloaded the sample code to your developer environment, push the repo to GitHub.)
    * **Branch** → Select *main*.
    * **Repository source** → Select **Azure Container Registry**.
    * **Registry** → Select the Azure Container Registry you created earlier in the tutorial.
    * **Image** → Select the Docker image name. If you are following the tutorial, it's "python-container-app".
    * **Service principal** → Leave **Create new** and let the creation process create a new service principal.

    Select **Start continuous deployment** to finish the configuration.

:::column-end:::
:::column:::
    :::image type="content" source="media/tutorial-container-apps/azure-portal-continuous-deployment-configuration.png" alt-text="Screenshot showing the configuration of an Azure Container App in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-continuous-deployment-configuration.png":::
:::column-end:::

:::row-end::: :::row::: :::column span="2"::: Step 4. Review the continuous deployment information.

    After the continuous deployment is configured, you can find a link to the GitHub Actions workflow file created. Azure Container Apps checked the file in to your repo.
:::column-end:::
:::column:::
    :::image type="content" source="media/tutorial-container-apps/azure-portal-continuous-deployment-configuration-finish.png" alt-text="Screenshot showing the an Azure Container App configured for continuous deployment with GitHub Actions." lightbox="media/tutorial-container-apps/azure-portal-continuous-deployment-configuration-finish.png":::
:::column-end:::

:::row-end:::

Azure CLI commands can be run in the Azure Cloud Shell or on a workstation with the Azure CLI installed.

:::row::: :::column span="1"::: Step 1. Create a service principal with the az ad sp create-for-rbac command.

    ```bash        
    export MSYS_NO_PATHCONV=1
    az ad sp create-for-rbac \
    --name <app-name> \
    --role Contributor \
    --scopes "/subscriptions/<subscription-ID>/resourceGroups/<resource-group-name>"
    ```

    Where: 
    * *\<app-name>* is an optional display name for the service principal. If you leave off the `--name` option, a GUID is generated as the display name.
    * *\<subscription-ID>* is the GUID that uniquely identifies your subscription in Azure.
    * *\<resource-group-name>* is the name of a resource group that contains the Azure Container Registry. Role-based access control (RBAC) is on the resource group level.

    Save the output of this command for the next step, in  particular, the client ID and client secret.

:::column-end:::

:::row-end::: :::row::: :::column span="1"::: Step 2. Configure GitHub Actions with az containerapp github-action add command.

    ```bash
    az containerapp github-action add \
    --resource-group <resource-group-name> \
    --name python-container-app \
    --repo-url https://github.com/userid/repo \
    --branch main \
    --registry-url <registry-name>.azurecr.io \
    --service-principal-client-id <client-id> \
    --service-principal-tenant-id <tenant-id> \
    --service-principal-client-secret <client-secret> \
    --login-with-github
    ```

    Where:
    * *\<resource-group-name>* is the name of the resource group.If you are following this tutorial, it is "pythoncontainer-rg".
    * *\<registry-name>* must be unique within Azure, and contain 5-50 alphanumeric characters.
    * *\<client-id>* is a value from the previous `az ad sp` command. The ID is a GUID of the form 00000000-0000-0000-0000-00000000.
    * *\<tenant-id>* is a value from the previous `az ad sp` command. The ID is a GUID of the form 00000000-0000-0000-0000-00000000.
    * *\<client-secret>* is a value from the previous `az ad sp` command.

:::column-end:::

:::row-end:::


In the configuration of continuous deployment, a service principal is used to enable GitHub Actions to access and modify Azure resources. Access to resources is restricted by the roles assigned to the service principal. The service principal was assigned the built-in Contributor role on the resource group containing the container app.

If you followed the steps for the portal, the service principal was created automatically for you. If you followed the steps for the Azure CLI, you explicitly created the service principal first before configuring continuous deployment.

Redeploy web app with GitHub Actions

In this section, you'll make a small change to your forked copy of the sample repository and confirm that the change is automatically deployed to the web site.

If you haven't already, make a fork of the sample repository (Django or Flask). You can make your code change directly in GitHub or in your development environment from a command line with Git.

:::row::: :::column span="2"::: Step 1. Go to your fork of the sample repository and start in the main branch. :::column-end::: :::column::: :::image type="content" source="media/tutorial-container-apps/github-view-repo.png" alt-text="Screenshot showing a fork of the sample repo and starting in the main branch." lightbox="media/tutorial-container-apps/github-view-repo.png"::: :::column-end::: :::row-end::: :::row::: :::column span="2"::: Step 2. Make a change.

    * Go to the  */templates/base.html* file.
    * Select **Edit** and change the phrase "Azure Restaurant Review" to "Azure Restaurant Review - Redeployed".

:::column-end:::
:::column:::
    :::image type="content" source="media/tutorial-container-apps/github-edit-file.png" alt-text="Screenshot showing how to make a change in a template file in the fork of the sample repo." lightbox="media/tutorial-container-apps/github-edit-file.png":::
:::column-end:::

:::row-end::: :::row::: :::column span="2"::: Step 3. Commit the change directly to the main branch.

    * On the bottom of the page you editing, select the **Commit** button.
    * The commit kicks off the GitHub Actions workflow.

:::column-end:::
:::column:::
    :::image type="content" source="media/tutorial-container-apps/github-commit-change.png" alt-text="Screenshot showing how to commit a change in a template file in the fork of the sample repo." lightbox="media/tutorial-container-apps/github-commit-change.png":::
:::column-end:::

:::row-end:::

Step 1. Start in main.

git checkout main
git pull

If you haven't already, use git clone to pull your forked repository to your development environment and change directory to the repository.

Step 2. Make a change.

Go to the ./templates/base.html file and change the phrase "Azure Restaurant Review" to "Azure Restaurant Review - Redeployed".

Step 3. Commit and push the change to GitHub.

git commit -a -m "Redeploy with title change."
git push

The first time using git, you may need to set global variables "user.name" and "user.email". For more information, see the help for git-config.

The push of changes to the main branch kicks off the GitHub Actions workflow.


Note

We showed making a change directly in the main branch. In typical software workflows, you'll make a change in a branch other than main and then create a pull request (PR) to merge those change into main. The PR will also kick off the workflow.

GitHub Actions workflow

Viewing workflow history

You can view GitHub Actions workflow history in GitHub or using GitHub CLI commands.

:::row::: :::column span="2"::: Step 1. Go to your fork of the sample repository and open the Actions tab. :::column-end::: :::column::: :::image type="content" source="media/tutorial-container-apps/github-check-action.png" alt-text="Screenshot showing how to view GitHub Actions for a repo and look at workflows." lightbox="media/tutorial-container-apps/github-check-action.png"::: :::column-end::: :::row-end:::

Step 1. Get a summary of your workflow.

gh workflow view

This command prompts you to select a workflow and then gives an overview of recent runs of that workflow. The first time using gh you may be prompted to authentication. Follow the GitHub CLI prompts to authenticate.

Step 2. Go to GitHub for details of run of workflow.

gh workflow view --web

Workflow secrets

In the .github/workflows/<workflow-name>.yml workflow file that was added to the repo, you'll see placeholders for credentials that are needed for the build and container app update jobs of the workflow. The credential information is stored encrypted in the repository Settings under Security/Actions.

:::image type="content" source="media/tutorial-container-apps/github-repo-action-secrets.png" alt-text="Screenshot showing how to see where GitHub Actions secrets are stored in GitHub." lightbox="media/tutorial-container-apps/github-repo-action-secrets.png":::

If credential information changes, you can update it here. For example, if the Azure Container Registry passwords are regenerated, you'll need to update the REGISTRY_PASSWORD value. For more information, see Encrypted secrets in the GitHub documentation.

OAuth authorized apps

When you set up continuous deployment, you authorize Azure Container Apps as an authorized OAuth App for your GitHub account. Container Apps uses the authorized access to create a GitHub Actions YML file in .github/workflows/<workflow-name>.yml when you set up continuous deployment. You can see your authorized apps and revoke permissions under Integrations/Applications of your account.

:::image type="content" source="media/tutorial-container-apps/github-authorized-oauth-apps.png" alt-text="Screenshot showing how to see the authorized apps for a user in GitHub." lightbox="media/tutorial-container-apps/github-authorized-oauth-apps.png":::

Troubleshooting tips

Errors setting up a service principal with the Azure CLI az ad sp create-for-rba command.

  • You receive an error containing "InvalidSchema: No connection adapters were found".

  • You receive an error containing "More than one application have the same display name".

    • This error indicates the name is already taken for the service principal. Choose another name or leave off the --name argument and a GUID will be automatically generated as a display name.

GitHub Actions workflow failed.

  • To check a workflow's status, go to the Actions tab of the repo.
  • If there's a failed workflow, drill into its workflow file. There should be two jobs "build" and "deploy". For a failed job, look at the output of the job's tasks to look for problems.
  • If you see an error message with "TLS handshake timeout", run the workflow manually by selecting Trigger auto deployment under the Actions tab of the repo to see if timeout is a temporary issue.
  • If you set up continuous deployment for the container app as shown in this tutorial, the workflow file (.github/workflows/<workflow-name>.yml) is created automatically for you. You shouldn't need to modify this file for this tutorial. If you did, revert your changes and try the workflow.

Website doesn't show changes you merged in the main branch.

  • In GitHub: check that the GitHub Actions workflow ran and that you checked the change into the branch that triggers the workflow.
  • In Azure portal: check the Azure Container Registry to see if a new container image was created with a timestamp after your change to the branch.
  • In Azure portal: check the logs of container app. If there's a programming error, you'll see it here.
    • Go to the Container App | Revision Management | <active container> | Revision details | Console logs
    • Choose the order of the columns to show "Time Generated", "Stream_s", and "Log_s". Sort the logs by most-recent first and look for Python stderr and stdout messages in the "Stream_s" column. Python 'print' output will be stdout messages.

What happens when I disconnect continuous deployment?

  • Stopping continuous deployment means disconnecting your container app from your repo. To disconnect:

  • After disconnecting, in your GitHub repo:

    • The .github/workflows/<workflow-name>.yml file is removed from your repo.
    • Secret keys aren't removed.
    • Azure Container Apps remains as an authorized OAuth App for your GitHub account.
  • After disconnecting, in Azure:

    • The container is left with last deployed container. You can reconnect the container app with the Azure Container Registry, so that new container revisions pick up the latest image.
    • Service principals created and used for continuous deployment aren't deleted.

Next steps

If you are done with the tutorial and don't want to incur costs, remove the resources used. Removing a resource group removes all resources in the group and is the fastest way to remove resources. For an example on how to remove resource groups, see Containerize tutorial cleanup.

If you plan on building on this tutorial, here are some next steps you can take.