Skip to content
This repository was archived by the owner on Mar 31, 2026. It is now read-only.

Commit 310d47a

Browse files
committed
Run spot worker on .NET 7 and enable optional LB
1 parent 8daa670 commit 310d47a

12 files changed

Lines changed: 196 additions & 74 deletions

.pipelines/Retail.PullRequest.yml

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,31 @@ jobs:
9393
pwsh: true
9494
retryCountOnTaskFailure: 1
9595

96-
- script: dotnet publish $(Build.SourcesDirectory)/src/Website/Website.csproj --configuration $(BuildConfiguration) --runtime ${{ rid }} --self-contained false
97-
displayName: "Publish Website to ZIP"
96+
- script: dotnet build $(Build.SourcesDirectory)/src/Website/Website.csproj --configuration $(BuildConfiguration) --runtime ${{ rid }} --self-contained false
97+
displayName: "Build Website for ${{ rid }}"
9898

99-
- script: dotnet publish $(Build.SourcesDirectory)/src/Worker/Worker.csproj --configuration $(BuildConfiguration) --runtime ${{ rid }} --self-contained false
100-
displayName: "Publish Worker to ZIP"
99+
- script: dotnet publish $(Build.SourcesDirectory)/src/Website/Website.csproj --no-build --configuration $(BuildConfiguration) --runtime ${{ rid }} --self-contained false --output $(OutputDirectory)/deploy/Website
100+
displayName: "Publish Website for ${{ rid }}"
101+
102+
- task: ArchiveFiles@2
103+
displayName: "Zip Website"
104+
inputs:
105+
rootFolderOrFile: $(OutputDirectory)/deploy/Website
106+
includeRootFolder: false
107+
archiveFile: $(OutputDirectory)/deploy/Website.zip
108+
109+
- script: dotnet build $(Build.SourcesDirectory)/src/Worker/Worker.csproj --configuration $(BuildConfiguration) --runtime ${{ rid }} --self-contained false
110+
displayName: "Build Worker for ${{ rid }}"
111+
112+
- script: dotnet publish $(Build.SourcesDirectory)/src/Worker/Worker.csproj --no-build --configuration $(BuildConfiguration) --runtime ${{ rid }} --self-contained false --output $(OutputDirectory)/deploy/Worker
113+
displayName: "Publish Worker for ${{ rid }}"
114+
115+
- task: ArchiveFiles@2
116+
displayName: "Zip Worker"
117+
inputs:
118+
rootFolderOrFile: $(OutputDirectory)/deploy/Worker
119+
includeRootFolder: false
120+
archiveFile: $(OutputDirectory)/deploy/Worker.zip
101121

102122
- task: PowerShell@2
103123
displayName: "Publish Azure Functions host"

Directory.Build.props

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
<ArtifactsSubdirectory Condition="'$(ArtifactsDirectory)' != ''">NuGet.Insights\</ArtifactsSubdirectory>
66
<ArtifactsSubdirectory Condition="'$(ArtifactsDirectory)' == ''"></ArtifactsSubdirectory>
77
<ArtifactsDirectory Condition="'$(ArtifactsDirectory)' == ''">$(MSBuildThisFileDirectory)artifacts</ArtifactsDirectory>
8-
<DeploymentDir Condition="'$(DeploymentDir)' == ''">$(ArtifactsDirectory)\deploy</DeploymentDir>
98
<_ProjectArtifactsDirectory>$(ArtifactsDirectory)\$(ArtifactsSubdirectory)$(MSBuildProjectName)\</_ProjectArtifactsDirectory>
109
<BaseIntermediateOutputPath>$(_ProjectArtifactsDirectory)obj\</BaseIntermediateOutputPath>
1110
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>

Directory.Build.targets

Lines changed: 0 additions & 14 deletions
This file was deleted.

deploy/bicep/function-worker.bicep

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ resource workerPlanAutoScale 'Microsoft.Insights/autoscalesettings@2015-04-01' =
7676
direction: 'Increase'
7777
type: 'ChangeCount'
7878
cooldown: 'PT1M'
79-
value: '5'
79+
value: string(min(maxInstances - minInstances, 5))
8080
}
8181
}
8282
{
@@ -95,7 +95,7 @@ resource workerPlanAutoScale 'Microsoft.Insights/autoscalesettings@2015-04-01' =
9595
direction: 'Decrease'
9696
type: 'ChangeCount'
9797
cooldown: 'PT2M'
98-
value: '10'
98+
value: string(min(maxInstances - minInstances, 10))
9999
}
100100
}
101101
]

