AUTOMATED RELEASE MANAGEMENT
WITH TEAMCITY & OCTOPUSDEPLOY
12.04.2023
CONTINOUS DELIVERY
/ 2
12.04.2023
Continuous Integration
/ 3
12.04.2023
Continuous Deployment
/ 4
12.04.2023
Continuous Delivery
/ 5
12.04.2023
It’s all about frequent releases
/ 6
John Allspaw: “Ops metametrics” http://slidesha.re/dsSZIr
It’s all about failing fast
12.04.2023
The deployment pipeline
/ 7
12.04.2023
Test coverage
/ 8
http://www.industrieit.com/blog/2012/02/a-practical-guide-to-extending-continuous-integration-to-continuous-delivery/http://jamescrisp.org/2011/05/30/automated-testing-and-the-test-pyramid/
12.04.2023
Blue-green deployment
/ 9
Jez Humble: “Continous Delivery” http://www.slideshare.net/jezhumble/continuous-delivery-5359386
12.04.2023
Blue-green deployment
/ 10
Jez Humble: “Continous Delivery” http://www.slideshare.net/jezhumble/continuous-delivery-5359386
12.04.2023
Blue-green deployment
/ 11
Jez Humble: “Continous Delivery” http://www.slideshare.net/jezhumble/continuous-delivery-5359386
12.04.2023
Blue-green deployment
/ 12
Jez Humble: “Continous Delivery” http://www.slideshare.net/jezhumble/continuous-delivery-5359386
12.04.2023
Canary releasing
/ 13
Jez Humble: “Four principles or Low-Risk Software releases” http://www.informit.com/articles/article.aspx?p=1833567
12.04.2023
The arguments
/ 14
12.04.2023
The arguments
/ 15
• Before: ~30 minutes• After: 4 minutes• 4 times per day• Time spent: 8 hours• Days until investment time paid:
12.04.2023 / 16
12.04.2023
DEPLOYING A WEBSITE
/ 17
12.04.2023
Basic asp.net mvc4 website
<hgroup class="title"> <h1>Welcome to ASP.NET Web API!</h1> <br /> <h2>
@WebApiApplication.Environment - @WebApiApplication.Version
</h2></hgroup>
/ 18
12.04.2023
Web.Development.config
<?xml version="1.0"?><configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <appSettings> <add key="Environment" value="Development“
xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/> </appSettings></configuration>
/ 19
12.04.2023
Creating the Octopus NuGet package
• Why NuGet?– Metadata– Lots of available tools– Feed-based– Developers know how to use them– Already used for other purposes (check out chocolatey.org)
• Does NOT use the default NuGet conventions– Octopus deploys the exact structure of the package
/ 20
12.04.2023
mvc4webapi.nuspec
<?xml version="1.0"?><package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>Itera.NDC2013.TCOD.Web</id> <title>ASP.NET MVC 4 Web Api demo site</title> <version>1.0.0</version> <authors>Kristoffer Rolf Deinoff</authors> <owners>Kristoffer Rolf Deinoff</owners> <licenseUrl>http://itera.no</licenseUrl> <projectUrl>http://itera.no</projectUrl> <requireLicenseAcceptance>false</requireLicenseAcceptance> <description>A sample project</description> <releaseNotes>First release</releaseNotes> </metadata></package>
/ 21
12.04.2023
Using OctoPack
/ 22
12.04.2023
Using TeamCity
/ 23
12.04.2023
Using NuGet.exe
nuget.exe pack $nuspecFileName-OutputDirectory $contentDir-Version $version
/ 24
12.04.2023
Configuring TeamCity
/ 25
12.04.2023
Configuring TeamCity – Commit build
/ 26
12.04.2023
Configuring TeamCity – VCS root
/ 27
12.04.2023
Configuring TeamCity – Patch AssemblyInfo
/ 28
12.04.2023
Configuring TeamCity - Compile
/ 29
12.04.2023
Configuring TeamCity – Commit tests
/ 30
12.04.2023
Configuring TeamCity – Trigger on check-in
/ 31
12.04.2023
Configuring TeamCity – Build artifacts
/ 32
12.04.2023
Configuring TeamCity – NuGet Server
/ 33
12.04.2023
Configuring TeamCity – NuGet Server
/ 34
12.04.2023
Configuring OctopusDeploy - Environments
/ 35
12.04.2023
Configuring OctopusDeploy – NuGet server
/ 36
12.04.2023
Configuring OctopusDeploy – Steps
/ 37
12.04.2023
Configuring OctopusDeploy – Publish website
/ 38
12.04.2023
Configuring OctopusDeploy – Publish website
/ 39
12.04.2023
Configuring OctopusDeploy – Smoke test
/ 40
$url = ("http://" + $hostname + ":" + $port + "/")
Invoke-WebRequest $url -UseBasicParsing
12.04.2023
Configuring OctopusDeploy – UAT Verification
/ 41
12.04.2023
Configuring OctopusDeploy – Variables
/ 42
12.04.2023
Configuring OctopusDeploy – Security
/ 43
12.04.2023
Configuring OctopusDeploy – Security
/ 44
12.04.2023
Configuring TeamCity – Integration build
/ 45
12.04.2023
Configuring TeamCity – Dependencies
/ 46
12.04.2023
Configuring TeamCity – Create release
/ 47
12.04.2023
Configuring TeamCity – Integration tests
/ 48
$url = ("http://tcod-build:8080/")
$TeamCitySession = New-Object Microsoft.PowerShell.Commands.WebRequestSessionInvoke-WebRequest -Uri $url -WebSession $TeamCitySession -UseBasicParsing
12.04.2023
DEPLOYING A SERVICE
/ 49
12.04.2023
Asp.net mvc webapi as a service
/ 50
<appSettings> <add key="Environment" value="Local" /> <add key="Hostname" value="localhost" /> <add key="Port" value="8989" /> </appSettings>
12.04.2023
And then…
/ 51
12.04.2023
Differences - Steps
/ 52
12.04.2023
Differences - Publish service
/ 53
12.04.2023
Differences - Variables
/ 54
12.04.2023
Differences - Automated «Acceptance test»
/ 55
$url = ("http://tcod-build:8090/api/version")
$TeamCitySession = New-Object Microsoft.PowerShell.Commands.WebRequestSession$response = Invoke-WebRequest -Uri $url -WebSession $TeamCitySession -UseBasicParsing
if ($response.Content.Contains("Development")){ Write-Host "Correct environment(Development)."}else{ Write-Host Environment 'Development' not found. Exit 1}$buildNumber = $env:build_numberif ($response.Content.Contains($buildNumber)){ Write-Host "Correct build number($buildNumber)."}else{ Write-Host Build number '$buildNumber' not found. Exit 1}
12.04.2023
WRITING POWERSHELLS SCRIPTS
/ 56
12.04.2023
Deploy.config
/ 57
<?xml version="1.0"?><configuration>
<name>MyProject</name><nuGet>
<url>"http://www.myget.org/F/MyProject/"</url><apiKey>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</apiKey><username>myUser</username><password>myPassword</password>
</nuGet></configuration>
12.04.2023
CreateOctopusPackage.ps1
/ 58
param ([string]$contentDir, [string]$version)
try{ $configFile = New-Object XML $configFile.Load('Deploy.config') $config = $configFile.configuration
$nuspecFileName = $config.name+'.nuspec' $targetNuspecFileName = Join-Path $contentDir $nuspecFileName
.\nuget.exe pack $targetNuspecFileName-OutputDirectory $contentDir-Version $version
}catch { Write-Error $error[0] Exit 1}
12.04.2023
PublishNuGet.ps1
/ 59
param ([string]$contentDir, [string]$version)
try{ $configFile = New-Object XML $configFile.Load('Deploy.config') $config = $configFile.configuration $nugetFileName = $config.name+'.'+$version+'.nupkg'
nuget sources Add -Name $config.name -Source $config.nuGet.url -Username $config.nuGet.username -Password $config.nuGet.password
nuget push $nugetFileName $config.nuGet.apiKey -Source $config.name nuget sources Remove -Name $config.name}catch { Write-Error $error[0] Exit 1}
12.04.2023
CreateMSDeployPackage.ps1
/ 60
param ([string]$sourceDir, [string]$targetPackage)
$BuildDir = (Split-Path $MyInvocation.MyCommand.Path -Parent) $msdeploy = $BuildDir + "\msdeploy.exe" $parameterFile = $BuildDir + "\parameters.xml"
$msdeploy_params = " -verb:sync"$msdeploy_params += " -source:contentPath=" + $sourceDir$msdeploy_params += " -dest:package=" + $targetPackage$msdeploy_params += " -declareParamFile:" + $parameterFile
Write-Host "creating '$targetPackage' from '$sourceDir'."try { iex "$msdeploy $msdeploy_params"}catch { Write-Error $error[0] Exit 1}
12.04.2023
Deploy.ps1
/ 61
. .\DeployUtil.ps1
$ServiceName = "Itera.NDC2013.TCOD.Service"$ServiceExecutable = $ServiceName + ".exe"
Install-WebApi-Service $ServiceName $ServiceExecutable
12.04.2023
DeployUtil.ps1
/ 62
function Install-WebApi-Service($name, $executable) { Write-Host "'$name'$executable'" $service = Get-Service $name -ErrorAction SilentlyContinue $fullPath = Resolve-Path $executable
if (! $service) { Write-Host "Installing service" $frameworkDir = Get-FrameworkDirectory Set-Alias install_util (Join-Path $frameworkDir "installutil.exe") install_util $fullPath } else { Write-Host "The service will be stopped and reconfigured" Stop-Service $name -Force & "sc.exe" config $service.Name binPath= $fullPath start= auto } $config = $executable + ".config" $port = Get-Port $config Set-User-Rights $port "NT AUTHORITY\NETWORK SERVICE" Write-Host "Starting service" Start-Service $name | Write-Host}
12.04.2023
DeployUtil.ps1
/ 63
function Get-FrameworkDirectory {$([System.Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory())}
function Set-User-Rights($port, $user) { $uri = "http://+:$port/" $acls = (netsh http show urlacl url=$uri | Select-String -SimpleMatch $user) if ($acls.count -eq 0 ) { Write-Host "Setting rights for '$user' on $uri" netsh http add urlacl url=$uri user=$user | Write-Host } else { Write-Host "Rights already set for '$user' on $uri." }}
12.04.2023
DeployUtil.ps1
/ 64
function Get-Port($config){ Write-Host "Reading config file '$config'" $found = $FALSE $appConfig = [xml](cat .\$config) $appConfig.configuration.appSettings.add | foreach { if ($_.key -eq 'Port') { $port = $_.value $found = $TRUE } } if (-not $found) { $port = "8080“ } $($port)}
12.04.2023
AUTOMATING YOUR PROCESS
/ 65
12.04.2023
Automating your process
• Create environments and projects• Add all the automated build steps you can• Add manual steps for the rest• Automate manual steps one by one• You can have more than one tentacle on a server
– Not as a service
/ 66
12.04.2023
CONNECTING THE ISSUE TRACKER
/ 67
12.04.2023
Connecting the issue tracker
• Connect TeacmCity throught Settings – Issue Tracker• Connect your issue tracker to TeamCity• Use the Issue tracker’s web api to get issues pending user acceptance
– Add them to releasenotes while deploying
/ 68
Kristoffer Rolf DeinoffLead Technologist
@gatepoet [email protected]