vhd/packer/configure-windows-vhd.ps1 (310 lines of code) (raw):

<# .SYNOPSIS Used to produce Windows AKS images. .DESCRIPTION This script is used by packer to produce Windows AKS images. #> param() $ErrorActionPreference = "Stop" filter Timestamp { "$(Get-Date -Format o): $_" } $global:containerdPackageUrl = "https://mobyartifacts.azureedge.net/moby/moby-containerd/1.6.36+azure/windows/windows_amd64/moby-containerd-1.6.36+azure-u1.amd64.zip" function Write-Log($Message) { $msg = $message | Timestamp Write-Output $msg } function Disable-WindowsUpdates { # See https://docs.microsoft.com/en-us/windows/deployment/update/waas-wu-settings # for additional information on WU related registry settings Write-Log "Disabling automatic windows upates" $WindowsUpdatePath = "HKLM:SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" $AutoUpdatePath = "HKLM:SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" if (Test-Path -Path $WindowsUpdatePath) { Remove-Item -Path $WindowsUpdatePath -Recurse } New-Item -Path $WindowsUpdatePath | Out-Null New-Item -Path $AutoUpdatePath | Out-Null Set-ItemProperty -Path $AutoUpdatePath -Name NoAutoUpdate -Value 1 | Out-Null } function Get-ContainerImages { param ( $containerRuntime, $windowsServerVersion ) switch ($windowsServerVersion) { '2019' { $imagesToPull = @( "mcr.microsoft.com/windows/servercore:ltsc2019", "mcr.microsoft.com/windows/nanoserver:1809", "mcr.microsoft.com/oss/kubernetes/pause:3.8", "mcr.microsoft.com/oss/kubernetes/azure-cloud-node-manager:v1.29.9", "mcr.microsoft.com/oss/kubernetes/azure-cloud-node-manager:v1.30.8", "mcr.microsoft.com/oss/kubernetes-csi/azuredisk-csi:v1.29.1", "mcr.microsoft.com/oss/kubernetes-csi/azuredisk-csi:v1.29.1-windows-hp", "mcr.microsoft.com/oss/kubernetes-csi/azuredisk-csi:v1.31.5", "mcr.microsoft.com/oss/kubernetes-csi/azuredisk-csi:v1.31.5-windows-hp", "mcr.microsoft.com/oss/kubernetes-csi/csi-node-driver-registrar:v2.8.0", "mcr.microsoft.com/oss/kubernetes-csi/csi-node-driver-registrar:v2.13.0", "mcr.microsoft.com/oss/kubernetes-csi/livenessprobe:v2.10.0", "mcr.microsoft.com/oss/kubernetes-csi/livenessprobe:v2.15.0", "mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0") } '2004' { $imagesToPull = @( "mcr.microsoft.com/windows/servercore:2004", "mcr.microsoft.com/windows/nanoserver:2004", "mcr.microsoft.com/oss/kubernetes/pause:1.4.1", "mcr.microsoft.com/oss/kubernetes/pause:3.4.1", "mcr.microsoft.com/oss/kubernetes/pause:3.8") } default { $imagesToPull = @() } } if ($containerRuntime -eq 'containerd') { # start containerd to pre-pull the images to disk on VHD # CSE will configure and register containerd as a service at deployment time Start-Job -Name containerd -ScriptBlock { containerd.exe } foreach ($image in $imagesToPull) { & ctr.exe -n k8s.io images pull $image } Stop-Job -Name containerd Remove-Job -Name containerd } else { foreach ($image in $imagesToPull) { docker pull $image } } } function Get-FilesToCacheOnVHD { Write-Log "Caching misc files on VHD" $map = @{ "c:\akse-cache\" = @( "https://github.com/Azure/aks-engine-azurestack/raw/master/scripts/collect-windows-logs.ps1", "https://github.com/Microsoft/SDN/raw/master/Kubernetes/flannel/l2bridge/cni/win-bridge.exe", "https://github.com/microsoft/SDN/raw/master/Kubernetes/windows/debug/collectlogs.ps1", "https://github.com/microsoft/SDN/raw/master/Kubernetes/windows/debug/dumpVfpPolicies.ps1", "https://github.com/microsoft/SDN/raw/master/Kubernetes/windows/debug/portReservationTest.ps1", "https://github.com/microsoft/SDN/raw/master/Kubernetes/windows/debug/starthnstrace.cmd", "https://github.com/microsoft/SDN/raw/master/Kubernetes/windows/debug/startpacketcapture.cmd", "https://github.com/microsoft/SDN/raw/master/Kubernetes/windows/debug/stoppacketcapture.cmd", "https://github.com/Microsoft/SDN/raw/master/Kubernetes/windows/debug/VFP.psm1", "https://github.com/microsoft/SDN/raw/master/Kubernetes/windows/helper.psm1", "https://github.com/microsoft/SDN/raw/master/Kubernetes/windows/hns.v2.psm1" ); "c:\akse-cache\containerd\" = @( $global:containerdPackageUrl ); "c:\akse-cache\csi-proxy\" = @( "https://packages.aks.azure.com/csi-proxy/v1.1.3/binaries/csi-proxy-v1.1.3.tar.gz" ); "c:\akse-cache\win-k8s\" = @( "https://packages.aks.azure.com/kubernetes/v1.29.15/windowszip/v1.29.15-1int.zip", "https://packages.aks.azure.com/kubernetes/v1.30.10/windowszip/v1.30.10-1int.zip" ); "c:\akse-cache\win-vnet-cni\" = @( "https://packages.aks.azure.com/azure-cni/v1.4.59/binaries/azure-vnet-cni-windows-amd64-v1.4.59.zip" ) } foreach ($dir in $map.Keys) { New-Item -ItemType Directory $dir -Force | Out-Null foreach ($URL in $map[$dir]) { $fileName = [IO.Path]::GetFileName($URL) $dest = [IO.Path]::Combine($dir, $fileName) Write-Log "Downloading $URL to $dest" curl.exe -f --retry 5 --retry-delay 0 -L $URL -o $dest if ($LASTEXITCODE) { throw "Curl exited with '$LASTEXITCODE' while attemping to downlaod '$URL'" } } } } function Install-ContainerD { Write-Log "Getting containerD binaries from $global:containerdPackageUrl" $installDir = "c:\program files\containerd" Write-Log "Installing containerd to $installDir" New-Item -ItemType Directory $installDir -Force | Out-Null if ($global:containerdPackageUrl.endswith(".zip")) { $zipPath = [IO.Path]::Combine($installDir, "containerd.zip") Invoke-WebRequest -UseBasicParsing -Uri $global:containerdPackageUrl -OutFile $zipPath Expand-Archive -path $zipPath -DestinationPath $installDir -Force Remove-Item -Path $zipPath | Out-Null } else { $tarPath = [IO.Path]::Combine($installDir, "containerd.tar.gz") Invoke-WebRequest -UseBasicParsing -Uri $global:containerdPackageUrl -OutFile $tarPath tar -xzf $tarPath --strip=1 -C $installDir Remove-Item -Path $tarPath | Out-Null } $newPath = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::Machine) + ";$installDir" [Environment]::SetEnvironmentVariable("Path", $newPath, [EnvironmentVariableTarget]::Machine) $env:Path += ";$installDir" } function Install-Docker { $defaultDockerVersion = "20.10.9" Write-Log "Attempting to install Docker version $defaultDockerVersion" Install-PackageProvider -Name DockerMsftProvider -Force -ForceBootstrap | Out-Null $package = Find-Package -Name Docker -ProviderName DockerMsftProvider -RequiredVersion $defaultDockerVersion Write-Log "Installing Docker version $($package.Version)" $package | Install-Package -Force | Out-Null Start-Service docker } function Install-OpenSSH { Write-Log "Installing OpenSSH Server" # Somehow openssh client got added to Windows 2019 base image. # Remove openssh client in order to install the server. Remove-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 } function Install-WindowsPatches { param ( $windowsServerVersion ) switch ($windowsServerVersion) { '2019' { # Windows Server 2019 update history can be found at https://support.microsoft.com/en-us/help/4464619 # then you can get download links by searching for specific KBs at http://www.catalog.update.microsoft.com/home.aspx # Find a specific patch at https://www.catalog.update.microsoft.com/Search.aspx?q=kb5005625 $patchUrls = @() } '2004' { # Windows Server, Version 2004 update history can be found at https://support.microsoft.com/en-us/help/4555932 # then you can get download links by searching for specific KBs at http://www.catalog.update.microsoft.com/home.aspx $patchUrls = @() } default { $patchUrls = @() } } foreach ($patchUrl in $patchUrls) { $pathOnly = $patchUrl.Split("?")[0] $fileName = Split-Path $pathOnly -Leaf $fileExtension = [IO.Path]::GetExtension($fileName) $fullPath = [IO.Path]::Combine($env:TEMP, $fileName) switch ($fileExtension) { ".msu" { Write-Log "Downloading windows patch from $pathOnly to $fullPath" Invoke-WebRequest -UseBasicParsing $patchUrl -OutFile $fullPath Write-Log "Starting install of $fileName" $proc = Start-Process -PassThru -FilePath wusa.exe -ArgumentList "$fullPath /quiet /norestart" Wait-Process -InputObject $proc switch ($proc.ExitCode) { 0 { Write-Log "Finished install of $fileName" } 3010 { Write-Log "Finished install of $fileName. Reboot required" } default { Write-Log "Error during install of $fileName. ExitCode: $($proc.ExitCode)" exit 1 } } } default { Write-Log "Installing patches with extension $fileExtension is not currently supported." exit 1 } } } } function Set-AllowedSecurityProtocols { $allowedProtocols = @() $insecureProtocols = @([System.Net.SecurityProtocolType]::SystemDefault, [System.Net.SecurityProtocolType]::Ssl3) foreach ($protocol in [System.Enum]::GetValues([System.Net.SecurityProtocolType])) { if ($insecureProtocols -notcontains $protocol) { $allowedProtocols += $protocol } } Write-Log "Settings allowed security protocols to: $allowedProtocols" [System.Net.ServicePointManager]::SecurityProtocol = $allowedProtocols } function Set-WinRmServiceAutoStart { Write-Log "Setting WinRM service start to auto" sc.exe config winrm start=auto } function Set-WinRmServiceDelayedStart { # Hyper-V messes with networking components on startup after the feature is enabled # causing issues with communication over winrm and setting winrm to delayed start # gives Hyper-V enough time to finish configuration before having packer continue. Write-Log "Setting WinRM service start to delayed-auto" sc.exe config winrm start=delayed-auto } function Update-DefenderSignatures { Write-Log "Updating windows defender signatures." Update-MpSignature } function Update-WindowsFeatures { $featuresToEnable = @( "Containers", "Hyper-V", "Hyper-V-PowerShell") foreach ($feature in $featuresToEnable) { Write-Log "Enabling Windows feature: $feature" Install-WindowsFeature $feature } } function Update-Registry { param ( $windowsServerVersion ) if ($windowsServerVersion -Like '2019') { # Enable HNS fixed gated behind reg keys for Windows Server 2019 Write-Log "Enable a HNS fix (0x40) in 2022-11B and another HNS fix (0x10)" $hnsControlFlag=0x50 $currentValue=(Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\hns\State" -Name HNSControlFlag -ErrorAction Ignore) if (![string]::IsNullOrEmpty($currentValue)) { Write-Log "The current value of HNSControlFlag is $currentValue" $hnsControlFlag=([int]$currentValue.HNSControlFlag -bor $hnsControlFlag) } Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\hns\State" -Name HNSControlFlag -Value $hnsControlFlag -Type DWORD Write-Log "Enable a WCIFS fix in 2022-10B" $currentValue=(Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\wcifs" -Name WcifsSOPCountDisabled -ErrorAction Ignore) if (![string]::IsNullOrEmpty($currentValue)) { Write-Log "The current value of WcifsSOPCountDisabled is $currentValue" } Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\wcifs" -Name WcifsSOPCountDisabled -Value 0 -Type DWORD } } # Disable progress writers for this session to greatly speed up operations such as Invoke-WebRequest $ProgressPreference = 'SilentlyContinue' $containerRuntime = $env:ContainerRuntime $validContainerRuntimes = @('containerd', 'docker') if (-not ($validContainerRuntimes -contains $containerRuntime)) { Write-Host "Unsupported container runtime: $containerRuntime" exit 1 } $windowsServerVersion = $env:WindowsServerVersion $validWindowsServerContainers = @('2019', '2004') if (-not ($validWindowsServerContainers -contains $windowsServerVersion)) { Write-Host "Unsupported Windows Server version: $windowsServerVersion" exit 1 } switch ($env:ProvisioningPhase) { "1" { Write-Log "Performing actions for provisioning phase 1" Set-WinRmServiceDelayedStart Set-AllowedSecurityProtocols Disable-WindowsUpdates Install-WindowsPatches -WindowsServerVersion $windowsServerVersion Update-DefenderSignatures Install-OpenSSH Update-WindowsFeatures } "2" { Write-Log "Performing actions for provisioning phase 2 for container runtime '$containerRuntime'" Set-WinRmServiceAutoStart if ($containerRuntime -eq 'containerd') { Install-ContainerD } else { Install-Docker } Update-Registry -WindowsServerVersion $windowsServerVersion Get-ContainerImages -containerRuntime $containerRuntime -WindowsServerVersion $windowsServerVersion Get-FilesToCacheOnVHD (New-Guid).Guid | Out-File -FilePath 'c:\vhd-id.txt' } default { Write-Log "Unable to determine provisiong phase... exiting" exit 1 } }