Previously we setup a basic pipeline that tests and builds our project, but before we can deploy it we need someplace to put it, first lets take a look at our YAML file.
trigger:
- dev
- prod
pool:
vmImage: 'windows-latest'
variables:
buildConfiguration: 'Release'
steps:
# Execute xunit tests
- task: DotNetCoreCLI@2
displayName: 'xUnit unit tests'
inputs:
command: test
projects: '**/*tests/*.csproj'
arguments: '--configuration $(buildConfiguration)'
# Build dotnet core project
- task: DotNetCoreCLI@2
displayName: 'dotnet build Tic tac toe : $(buildConfiguration)'
inputs:
command: build
projects: '**/*source/*.csproj'
exactly what we had a couple of days ago, so today lets build the infrastructure to deploy our project to, now there are many various ways to deploy infrastructure, personally I go with PowerShell, because that's the way I have done it since 2010 and I don't see a to change now, that and I just don't have the time to pick up the newest flavor of the week.
so lets add a infrastructure powershell file to the root of our project.
with that done, lets start by creating a resource group in our poweshell script
Param (
[Parameter()][String]$location,
[Parameter()][String]$name,
[Parameter()][String]$env)
$name = "$name-$env"
#sub functions
function PrintHeader{
$doubleStar = "**"
$line = "*****************************************************************************************"
$msg = "Creating Azure environment for Tic Tac Toe"
write-host $line
write-host $doubleStar -NoNewline
write-host $doubleStar.padLeft($line.length - 2)
write-host $doubleStar -NoNewline
write-host $doubleStar.padLeft($line.length - 2)
write-host $doubleStar.PadRight(($line.Length - $msg.Length)/2) -NoNewline
write-host $msg -NoNewline
write-host $doubleStar.padLeft(($line.Length - $msg.Length)/2)
write-host $doubleStar -NoNewline
write-host $doubleStar.padLeft($line.length - 2)
write-host $doubleStar -NoNewline
write-host $doubleStar.padLeft($line.length - 2)
write-host $line
}
#create resource group
function CreateResourceGroup {
Param(
[Parameter(Mandatory=$true)][String]$name,
[Parameter(Mandatory=$true)][String]$location)
$rgName = "rg-$name"
Write-Host "Createing $rgName resource group in $location" -ForegroundColor Magenta
#check if resource group already exists
$resourceGroup = Get-AzResourceGroup -Name $rgName -ErrorAction SilentlyContinue
if($resourceGroup){
Write-host "Resource group already exists" -foregroundcolor yellow
return
}
#create resource group
try {
$resourceGroup = New-AzResourceGroup -Name $rgName -Location $location -Tag @{Type="Incubation"; Enviroments="ALL"}
Write-host "Resource group created" -foregroundcolor Green
return
}
catch {
#failed to create resource group
Write-error "Resource group NOT created" -ErrorAction Stop
}
}
Clear-Host
PrintHeader
# create resource group
CreateResourceGroup $name $location
the above powershell script outputs a nice message notifies us what the script does and then creates a resource group.
to execute this from our yml file edit the pipline and add an azure powershell task, doing it form the Devops GUI will make your life much easier.
once you select an Azure PowerShell task ensure that you select the correct azure subscription and make sure you authorize it.
you'll know that you authorized this connection correctly if you see the following
under the service connections section
# setup azure infrastructure
- task: AzurePowerShell@5
displayName: 'Create Azure infrastructure'
inputs:
azurePowerShellVersion: 'LatestVersion'
azureSubscription: 'Pavs Subscription(00000000-0000-0000-0000-000000000000)'
errorActionPreference: 'continue'
ScriptType: 'FilePath'
ScriptPath: '$(Build.SourcesDirectory)\infrastructure.ps1'
ScriptArguments: '-location switzerlandnorth -name tictactoe -env dev'
keep in mind that often times this process doesn't go smoothly, for example i had to log into my azure portal and get the subscription guid as well as the subscription name
now that we have our task set up copy it to your local yml file and push the changes, the first time you push you will see something along the lines of
just click the view button
and grant the permission, once this is done the job will start on its own and you wont have to do this again moving forward, now that our run is complete lets take a look at our azure environment, and sure enough we have a resource group named rg-tictactoe-dev.
which is great, but now lets add the creation of a service plan
# Create app service plan
function CreateAppServicePlan {
Param(
[Parameter(Mandatory=$true)] [String] $name,
[Parameter(Mandatory=$true)] [String] $location)
$rgName = "rg-$name"
$planName = "plan-$name"
Write-Host "Createing $planName ($location) app service plan in $rgName resource group" -ForegroundColor Magenta
#check if service plan already exists
$servicePlan = Get-AzAppServicePlan -ResourceGroupName $rgName -Name $planName -ErrorAction SilentlyContinue
if($servicePlan){
Write-host "App service already exists" -foregroundcolor yellow
return $servicePlan
}
#create service plan
try{
$servicePlan = New-AzAppServicePlan -ResourceGroupName $rgName -Name $planName -Location $location -Tier "Free" -NumberofWorkers 1 -WorkerSize "Small"
Write-host "App service plan Created" -foregroundcolor Green
return $servicePlan
}
catch{
Write-error "App service plan NOT created" -ErrorAction Stop
}
}
and an actual app service
# create app service
function CreateAppService {
Param(
[Parameter(Mandatory=$true)] [String] $name,
[Parameter(Mandatory=$true)] [String] $prefix,
[Parameter(Mandatory=$true)] [String] $location,
[Parameter(Mandatory=$true)] [Microsoft.Azure.Management.WebSites.Models.AppServicePlan] $servicePlan)
$rgName = "rg-$name"
$appName = "app-$prefix-$name"
Write-Host "Createing $appName web app in $rgName resource group" -ForegroundColor Magenta
#check if web app already exists
$webApp = Get-AzWebApp -ResourceGroupName $rgName -Name $appName -ErrorAction SilentlyContinue
if($webApp){
Write-host "Web app ""$appName"" already exists" -foregroundcolor yellow
return $webApp
}
#create web app
try{
$webApp = New-AzWebApp -ResourceGroupName $rgName -Name $appName -Location $location -AppServicePlan $servicePlan.Name
Write-host "App service ""$appName"" Created" -foregroundcolor Green
return $webApp
}
catch{
Write-error "App service NOT created" -ErrorAction Stop
}
}
with those complete make sure to actually call them
Clear-Host
PrintHeader
# create resource group
CreateResourceGroup $name $location
#create service plan
$servicePlan = CreateAppServicePlan $name $location
#create app service
CreateAppService $name "API" $location $servicePlan
And with our successful deployment we now have a place to deploy our project.
and next lets set up Continuous deliver portion of our DevOps pipeline
and for good measure our full PowerShell file
Param (
[Parameter()][String]$location,
[Parameter()][String]$name,
[Parameter()][String]$env)
$name = "$name-$env"
#sub functions
function PrintHeader{
$doubleStar = "**"
$line = "*****************************************************************************************"
$msg = "Creating Azure enviroment for Tic Tac Toe"
write-host $line
write-host $doubleStar -NoNewline
write-host $doubleStar.padLeft($line.length - 2)
write-host $doubleStar -NoNewline
write-host $doubleStar.padLeft($line.length - 2)
write-host $doubleStar.PadRight(($line.Length - $msg.Length)/2) -NoNewline
write-host $msg -NoNewline
write-host $doubleStar.padLeft(($line.Length - $msg.Length)/2)
write-host $doubleStar -NoNewline
write-host $doubleStar.padLeft($line.length - 2)
write-host $doubleStar -NoNewline
write-host $doubleStar.padLeft($line.length - 2)
write-host $line
}
#create resource group
function CreateResourceGroup {
Param(
[Parameter(Mandatory=$true)][String]$name,
[Parameter(Mandatory=$true)][String]$location)
$rgName = "rg-$name"
Write-Host "Createing $rgName resource group in $location" -ForegroundColor Magenta
#check if resource group already exists
$resourceGroup = Get-AzResourceGroup -Name $rgName -ErrorAction SilentlyContinue
if($resourceGroup){
Write-host "Resource group already exists" -foregroundcolor yellow
return
}
#create resource group
try {
$resourceGroup = New-AzResourceGroup -Name $rgName -Location $location -Tag @{Type="Incubation"; Enviroments="ALL"}
Write-host "Resource group created" -foregroundcolor Green
return
}
catch {
#failed to create resourcec group
Write-error "Resource group NOT created" -ErrorAction Stop
}
}
# Create app service plan
function CreateAppServicePlan {
Param(
[Parameter(Mandatory=$true)] [String] $name,
[Parameter(Mandatory=$true)] [String] $location)
$rgName = "rg-$name"
$planName = "plan-$name"
Write-Host "Createing $planName ($location) app service plan in $rgName resource group" -ForegroundColor Magenta
#check if service plan already exists
$servicePlan = Get-AzAppServicePlan -ResourceGroupName $rgName -Name $planName -ErrorAction SilentlyContinue
if($servicePlan){
Write-host "App service already exists" -foregroundcolor yellow
return $servicePlan
}
#create service plan
try{
$servicePlan = New-AzAppServicePlan -ResourceGroupName $rgName -Name $planName -Location $location -Tier "Free" -NumberofWorkers 1 -WorkerSize "Small"
Write-host "App service plan Created" -foregroundcolor Green
return $servicePlan
}
catch{
Write-error "App service plan NOT created" -ErrorAction Stop
}
}
# create app service
function CreateAppService {
Param(
[Parameter(Mandatory=$true)] [String] $name,
[Parameter(Mandatory=$true)] [String] $prefix,
[Parameter(Mandatory=$true)] [String] $location,
[Parameter(Mandatory=$true)] [Microsoft.Azure.Management.WebSites.Models.AppServicePlan] $servicePlan)
$rgName = "rg-$name"
$appName = "app-$prefix-$name"
Write-Host "Createing $appName web app in $rgName resource group" -ForegroundColor Magenta
#check if web app already exists
$webApp = Get-AzWebApp -ResourceGroupName $rgName -Name $appName -ErrorAction SilentlyContinue
if($webApp){
Write-host "Web app ""$appName"" already exists" -foregroundcolor yellow
return $webApp
}
#create web app
try{
$webApp = New-AzWebApp -ResourceGroupName $rgName -Name $appName -Location $location -AppServicePlan $servicePlan.Name
Write-host "App service ""$appName"" Created" -foregroundcolor Green
return $webApp
}
catch{
Write-error "App service NOT created" -ErrorAction Stop
}
}
Clear-Host
PrintHeader
# create resource group
CreateResourceGroup $name $location
#create service plan
$servicePlan = CreateAppServicePlan $name $location
#create app service
CreateAppService $name "API" $location $servicePlan