In my previous blog I've showed you how to build an Azure deployable package for Ghost blog. It's now time to deploy that thing.
Goal
The goal of this build pipeline is to create an automatic release pipeline that will do the following:
- Deploy the files to our App Service
dev
slot - Warm it up
- Validate we got back an
Http 200
- Wait for manual approval (so we can do a manual sanity check)
When approved
- Swap the
dev
slot with production - Validate we still got
Http 200
on the production url
Create the Release pipeline
From Azure DevOps, create a new Release pipeline and make sure to select empty job
Add artifact
To link the previously build artifact package:
- Click on
Add artifact
- Select
Build
as source type - Select the build pipeline we just created
- Change the alias to
drop
- Click
Add
Stages
Next step is to create the stages, in our case: dev
and prod
. Start by creating these 2 stages empty, simply fill up their names and make sure they are linked together properly. You should have a line starting from the the artifacts box to dev
and one from dev
to prod
. This means that if the previous step is successful, the pipeline will continue the deployment automatically, which is exactly what we want.
Variables
Before we create all the deployment tasks, let's start with the variables we going to need. This will save us some typing and it will also make our pipeline easier to understand and maintain over time.
- Click on
Variables
on the top navigation bar - Create
devSlotName
,devSlotUrl
andprodSlotUrl
variables with your specific values - Make sure to set the scope of those variables
Dev tasks
Alright, time to configure actual work. On the dev
stage, create those tasks.
Stop Azure App Service
Funny things tend to happen when you try to change files on a server while another process is using them. Since I don't want to deal with this kind of situation, I always start by stopping completely my App Service. That way, I can avoid a whole aray of problems.
Be very careful though to only stop your
dev
slot and not theprod
slot
Task type: Azure App Service manage
variables:
devSlotName: 'dev'
steps:
- task: AzureAppServiceManage@0
displayName: 'Stop Azure App Service Dev Slot'
inputs:
azureSubscription: 'migblog-as-ghostblog - Azure'
Action: 'Stop Azure App Service'
WebAppName: 'migblog-as-ghostblog'
SpecifySlotOrASE: true
ResourceGroupName: migblog
Slot: '$(devSlotName)'
Screenshot
Azure App Service deploy
This task deploys the actual package to the dev
slot and start the Node.js server that runs Ghost blog.
Task type: Azure App Service deploy
variables:
devSlotName: 'dev'
steps:
- task: AzureRmWebAppDeployment@4
displayName: 'Deploy Azure App Service to Dev slot'
inputs:
azureSubscription: 'migblog-as-ghostblog - Azure'
WebAppName: 'migblog-as-ghostblog'
deployToSlotOrASE: true
ResourceGroupName: migblog
SlotName: '$(devSlotName)'
packageForLinux: '$(System.DefaultWorkingDirectory)\**\*.zip'
ScriptType: 'Inline Script'
InlineScript: 'call npm install --only=prod --ignore-scripts'
WebConfigParameters: '-Handler iisnode -NodeStartFile server.js -appType node'
enableCustomDeployment: true
ExcludeFilesFromAppDataFlag: false
Screenshot
Start Azure App Service
Start the Azure App Service on the dev
slot
Task type: Azure App Service manage
variables:
devSlotName: 'dev'
steps:
- task: AzureAppServiceManage@0
displayName: 'Start Azure App Service Dev slot'
inputs:
azureSubscription: 'migblog-as-ghostblog - Azure'
Action: 'Start Azure App Service'
WebAppName: 'migblog-as-ghostblog'
SpecifySlotOrASE: true
ResourceGroupName: migblog
Slot: '$(devSlotName)'
Screenshot
Warm up slot
In order to avoid long loading time for the first clients hitting our blog, let's warm up the dev
slot by sending a few web requests to it. This will force the web server to warm up and cache required files. In doing so, we'll also validate that the site is healthy after the blog update.
Task type: PowerShell
variables:
devSlotUrl: 'https://dev.miguelbernard.com'
steps:
- powershell: |
$statusCode = 0
While($StatusCode -ne 200)
{
$res = wget $(devSlotUrl)
$statusCode = $res.StatusCode
Start-Sleep -Seconds 10
}
errorActionPreference: continue
displayName: 'Warm up slot'
timeoutInMinutes: 5
Screenshot
Recap of Dev tasks
The tasks of your dev stage should look like this
Prod tasks
At this point, we should be able to run this pipeline and validate that our dev
slot is working properly. If everything is fine, we can now swap it with the prod
slot.
Swap dev and prod
Task type: Azure App Service manage
variables:
devSlotName: 'dev'
steps:
- task: AzureAppServiceManage@0
displayName: 'Swap Slots: migblog-as-ghostblog'
inputs:
azureSubscription: 'migblog-as-ghostblog - Azure'
WebAppName: 'migblog-as-ghostblog'
ResourceGroupName: migblog
SourceSlot: '$(devSlotName)'
Screenshot
Validation
I'm a bit paranoid, so my last step is always to perform an extra validation directly in prod. That way if something goes wrong, I'll get a notification from Azure DevOps and I'll be able to swap back the environments.
Task type: PowerShell
variables:
prodSlotUrl: 'https://blog.miguelbernard.com'
steps:
- powershell: |
$statusCode = 0
While($StatusCode -ne 200)
{
$res = wget $(prodSlotUrl)
$statusCode = $res.StatusCode
Start-Sleep -Seconds 10
}
errorActionPreference: continue
displayName: 'Make sure site is up and running'
Screenshot
Recap of Prod tasks
The tasks of your prod stage should look like this
Pre-Approval
It's important to add a manual pre-approbation before running the production tasks. Otherwise, we won't have time to validate the dev environment before it's swapped with the prod one.
- Click on the little guy icon next to the
prod
stage. This is the Pre-Deployment configuration of that stage - Enable
Pre-Deployment approvals
- Add yourself as an approver
Automatic deployment
Wouldn't it be nice to kick start a deployment as soon as a new package is built? Easy peasy.
- Click on the little lightning bolt right by the
drop
artifact - Enable
Continous deployment trigger
- Voilà!
Summary
You're all done! You now have a deployment pipeline that will automatically kick-off when a new package is available. It will prepare the dev
environment and you'll receive a notification when it's ready to be validated and pushed to prod
. All of this achieved with zero down time on your precious blog.