Lesson 5.3: Create Continuous Delivery Pipeline for Blazor app

Now that we have our game building automatically in Azure Pipelines and an Azure Storage account configured to host our application, we need to build an automated pipeline to deploy new builds to the desired storage account. We will do this by using the Releases pipeline in Azure DevOps.

Similar to Continuous Integration (which we covered Lesson 1.9), we will follow the concept of Continuous Delivery (CD), an extension to continuous integration to make sure that we can release new changes to our customers quickly in a sustainable way. This means that on top of having automated our testing, we also have automated our release process, and we can deploy our application at any point in time at the click of a button.

In theory, with continuous delivery, we can decide to release daily, weekly, fortnightly, or whatever suits our game’s needs. However, if we truly want to get the benefits of continuous delivery, we should deploy to production as early as possible to make sure that we release small batches that are easy to troubleshoot in case of a problem.

Our CD pipeline will be very simple. We will take the latest good build (which builds successfully and all tests pass), and copy the wwwroot folder from the build folder to our Azure Storage $web container (which we configured in lesson 5.2).

Update Blazor Build Pipeline

Currently our Azure DevOps build zips the build output for all of our projects and copies them to the Drop folder, so that it is accessible to the release pipeline. However, we actually need the build output unzipped to copy it our Azure Storage container. So we are going to update the /build/azure-pipelines.yml file in our source tree.

# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml

trigger:
- '*'

# all of the variables used by this pipeline and dependent templates.
variables:
  buildConfiguration: 'Release'
  dotnetSdkVersion: '3.1.200'
  releaseBranchName: 'main'
  localPackageFeed: 'd20Tek'

# define the image to use for the whole pipeline... can be overridden by specific jobs.
pool:
    vmImage: 'ubuntu-16.04'

stages:
# Build
- stage: 'Build'
  displayName: 'Build app'
  jobs:
  - job: 'Build'
    displayName: 'Build job'

    steps:
    # ensure the right version of .NET Core is installed -- defaults to 3.1.
    - task: UseDotNet@2
      displayName: 'Use .NET Core SDK $(dotnetSdkVersion)'
      inputs:
        version: '$(dotnetSdkVersion)'

    # restore NuGet packages used by the projects.
    - task: DotNetCoreCLI@2
      displayName: 'Restore project dependencies'
      inputs:
        command: 'restore'
        projects: '**/*.csproj'
        feedsToUse: 'select'
        vstsFeed: '$(localPackageFeed)'

    # build all projects in this repo... defined by folders with .csproj files.
    - task: DotNetCoreCLI@2
      displayName: 'Build the project - $(buildConfiguration)'
      inputs:
        command: 'build'
        arguments: '--no-restore --configuration $(buildConfiguration)'
        projects: '**/*.csproj'
        versioningScheme: byBuildNumber
    
    # publish all artifacts from the builds.
    - task: DotNetCoreCLI@2
      displayName: 'Publish the project - $(buildConfiguration)'
      inputs:
        command: 'publish'
        projects: '**/*.csproj'
        publishWebProjects: false
        arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
        zipAfterPublish: true

    # runs tests for all projects in this repo... defined by folders with .Test.csproj files.
    - task: DotNetCoreCLI@2
      displayName: 'Run unit tests - $(buildConfiguration)'
      inputs:
        command: 'test'
        arguments: '--no-build --no-restore --configuration $(buildConfiguration)'
        # publish the test pass/fail results to the pipeline, so that they are available in the Azure DevOps pipeline dashboard.
        publishTestResults: true
        projects: '**/*.Tests.csproj'

    # publish the artifacts created by this build in the drop location.
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact: drop'
      condition: succeeded()

We just updated the zipAfterPublish to set in the Publish command to false, so that our build output doesn’t get zipped up on its way to the Drop folder.

Setup CD Pipeline

With Azure Pipelines, we are going to create a Release pipeline to manage when releases get deployed to Azure. In Azure DevOps, go to the Pipelines tab and click the releases button.

