DEV Community

Cover image for Automated deployment slots in Azure with GitHub Actions: Testing pull requests in live environments
Florian Lenz
Florian Lenz

Posted on

Automated deployment slots in Azure with GitHub Actions: Testing pull requests in live environments

Continuous Integration and Continuous Deployment (CI/CD) are already standard in many companies. However, development teams are constantly looking for ways to work more efficiently and ensure that code is tested in a real-world environment before it goes live. The ability to test pull requests (PRs) directly in a ‘live’-like environment can significantly improve code quality and detect bugs early.

Azure Deployment Slots offer an elegant solution to this by creating isolated test environments. In combination with GitHub Actions, you can automatically deploy and test PRs in these slots before they are merged into the ‘main’ branch. In this article, I'll show you how to set up PR-specific deployment slots and use GitHub Actions for this automation.

What are Azure Deployment Slots?

Azure App Service Deployment Slots are separate deployment environments within an App Service instance. They allow you to host multiple versions of your application simultaneously. Main advantages:

  • Zero-downtime deployments: New versions can be deployed and tested in one slot before going live
  • Easy rollback: In the event of problems, you can simply switch back to the previous slot.
  • Isolated environments: Each slot has its own configurations and connection strings.

GitHub Actions and Pull Requests

GitHub Actions is a tool for automating software workflows directly in your GitHub repository. It allows you to create CI/CD pipelines that can react to various events such as pushes, pull requests or time-based triggers. In combination with Azure, you can automate your entire development and deployment process

The idea: Branch-specific deployment slots

Imagine that every pull request automatically creates its own deployment slot. This enables:

  • Live-like testing: Test changes in an environment that is close to production.
  • Early detection of errors: Testing in the deployment slot allows problems to be detected before they reach the main branch.
  • Automation: Slots are automatically created and removed through integration with GitHub Actions.

Step-by-step guide

1. Set up workflow for pull requests

To automatically create and manage deployment slots for each pull request, we'll set up a new GitHub Actions workflow that responds to pull request events.

Folder structure: Create a .github/workflows folder in the root directory of your repository if it doesn't already exist.
Create workflow file: Create a new file called pull_request_deployment.yml in this folder.
Configure workflow: Use the following YAML code that extends your existing pipeline to manage deployment slots for PRs.

name: PR Deployment CI/CD

on:
  pull_request:
    types: [opened, synchronize, reopened, closed]

jobs:
  build:
    if: github.event.action != 'closed'
    runs-on: windows-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up .NET Core
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.x'

      - name: Build with dotnet
        run: dotnet build src/WebApplication/WebApplication.csproj --configuration Release

      - name: dotnet publish
        run: dotnet publish src/WebApplication/WebApplication.csproj -c Release -o ./deploy

      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v4
        with:
          name: .net-app
          path: ./deploy

  deploy:
    if: github.event.action != 'closed'
    runs-on: windows-latest
    needs: build
    environment:
      name: 'PR-slot-deployment'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
    permissions:
      id-token: write # This is required for requesting the JWT

    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v4
        with:
          name: .net-app

      - name: Login to Azure
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Create Deployment Slot
        run: |
          $SLOT_NAME="pr-${{ github.event.number }}"
          az webapp deployment slot create --name prdeploymentwebapp --resource-group prdeployment --slot $SLOT_NAME

      - name: Deploy to Azure Web App
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v3
        with:
          app-name: 'prdeploymentwebapp'
          slot-name: 'pr-${{ github.event.number }}'
          package: .

  cleanup:
    if: github.event.action == 'closed'
    runs-on: windows-latest
    environment:
      name: 'PR-slot-deployment'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
    permissions:
      id-token: write # This is required for requesting the JWT

    steps:
      - name: Login to Azure
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Delete Deployment Slot
        run: |
          $SLOT_NAME="pr-${{ github.event.number }}"
          az webapp deployment slot delete --name prdeploymentwebapp --resource-group prdeployment --slot $SLOT_NAME
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Trigger: The workflow is triggered by pull request events such as opened, synchronise, reopened and closed.
  • Build Job: Builds and publishes the application, uploads the artefact for the deploy job.
  • Deploy Job: Creates a deployment slot with the name pr-(PR number), deploys the application to this slot and provides the URL of the live environment.
  • Cleanup Job: Is only triggered when the pull request is closed (merged or rejected). Deletes the corresponding deployment slot.

2. Create pull request

The pipeline will start automatically as soon as the pull request has been created.

Automated provision of a PR with GitHub Actions

3. perform tests in the ‘live’ environment

After the application has been deployed to the deployment slot, you can perform both manual and automated tests in this environment. The URL of the slot is usually:https://prdeploymentwebapp-pr-12.azurewebsites.net

Deployment slots Overview by PR Deployment

Manual tests:
Open the above URL in your browser and perform the necessary tests.

4. Clean up the deployment slots

After closing a pull request, the slot is automatically removed. This ensures that no legacy data remains available for an unnecessarily long time.

Cleanup process in the GitHub Actions

Best practices and pitfalls

Number of deployment slots

  • Cost control: Each slot consumes resources. Limit the number of concurrent slots, especially in large projects with many parallel pull requests.
  • Clean up: Make sure that temporary slots are deleted after use to avoid unnecessary resources.

Dealing with many pull requests

  • Limits in Azure: Azure has limits on the number of slots per App Service Plan (up to 20 slots by default). Plan accordingly to avoid bottlenecks.
  • Scaling: Resources could become scarce if the PR volume is high. Consider scaling the App Service Plan or optimising automated slot deletions.

Workflow optimisation

  • Parallel jobs: Use the parallelism of GitHub Actions to speed up workflows.
  • Fast deployments: Minimise the number of steps and optimise build processes to reduce deployment times.
  • Automated testing: automated deployment of the application also allows E2E testing to be performed using Cypress, for example.

Rollback strategies

  • Automatic rollback: implement mechanisms to automatically roll back to the previous slot in the event of failed deployments.
  • Monitoring and alerts: monitor deployments and set up alerts to respond quickly to issues.

Conclusion

With these customisations to your GitHub Actions Pipeline, you can effectively use Azure Deployment Slots to test pull requests in isolated, live-like environments. This increases the quality of your code and significantly reduces the risk of errors in the production environment.

Summary of customisations:

  • PR-specific slots: Each pull request gets its own deployment slot, which is automatically removed once the PR is complete.
  • Automated slot management: creation and deletion of slots automated by GitHub Actions.

These measures help to streamline the deployment process, increase efficiency and improve the reliability of your applications.‍

Resources:

Top comments (0)