Created
October 4, 2022 01:45
-
-
Save onionhammer/df3f4af9d0e615b11ce062020508b15b to your computer and use it in GitHub Desktop.
Deploy ACA with zero downtime
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.DESCRIPTION | |
deploy-app-revision Creates a new revision of the app, waits for it to be healthy and swaps traffic | |
#> | |
Param ( | |
[String] $Environment = "some-rg", | |
[String] $AppName = "some-app", | |
[String] $HealthcheckPath = "api/healthcheck", | |
[String] $Subscription = "", | |
[int] $TimeoutSeconds = 100, | |
[int] $PollingIntervalSeconds = 5 | |
) | |
Write-Host "Reading information from $appName..." | |
# Get revisions | |
$revisions = az containerapp revision list -n $appName -g $Environment --subscription $Subscription ` | |
| ConvertFrom-Json | |
# Get hostname info | |
$hostnames = az containerapp show -g $Environment -n $appName --subscription $Subscription ` | |
--query "properties.[latestRevisionFqdn,latestRevisionName]" ` | |
| ConvertFrom-Json | |
# i.e. somethingsomething-ff1921d9.centralus.azurecontainerapps.io | |
$hostSuffix = ($hostnames[0] -replace $hostnames[1], "").Substring(1) | |
# Define a health checking function | |
function Wait-Ready($Revision) { | |
# Wait for revision to be ready | |
$fqdn = "$Revision.$hostSuffix" | |
Write-Host "Invoking https://$fqdn/$HealthcheckPath with $TimeoutSeconds seconds remaining..." | |
# Start a stopwatch | |
$stopwatch = [system.diagnostics.stopwatch]::StartNew() | |
$remaining = $TimeoutSeconds | |
$healthy = $false | |
$tries = 0 | |
while (-not $healthy -and $remaining -gt 0) { | |
$start = $stopwatch.Elapsed.TotalSeconds | |
try { | |
$timeoutFor = $remaining -gt $PollingIntervalSeconds ? $PollingIntervalSeconds : $remaining | |
$response = Invoke-WebRequest -Uri "https://$fqdn/$HealthcheckPath" -UseBasicParsing -Timeout $timeoutFor | |
$healthy = $response.StatusCode -eq 200 | |
} | |
catch { | |
$tries++ | |
$end = $stopwatch.Elapsed.TotalSeconds | |
$remaining = $TimeoutSeconds - $end | |
Write-Host "Revision not ready... (try $tries, $remaining seconds remaining)" | |
if ($remaining -gt 0 -and $end - $start -lt $PollingIntervalSeconds) { | |
$sleep = $PollingIntervalSeconds - ($end - $start) | |
Start-Sleep -Seconds $sleep | |
} | |
$remaining = $TimeoutSeconds - $stopwatch.Elapsed.TotalSeconds | |
} | |
} | |
return $healthy | |
} | |
# Step 1: Set traffic to currently active traffic revision | |
$active = $revisions | Where-Object { $_.properties.trafficWeight -gt 0 } | Select-Object -First 1 | |
$activeRevName = $active.name | |
Write-Host "Setting $activeRevName to 100% traffic..." | |
az containerapp ingress traffic set -n $appName -g $Environment --subscription $Subscription --revision-weight "$activeRevName=100" | |
# Step 2: Clone latest revision with new suffix | |
$newId = [guid]::NewGuid().ToString("N").Substring(0, 8) | |
$revName = "$appName--$newId" | |
Write-Host "Creating a new revision $revName..." | |
az containerapp revision copy -n $appName -g $Environment --subscription $Subscription --revision-suffix $newId | |
# Step 3: Wait for newRevision to be ready | |
if (Wait-Ready -Revision $revName) { | |
# Step 4: Update traffic weights to new revision | |
Write-Host "Updating traffic weights..." | |
az containerapp ingress traffic set -n $appName -g $Environment --subscription $Subscription --revision-weight "latest=100" | |
# Step 5: Deactivate revisions with 0 traffic | |
foreach ($rev in $revisions) { | |
Write-Host "Deactivating " $rev.name | |
az containerapp revision deactivate -n $appName -g $Environment --subscription $Subscription --revision $rev.name | |
} | |
} | |
else { | |
Write-Host "Revision failed to become ready" -ForegroundColor Red | |
Exit 1 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment