Skip to content

Commit

Permalink
feat(new): Added Azure.VMSS.ZoneBalance (Azure#2948)
Browse files Browse the repository at this point in the history
* feat(new): Added Azure.VMSS.ZoneBalance

* fix: Updated ref

* fix: Fixed culture

* Update docs/en/rules/Azure.VMSS.ZoneBalance.md

Co-authored-by: Bernie White <[email protected]>

* Update docs/en/rules/Azure.VMSS.ZoneBalance.md

Co-authored-by: Bernie White <[email protected]>

* Update docs/en/rules/Azure.VMSS.ZoneBalance.md

Co-authored-by: Bernie White <[email protected]>

* Minor updates

---------

Co-authored-by: Bernie White <[email protected]>
  • Loading branch information
BenjaminEngeset and BernieWhite authored Jun 19, 2024
1 parent 5095d47 commit f0f8f9d
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 16 deletions.
9 changes: 5 additions & 4 deletions docs/CHANGELOG-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers

## Unreleased

- Virtual Machine Scale Sets:
- Verify that virtual machine scale sets have availability zones configured by @BenjaminEngeset.
[#2902](https://github.com/Azure/PSRule.Rules.Azure/issues/2902)

What's changed since pre-release v1.38.0-B0011:

- New rules:
Expand All @@ -42,6 +38,11 @@ What's changed since pre-release v1.38.0-B0011:
- Azure Virtual Desktop:
- Added check for scheduled agent updates on host pools by @BernieWhite.
[#2946](https://github.com/Azure/PSRule.Rules.Azure/issues/2946)
- Virtual Machine Scale Sets:
- Verify that virtual machine scale sets have best-effort zone balance configured by @BenjaminEngeset.
[#2901](https://github.com/Azure/PSRule.Rules.Azure/issues/2901)
- Verify that virtual machine scale sets have availability zones configured by @BenjaminEngeset.
[#2902](https://github.com/Azure/PSRule.Rules.Azure/issues/2902)
- Engineering:
- Quality updates to rule documentation by @BernieWhite.
[#2570](https://github.com/Azure/PSRule.Rules.Azure/issues/2570)
Expand Down
108 changes: 108 additions & 0 deletions docs/en/rules/Azure.VMSS.ZoneBalance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
severity: Important
pillar: Reliability
category: RE:07 Self-preservation
resource: Virtual Machine Scale Sets
online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.VMSS.ZoneBalance/
---

# Deploy virtual machine scale set instances using best-effort zone balance

## SYNOPSIS

Deploy virtual machine scale set instances using the best-effort zone balance in supported regions.

## DESCRIPTION

Virtual machine scale sets (VMSS) scale-in/ out based on scaling rules your configured.
When scaling-out (adding instances) using availability zones instances are distribution over the configured zones.
However, it may not be possible to create an instance in a zone if there is an active issue affecting that zone.

The distribution behavior of instances across zones can be configured with two modes:

- **Best-effort zone balance** - Attempt to scale-in/ out while maintaining balance across zones.
If that is not possible, allow temporary imbalance so the scaling operation can complete.
- On subsequent scale-out attempts, the scale set adds VMs to the zones needing more VMs to restore balance.
- On subsequent scale-in attempts, the scale set removes VMs from zones that have more VMs than required to restore balance.
- **Strict zone balance** - Only allow the scaling operation to continue if zone balanced can be maintained.
If that is not possible, the scaling operation will fail.

Key points:

- Both modes attempt to keep balance across zones but have a different approach when balance can't be maintained.
- Scale-out typically occurs to reduce pressure on the already provisioned instances by increasing capacity.
- If scale-out fails, the workload may become unstable due to increasing pressure.
- Balance only applies when two or more zones are configured on the VMSS.
- An outage or disruption in a zone may impact a higher percentage of the workload instances when the workload is not balanced.

## RECOMMENDATION

Consider using best-effort zone balancing to maintain stability of the workload under load.

## EXAMPLES

### Configure with Azure template

To set best-effort zone balance for a virtual machine scale set:

- Set the `properties.zoneBalance` property to `false`.

For example:

```json
{
"type": "Microsoft.Compute/virtualMachineScaleSets",
"apiVersion": "2023-09-01",
"name": "[parameters('name')]",
"location": "[parameters('location')]",
"sku": {
"name": "b2ms",
"tier": "Standard",
"capacity": 3
},
"properties": {
"zoneBalance": false
},
"zones": [
"1",
"2",
"3"
]
}
```

### Configure with Bicep

To set best-effort zone balance for a virtual machine scale set:

- Set the `properties.zoneBalance` property to `false`.

For example:

```bicep
resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' = {
name: name
location: location
sku: {
name: 'b2ms'
tier: 'Standard'
capacity: 3
}
properties: {
zoneBalance: false
}
zones: [
'1'
'2'
'3'
]
}
```

<!-- external:avm res/compute/virtual-machine-scale-set zoneBalance -->

## LINKS

- [RE:07 Self-preservation](https://learn.microsoft.com/azure/well-architected/reliability/self-preservation)
- [Zone balancing](https://learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-use-availability-zones#zone-balancing)
- [Azure resource deployment](https://learn.microsoft.com/azure/templates/microsoft.compute/virtualmachinescalesets)
37 changes: 27 additions & 10 deletions src/PSRule.Rules.Azure/rules/Azure.VMSS.Rule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,24 @@ Rule 'Azure.VMSS.ScriptExtensions' -Ref 'AZR-000333' -Type 'Microsoft.Compute/vi

## Extension Prof
if ($vmssConfig.properties.virtualMachineProfile.extensionProfile.extensions) {
foreach($extensions in $vmssConfig.properties.virtualMachineProfile.extensionProfile.extensions ) {
foreach ($extensions in $vmssConfig.properties.virtualMachineProfile.extensionProfile.extensions ) {
$cleanValue = [PSRule.Rules.Azure.Runtime.Helper]::CompressExpression($extensions.properties.settings.commandToExecute);
$Assert.NotMatch($cleanValue, '.', "SecretReference")
}

} else {
}
else {
return $Assert.Pass();
}
}

# Synopsis: Use Azure Monitor Agent as replacement for Log Analytics Agent.
Rule 'Azure.VMSS.MigrateAMA' -Ref 'AZR-000318' -Type 'Microsoft.Compute/virtualMachineScaleSets' -If { HasOMSOrAMAExtension } -Tag @{ release = 'GA'; ruleSet = '2022_12'; 'Azure.WAF/pillar' = 'Operational Excellence'; } {
$property = $TargetObject.Properties.virtualMachineProfile.extensionProfile.extensions.properties |
Where-Object { (($_.publisher -eq 'Microsoft.EnterpriseCloud.Monitoring') -and ($_.type -eq 'MicrosoftMonitoringAgent')) -or
Where-Object { (($_.publisher -eq 'Microsoft.EnterpriseCloud.Monitoring') -and ($_.type -eq 'MicrosoftMonitoringAgent')) -or
(($_.publisher -eq 'Microsoft.EnterpriseCloud.Monitoring') -and ($_.type -eq 'OmsAgentForLinux')) }
$subresource = @(GetSubResources -ResourceType 'Microsoft.Compute/virtualMachineScaleSets/extensions' |
Where-Object { (($_.Properties.publisher -eq 'Microsoft.EnterpriseCloud.Monitoring') -and ($_.Properties.type -eq 'MicrosoftMonitoringAgent')) -or
$subresource = @(GetSubResources -ResourceType 'Microsoft.Compute/virtualMachineScaleSets/extensions' |
Where-Object { (($_.Properties.publisher -eq 'Microsoft.EnterpriseCloud.Monitoring') -and ($_.Properties.type -eq 'MicrosoftMonitoringAgent')) -or
(($_.Properties.publisher -eq 'Microsoft.EnterpriseCloud.Monitoring') -and ($_.Properties.type -eq 'OmsAgentForLinux')) })

$extensions = @($property; $subresource)
Expand All @@ -82,17 +83,16 @@ Rule 'Azure.VMSS.MigrateAMA' -Ref 'AZR-000318' -Type 'Microsoft.Compute/virtualM
# Synopsis: Use Azure Monitor Agent for collecting monitoring data.
Rule 'Azure.VMSS.AMA' -Ref 'AZR-000346' -Type 'Microsoft.Compute/virtualMachineScaleSets' -Tag @{ release = 'GA'; ruleSet = '2022_12'; 'Azure.WAF/pillar' = 'Operational Excellence'; } {
$amaTypes = @('AzureMonitorWindowsAgent', 'AzureMonitorLinuxAgent')
$property = $TargetObject.Properties.virtualMachineProfile.extensionProfile.extensions.properties |
Where-Object { $_.publisher -eq 'Microsoft.Azure.Monitor' -or $_.type -in $amaTypes }
$subresource = @(GetSubResources -ResourceType 'Microsoft.Compute/virtualMachineScaleSets/extensions' |
Where-Object { $_.properties.publisher -eq 'Microsoft.Azure.Monitor' -or $_.properties.type -in $amaTypes })
$property = $TargetObject.Properties.virtualMachineProfile.extensionProfile.extensions.properties |
Where-Object { $_.publisher -eq 'Microsoft.Azure.Monitor' -or $_.type -in $amaTypes }
$subresource = @(GetSubResources -ResourceType 'Microsoft.Compute/virtualMachineScaleSets/extensions' |
Where-Object { $_.properties.publisher -eq 'Microsoft.Azure.Monitor' -or $_.properties.type -in $amaTypes })

$amaExtensions = @($property; $subresource)
$Assert.GreaterOrEqual($amaExtensions, '.', 1).
Reason($LocalizedData.VMSSAzureMonitorAgent)
}


# Synopsis: Deploy virtual machine scale set instances using availability zones in supported regions to ensure high availability and resilience.
Rule 'Azure.VMSS.AvailabilityZone' -Ref 'AZR-000436' -Type 'Microsoft.Compute/virtualMachineScaleSets' -Tag @{ release = 'GA'; ruleSet = '2024_06 '; 'Azure.WAF/pillar' = 'Reliability'; } {
# Check if the region supports availability zones.
Expand All @@ -112,6 +112,11 @@ Rule 'Azure.VMSS.AvailabilityZone' -Ref 'AZR-000436' -Type 'Microsoft.Compute/vi
)
}

# Synopsis: Deploy virtual machine scale set instances using the best-effort zone balance in supported regions to ensure an approximately balanced distribution of instances across availability zones.
Rule 'Azure.VMSS.ZoneBalance' -Ref 'AZR-000438' -Type 'Microsoft.Compute/virtualMachineScaleSets' -If { RegionSupportsAvailabilityZones } -Tag @{ release = 'GA'; ruleSet = '2024_06 '; 'Azure.WAF/pillar' = 'Reliability'; } {
$Assert.HasDefaultValue($TargetObject, 'properties.zoneBalance', $false)
}

#endregion Rules

#endregion Virtual machine scale set
Expand All @@ -127,4 +132,16 @@ function global:IsLinuxVMSS {
}
}

function global:RegionSupportsAvailabilityZones {
[CmdletBinding()]
param ( )
$provider = [PSRule.Rules.Azure.Runtime.Helper]::GetResourceType('Microsoft.Compute', 'virtualMachineScaleSets')
$availabilityZones = GetAvailabilityZone -Location $TargetObject.Location -Zone $provider.ZoneMappings

if (-not $availabilityZones) {
return $false
}
$true
}

#endregion Helper functions
21 changes: 21 additions & 0 deletions tests/PSRule.Rules.Azure.Tests/Azure.VMSS.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,27 @@ Describe 'Azure.VMSS' -Tag 'VMSS' {
$ruleResult.Length | Should -Be 3;
$ruleResult.TargetName | Should -BeIn 'vmss-003', 'vmss-004', 'vmss-005';
}

It 'Azure.VMSS.ZoneBalance' {
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.VMSS.ZoneBalance' };

# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -BeIn 'vmss-002';

$ruleResult[0].Reason | Should -BeExactly "The field 'properties.zoneBalance' is set to 'True'.";

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult.Length | Should -Be 3;
$ruleResult.TargetName | Should -BeIn 'vmss-001', 'vmss-004', 'vmss-005';

# None
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'None' });
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -BeIn 'vmss-003';
}
}

Context 'Resource name - Azure.VMSS.Name' {
Expand Down
6 changes: 4 additions & 2 deletions tests/PSRule.Rules.Azure.Tests/Resources.VMSS.json
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,8 @@
},
"provisioningState": "Succeeded",
"overprovision": false,
"doNotRunExtensionsOnOverprovisionedVMs": false
"doNotRunExtensionsOnOverprovisionedVMs": false,
"zoneBalance": true
},
"zones": [
"1"
Expand Down Expand Up @@ -816,7 +817,8 @@
},
"provisioningState": "Succeeded",
"overprovision": false,
"doNotRunExtensionsOnOverprovisionedVMs": false
"doNotRunExtensionsOnOverprovisionedVMs": false,
"zoneBalance": false
},
"zones": [
"1",
Expand Down

0 comments on commit f0f8f9d

Please sign in to comment.