deploy/bicep/main.bicep

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ module spotWorkers './spot-workers.bicep' = if (useSpotWorkers) {
227227
params: {
228228
location: location
229229
storageAccountName: storageAccountName
230+
keyVaultName: keyVaultName
230231
userManagedIdentityName: userManagedIdentityName
231232
uploadScriptUrl: spotWorkerUploadScriptUrl
232233
deploymentUrls: spotWorkerDeploymentUrls

deploy/bicep/spot-worker.bicep

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,95 @@ param customScriptExtensionFiles array
66

77
param location string
88
param vmssSku string
9+
@minValue(0)
10+
param minInstances int
911
@minValue(1)
1012
param maxInstances int
1113
param nsgName string
1214
param vnetName string
1315
param vmssName string
1416
param nicName string
1517
param ipConfigName string
18+
param loadBalancerName string
1619
param autoscaleName string
1720
param adminUsername string
1821
@secure()
1922
param adminPassword string
23+
param addLoadBalancer bool
24+
25+
resource ipConfig 'Microsoft.Network/publicIPAddresses@2022-05-01' = if (addLoadBalancer) {
26+
name: ipConfigName
27+
location: location
28+
sku: {
29+
name: 'Standard'
30+
}
31+
properties: {
32+
publicIPAllocationMethod: 'Static'
33+
publicIPAddressVersion: 'IPv4'
34+
}
35+
}
36+
37+
var frontendIPConfigurationName = '${loadBalancerName}-fipc'
38+
var backendAddressPoolName = '${loadBalancerName}-bap'
39+
40+
resource loadBalancer 'Microsoft.Network/loadBalancers@2023-05-01' = if (addLoadBalancer) {
41+
name: loadBalancerName
42+
location: location
43+
sku: {
44+
name: 'Standard'
45+
}
46+
properties: {
47+
frontendIPConfigurations: [
48+
{
49+
name: frontendIPConfigurationName
50+
properties: {
51+
publicIPAddress: {
52+
id: ipConfig.id
53+
}
54+
}
55+
}
56+
]
57+
backendAddressPools: [
58+
{
59+
name: backendAddressPoolName
60+
properties: {}
61+
}
62+
]
63+
inboundNatRules: [
64+
{
65+
name: '${loadBalancerName}-rdp-inr'
66+
properties: {
67+
frontendIPConfiguration: {
68+
id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', loadBalancerName, frontendIPConfigurationName)
69+
}
70+
backendAddressPool: {
71+
id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', loadBalancerName, backendAddressPoolName)
72+
}
73+
protocol: 'Tcp'
74+
backendPort: 3389
75+
frontendPortRangeStart: 50000
76+
frontendPortRangeEnd: 60000
77+
}
78+
}
79+
]
80+
outboundRules: [
81+
{
82+
name: '${loadBalancerName}-or'
83+
properties: {
84+
frontendIPConfigurations: [
85+
{
86+
id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', loadBalancerName, frontendIPConfigurationName)
87+
}
88+
]
89+
backendAddressPool: {
90+
id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', loadBalancerName, backendAddressPoolName)
91+
}
92+
protocol: 'All'
93+
}
94+
}
95+
]
96+
}
97+
}
2098

2199
resource nsg 'Microsoft.Network/networkSecurityGroups@2021-03-01' = {
22100
name: nsgName
@@ -26,7 +104,7 @@ resource nsg 'Microsoft.Network/networkSecurityGroups@2021-03-01' = {
26104
{
27105
name: 'AllowCorpNetPublicRdp'
28106
properties: {
29-
priority: 100
107+
priority: 2000
30108
protocol: 'Tcp'
31109
access: 'Allow'
32110
direction: 'Inbound'
@@ -39,7 +117,7 @@ resource nsg 'Microsoft.Network/networkSecurityGroups@2021-03-01' = {
39117
{
40118
name: 'AllowCorpNetSawRdp'
41119
properties: {
42-
priority: 101
120+
priority: 2001
43121
protocol: 'Tcp'
44122
access: 'Allow'
45123
direction: 'Inbound'
@@ -128,11 +206,11 @@ resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2021-11-01' = {
128206
subnet: {
129207
id: vnet.properties.subnets[0].id
130208
}
131-
/* Enable a public IP address so you can RDP into an instance for debugging purposes.
132-
publicIPAddressConfiguration: {
133-
name: ipConfigName
134-
}
135-
*/
209+
loadBalancerBackendAddressPools: addLoadBalancer ? [
210+
{
211+
id: loadBalancer.properties.backendAddressPools[0].id
212+
}
213+
] : []
136214
}
137215
}
138216
]
@@ -222,7 +300,7 @@ var eventCounterRules = [for event in eventCounters: {
222300
direction: 'Increase'
223301
type: 'ExactCount'
224302
cooldown: 'PT1M'
225-
value: '5'
303+
value: string(min(maxInstances, 5))
226304
}
227305
}]
228306

@@ -237,8 +315,8 @@ resource autoscale 'Microsoft.Insights/autoscalesettings@2015-04-01' = {
237315
{
238316
name: 'default'
239317
capacity: {
240-
default: '0'
241-
minimum: '0'
318+
default: string(minInstances)
319+
minimum: string(minInstances)
242320
maximum: string(maxInstances)
243321
}
244322
rules: concat(eventCounterRules, [
@@ -258,7 +336,7 @@ resource autoscale 'Microsoft.Insights/autoscalesettings@2015-04-01' = {
258336
direction: 'Increase'
259337
type: 'ChangeCount'
260338
cooldown: 'PT1M'
261-
value: '5'
339+
value: string(min(maxInstances - minInstances, 5))
262340
}
263341
}
264342
{
@@ -277,7 +355,7 @@ resource autoscale 'Microsoft.Insights/autoscalesettings@2015-04-01' = {
277355
direction: 'Decrease'
278356
type: 'ChangeCount'
279357
cooldown: 'PT2M'
280-
value: '10'
358+
value: string(min(maxInstances - minInstances, 10))
281359
}
282360
}
283361
])

deploy/bicep/spot-workers.bicep

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
param location string
22
param storageAccountName string
3+
param keyVaultName string
34
param userManagedIdentityName string
45
@secure()
56
param uploadScriptUrl string
@@ -12,7 +13,7 @@ param appInsightsName string
1213
param adminUsername string
1314
@secure()
1415
param adminPassword string
15-
param specs array // An array of objects with these properties: "namePrefix", "location", "sku", "maxInstances"
16+
param specs array // An array of objects with these properties: "namePrefix", "location", "sku", "minInstances", "maxInstances"
1617

1718
resource userManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' existing = {
1819
name: userManagedIdentityName
@@ -22,6 +23,18 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2019-06-01' existing
2223
name: storageAccountName
2324
}
2425

26+
resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
27+
name: keyVaultName
28+
29+
resource adminPasswordSecret 'secrets' = {
30+
name: 'admin-password'
31+
properties: {
32+
contentType: 'text/plain'
33+
value: adminPassword
34+
}
35+
}
36+
}
37+
2538
resource leaseContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2019-06-01' = {
2639
name: '${storageAccountName}/default/${spotWorkerDeploymentContainerName}'
2740
dependsOn: [
@@ -71,11 +84,14 @@ module workers './spot-worker.bicep' = [for (spec, index) in specs: {
7184
nsgName: '${spec.namePrefix}nsg'
7285
vnetName: '${spec.namePrefix}vnet'
7386
vmssName: '${spec.namePrefix}vmss'
87+
minInstances: spec.minInstances
7488
maxInstances: spec.maxInstances
7589
nicName: '${spec.namePrefix}nic'
7690
ipConfigName: '${spec.namePrefix}ip'
91+
loadBalancerName: '${spec.namePrefix}lb'
7792
autoscaleName: '${spec.namePrefix}autoscale'
7893
adminUsername: adminUsername
7994
adminPassword: adminPassword
95+
addLoadBalancer: spec.addLoadBalancer
8096
}
8197
}]

deploy/build-ev2.ps1

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,12 @@ process {
249249
# Copy the runtime assets
250250
Copy-Item $WebsiteZipPath -Destination (Join-Path $ev2 $websiteBinPath) -Verbose
251251
Copy-Item $WorkerZipPath -Destination (Join-Path $ev2 $workerBinPath) -Verbose
252-
if ($anyUseSpotWorkers) {
253-
if (!$AzureFunctionsHostZipPath) {
254-
throw "No AzureFunctionsHostZipPath parameter was provided but at least one of the configurations has UseSpotWorkers set to true."
255-
}
252+
if ($AzureFunctionsHostZipPath) {
256253
Copy-Item $AzureFunctionsHostZipPath -Destination (Join-Path $ev2 $azureFunctionsHostBinPath) -Verbose
257254
}
255+
elseif ($anyUseSpotWorkers) {
256+
throw "No AzureFunctionsHostZipPath parameter was provided but at least one of the configurations has UseSpotWorkers set to true."
257+
}
258258
Copy-Item $installWorkerStandaloneSourcePath -Destination (Join-Path $ev2 $installWorkerStandalonePath) -Verbose
259259
Write-Host "Wrote Ev2 files to: $ev2"
260260

deploy/build-host.ps1

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ $RuntimeIdentifier = Get-DefaultRuntimeIdentifier $RuntimeIdentifier
1414
$hostVersion = "4.27.1"
1515

1616
$artifactsDir = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot "../artifacts/azure-functions"))
17-
$hostSrcUrl = "https://github.com/Azure/azure-functions-host/archive/v$hostVersion.zip"
18-
$hostSrcZip = Join-Path $artifactsDir "azure-functions-host-$hostVersion.zip"
17+
$hostRepo = "https://github.com/Azure/azure-functions-host.git"
1918
$hostSrcDir = Join-Path $artifactsDir "azure-functions-host-$hostVersion"
2019
$hostBinDir = Join-Path $artifactsDir "host"
2120
$hostBinZip = if ($OutputPath) { $OutputPath } else { Join-Path $artifactsDir "AzureFunctionsHost.zip" }
@@ -37,18 +36,8 @@ function Remove-DirSafe ($dir) {
3736
Remove-DirSafe $artifactsDir
3837
New-Item $artifactsDir -ItemType Directory | Out-Null
3938

40-
# Download the Azure Functions host source code from GitHub
41-
Write-Host "Downloading Azure Functions host source code"
42-
$beforeSecurityProtocol = [Net.ServicePointManager]::SecurityProtocol;
43-
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
44-
$beforeProgressPreference = $ProgressPreference
45-
$ProgressPreference = "SilentlyContinue"
46-
Invoke-WebRequest $hostSrcUrl -OutFile $hostSrcZip
47-
[Net.ServicePointManager]::SecurityProtocol = $beforeSecurityProtocol
48-
$ProgressPreference = $beforeProgressPreference
49-
50-
# Unzip the source code
51-
Expand-Archive $hostSrcZip -DestinationPath $artifactsDir
39+
Write-Host "Cloning Azure Functions host source code"
40+
git clone --depth 1 --branch "v$hostVersion" $hostRepo $hostSrcDir
5241

5342
# Build and publish the host
5443
$hostProjectPath = Join-Path $hostSrcDir "src/WebJobs.Script.WebHost/WebJobs.Script.WebHost.csproj"
@@ -83,8 +72,14 @@ dotnet restore $hostProjectPath --verbosity Normal
8372
# See: https://github.com/Azure/azure-functions-host/pull/9564
8473
dotnet publish $hostProjectPath -c Release --output $hostBinDir --runtime $RuntimeIdentifier --self-contained false /p:NoWarn=SA1518
8574

75+
if ($LASTEXITCODE -ne 0) {
76+
throw "Failed to publish the Azure Functions Host."
77+
}
78+
8679
# Delete all out-of-process (non-.NET) workers to make the package smaller.
87-
Remove-DirSafe (Join-Path $hostBinDir "workers/*")
80+
$workersDir = Join-Path $hostBinDir "workers"
81+
Remove-DirSafe $workersDir
82+
New-Item $workersDir -ItemType Directory | Out-Null
8883

8984
# Zip the host and app for a stand-alone Azure Functions deployment.
9085
Write-Host "Zipping host to `"$hostBinZip`""

0 commit comments

Comments
 (0)