Fig 1 – Release Pipeline Empty

Click the ‘New Pipeline’ button.

Fig 2 – Release Pipeline Template

Click the ‘Empty Job’ link at the top of the flyout.

Fig 3 – Release Pipeline Rename Stage

Rename the default stage to ‘Deploy to Azure’ and close this flyout.

Fig 4 – Empty Release Pipeline

Click the ‘Add an artifact’ box.

Fig 5 – Add an Artifact

Select a build in our current project. Select the build pipeline to use: ‘simple-rpg-game-ci’. Then it defaults to the latest version. With all of this data selected, press the Add button.

Fig 6 – Artifact Added

We should see the artifact added to our pipeline. Now we click on the ‘Tasks’ menu item and select ‘Deploy to Azure’.

Fig 7 – Agent Job Settings

That will open the tasks for this pipeline, so far it should be empty. By selecting the ‘Agent job’ box, we can see all of the properties of our deployment agent. We’re not going to change any of the defaults, but it’s good to familiarize ourselves with the options here.

Then click the ‘+’ sign in the Agent job title bar to Add New Task.

Fig 8 – Add New Task to Job

Search for the ‘Azure file copy’ release task. This task is used to copy the files from our build output to the Azure Storage container that we created in lesson 5.2. Click the Add button on this task. This will open the following empty task.

Fig 9 – Empty Azure File Copy Task

Fill in the required information for this form:

  • Display Name: friendly name for this task.
  • Source: full path to the build source folder. The path goes to the drop and release folders and all the way down to the wwwroot folder (this is where all of our content and assemblies are placed during the build).
  • Azure Subscription: brings up a UI to connect to Azure using our credentials, then saves it for this release job.
  • Destination Type: for our use it’s Azure Blob.
  • Storage Account: this is the storage account we created previously – simplerpgv1.
  • Container Name: remember the container we created was named $web.
  • The remaining configuration entries are just the defaults.
Fig 10 – Azure File Copy Task Completed

Then click the Save button in the top bar. And let’s go back to the Release pipelines page by clicking the Releases link in the navigation bar.

Fig 11 – Releases with New Pipeline

Run First Release

With the release pipeline now in place, we can create and run our first release. This will get our initial version of the game to our public endpoint. To do this, click the ‘Create Release’ button to start a release of our current build.

Fig 12 – Create New Release

Just click the Create button… no changes are required for this flyout at this time. This will launch the release job and attempt to deploy the latest simple-rpg-game-ci build to our Azure location. Allow it to run until you see it complete.

As you can see the release is named ‘Release-1’, and new ones will follow the same naming pattern.

Fig 13: First Release Succeeds

With the release complete, we now have our game deployed in our Azure storage account. It is ready for users to access it by navigating to the https://bit.ly/simple-rpg-v1 URL.

Note: we will be running through the steps in this section every time we want to deploy a new build into our production environment, so get familiar with the deployment steps.

Fig 14 – Simple RPG Game Running in Azure

Notice the URL at the top of the browser is pointing at our public Azure endpoint. Our game is now running from that Azure location and accessible to all of our players. We are live on the web!!!

Now, we can make changes to our game code, check it into our DevOps Git repository, automatically start a continuous integration build, and then start another release to get it live in Azure. We have come a long way from creating our new project and have automated our whole pipeline. We can use this CI/CD infrastructure in all of our apps, services, and components.

Note: we can add triggers to automatically deploy every build to our Azure container as well, but rather than doing it completely automatic, we are going to require someone to create a new release. There’s a lot of compelling arguments about whether automatic deployment into productions is a good idea or not. But later, if we want to automate this final step as well, we can easily do it with Azure DevOps.

With our Continuous Delivery pipeline in place, we’re hosting our Blazor game in Azure. That’s very exciting. We will continue our tour of Azure services by looking at Azure Functions, and how we can use it to build web services for our game data.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s