Published on

Zero Downtime Deployments for Microservices in Azure: A Step-by-Step Guide

Authors
  • avatar
    Name
    Dinh Nguyen Truong
    Twitter

In today’s world, ensuring the availability of your application is so important. It helps your customer work with your product without any interruptions.

This challenge becomes more complex as applications grow, have many dependencies, or adopt microservices architecture. While major cloud providers like Azure and AWS guarantee high infrastructure availability, achieving 99.99% uptime for your application is still a wonderfully hard problem.

Problem with Traditional Deployments

Traditional deployment methods often lead to downtime, disrupting the user experience. This typically occurs due to:

  • Service Restarts: Deploying new versions often requires restarting services.

  • Configuration Changes: Applying new configurations or environment variables can trigger service restarts.

Luckily, Azure app service provides a reliable method to handle these problems.

Introduce Azure App Service Deployment Slots:

Azure App Service Deployment Slots is a powerful feature that allows you to create separate hosting environments for your application within the same App Service. Each slot is essentially a live app with its own hostname, URL, and configuration

How Deployment Slots Work:

  • Creation: You can create multiple deployment slots for your App Service, each acting as a separate instance of your application.

  • Configuration: Each slot can have its own configuration settings.

  • Deployment: You can deploy your application to any slot without affecting the production environment.

  • Swapping: You can swap the content and configuration of two slots.

How can you use it:

  • Validate Changes in Staging: You always need a staging environment where you can test your app the last time before going live. The deployment slot is an ideal place to do that. So, deploy your updates to a deployment slot first, test it and validate your changes.

  • Slot Swapping: When all changes are validated, you can swap the staging slot with the production slot. This swapping process happens instantaneously. I use this in many of my client apps, slot swapping always impresses me with how fast and reliable it is.

Implement Zero Downtime Strategy

Our strategy involves a two-step process:

  • Deploy all microservices to deployment slots using individual GitHub Actions.

  • Swap all deployment slots with production slots using another GitHub Action.

Deploy each app independently

And swap all at once

Does this method ensure 100% uptime for your application? Of course not. There are potential issues:

  1. Timing differences: There’s a chance that not all slot swap processes finish simultaneously.

  2. API version conflicts: If your application doesn’t handle API versions well, conflicts may arise when all app services swap their slots.

However, this approach will significantly reduce downtime compared to traditional deployment methods.

Implementing the Deployment Process

Setting Up Azure App Service

First, create an App Service for each of your microservices and configure a staging slot for each:

  • In the Azure Portal, create a new App Service for each microservice.

  • For each App Service, go to “Deployment slots” and add a new slot named “staging”.

GitHub Actions for Individual Microservice Deployments

For each microservice, create a GitHub Actions workflow file (e.g., .github/workflows/deploy-service-a.yml):

name: Deploy Service A to Staging

on:
  push:
    tags:
      - 'v*.*.*-staging.*'
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: Set up Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '20'

    - name: Install dependencies
      run: npm ci
      working-directory: apps/service-a

    - name: Build
      run: npm run build
      working-directory: apps/service-a

    - name: Deploy to Azure Web App
      uses: azure/webapps-deploy@v2
      with:
        app-name: 'service-a'
        slot-name: 'staging'
        publish-profile: ${{ secrets.azureWebAppPublishProfile }}
        package: apps/service-a

This workflow is triggered when a tag matches the pattern v*.*.*-staging.* is pushed.

Then each microservice is built and deployed to staging slot in Azure App Service.

GitHub Action for Slot Swapping

Create a separate workflow file for slot swapping (e.g., .github/workflows/swap-slots.yml):

name: Swap Staging to Production

on:
  push:
    tags:
      - 'v*.*.*'
jobs:
  swap-slots:
    runs-on: ubuntu-latest
    steps:
    - name: Azure Login
      uses: azure/login@v2
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: Swap Slots for Core Service
      uses: azure/cli@v2
      with:
        azcliversion: latest
        inlineScript: |
          az webapp deployment slot swap --name core-service --resource-group resource-group-name --slot staging

    - name: Swap Slots for Independent Services
      uses: azure/cli@v2
      with:
        azcliversion: latest
        inlineScript: |
          az webapp deployment slot swap --name service-a --resource-group resource-group-name --slot staging
          az webapp deployment slot swap --name service-b --resource-group resource-group-name --slot staging
          az webapp deployment slot swap --name service-c --resource-group resource-group-name --slot staging

Slot Swapping:

For each service, the workflow uses the Azure CLI to perform a slot swap. The az webapp deployment slot swap command swaps the 'staging' slot with the production slot for each service.

Coordination Strategies:

Sequential Swapping for Dependent Services

  • If you have services that depend on each other, it’s better to swap them in the correct order.

  • In the example above, we first swap the ‘Core Service’, assuming it’s a service that others might depend on.

Concurrent Swapping for Independent Services:

  • For services that are completely independent of each other, you can perform slot swaps concurrently.

  • In the example, we swap multiple independent services (service-a, service-b, service-c) in a single Azure CLI step.

Conclusion

Achieving zero downtime for your application is always hard, but it’s an important part of maintaining seamless user experiences. I hope you find this article helpful. Happy coding.