sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/agentpools/spec.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package agentpools 18 19 import ( 20 "context" 21 22 asocontainerservicev1preview "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20230202preview" 23 asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001" 24 asocontainerservicev1hub "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001/storage" 25 "github.com/Azure/azure-service-operator/v2/pkg/genruntime" 26 "k8s.io/apimachinery/pkg/api/resource" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/utils/ptr" 29 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 30 "sigs.k8s.io/cluster-api-provider-azure/azure" 31 "sigs.k8s.io/cluster-api-provider-azure/azure/services/aso" 32 "sigs.k8s.io/cluster-api-provider-azure/util/tele" 33 "sigs.k8s.io/cluster-api-provider-azure/util/versions" 34 ) 35 36 // KubeletConfig defines the set of kubelet configurations for nodes in pools. 37 type KubeletConfig struct { 38 // CPUManagerPolicy - CPU Manager policy to use. 39 CPUManagerPolicy *string 40 // CPUCfsQuota - Enable CPU CFS quota enforcement for containers that specify CPU limits. 41 CPUCfsQuota *bool 42 // CPUCfsQuotaPeriod - Sets CPU CFS quota period value. 43 CPUCfsQuotaPeriod *string 44 // ImageGcHighThreshold - The percent of disk usage after which image garbage collection is always run. 45 ImageGcHighThreshold *int 46 // ImageGcLowThreshold - The percent of disk usage before which image garbage collection is never run. 47 ImageGcLowThreshold *int 48 // TopologyManagerPolicy - Topology Manager policy to use. 49 TopologyManagerPolicy *string 50 // AllowedUnsafeSysctls - Allowlist of unsafe sysctls or unsafe sysctl patterns (ending in `*`). 51 AllowedUnsafeSysctls []string 52 // FailSwapOn - If set to true it will make the Kubelet fail to start if swap is enabled on the node. 53 FailSwapOn *bool 54 // ContainerLogMaxSizeMB - The maximum size (e.g. 10Mi) of container log file before it is rotated. 55 ContainerLogMaxSizeMB *int 56 // ContainerLogMaxFiles - The maximum number of container log files that can be present for a container. The number must be ≥ 2. 57 ContainerLogMaxFiles *int 58 // PodMaxPids - The maximum number of processes per pod. 59 PodMaxPids *int 60 } 61 62 // AgentPoolSpec contains agent pool specification details. 63 type AgentPoolSpec struct { 64 // Name is the name of the ASO ManagedClustersAgentPool resource. 65 Name string 66 67 // AzureName is the name of the agentpool resource in Azure. 68 AzureName string 69 70 // ResourceGroup is the name of the Azure resource group for the AKS Cluster. 71 ResourceGroup string 72 73 // Cluster is the name of the AKS cluster. 74 Cluster string 75 76 // Version defines the desired Kubernetes version. 77 Version *string 78 79 // SKU defines the Azure VM size for the agent pool VMs. 80 SKU string 81 82 // Replicas is the number of desired machines. 83 Replicas int 84 85 // OSDiskSizeGB is the OS disk size in GB for every machine in this agent pool. 86 OSDiskSizeGB int 87 88 // VnetSubnetID is the Azure Resource ID for the subnet which should contain nodes. 89 VnetSubnetID string 90 91 // Mode represents mode of an agent pool. Possible values include: 'System', 'User'. 92 Mode string 93 94 // Maximum number of nodes for auto-scaling 95 MaxCount *int `json:"maxCount,omitempty"` 96 97 // Minimum number of nodes for auto-scaling 98 MinCount *int `json:"minCount,omitempty"` 99 100 // Node labels - labels for all of the nodes present in node pool 101 NodeLabels map[string]string `json:"nodeLabels,omitempty"` 102 103 // NodeTaints specifies the taints for nodes present in this agent pool. 104 NodeTaints []string `json:"nodeTaints,omitempty"` 105 106 // EnableAutoScaling - Whether to enable auto-scaler 107 EnableAutoScaling bool `json:"enableAutoScaling,omitempty"` 108 109 // AvailabilityZones represents the Availability zones for nodes in the AgentPool. 110 AvailabilityZones []string 111 112 // MaxPods specifies the kubelet --max-pods configuration for the agent pool. 113 MaxPods *int `json:"maxPods,omitempty"` 114 115 // OsDiskType specifies the OS disk type for each node in the pool. Allowed values are 'Ephemeral' and 'Managed'. 116 OsDiskType *string `json:"osDiskType,omitempty"` 117 118 // EnableUltraSSD enables the storage type UltraSSD_LRS for the agent pool. 119 EnableUltraSSD *bool `json:"enableUltraSSD,omitempty"` 120 121 // OSType specifies the operating system for the node pool. Allowed values are 'Linux' and 'Windows' 122 OSType *string `json:"osType,omitempty"` 123 124 // EnableNodePublicIP controls whether or not nodes in the agent pool each have a public IP address. 125 EnableNodePublicIP *bool `json:"enableNodePublicIP,omitempty"` 126 127 // NodePublicIPPrefixID specifies the public IP prefix resource ID which VM nodes should use IPs from. 128 NodePublicIPPrefixID string `json:"nodePublicIPPrefixID,omitempty"` 129 130 // ScaleSetPriority specifies the ScaleSetPriority for the node pool. Allowed values are 'Spot' and 'Regular' 131 ScaleSetPriority *string `json:"scaleSetPriority,omitempty"` 132 133 // ScaleDownMode affects the cluster autoscaler behavior. Allowed values are 'Deallocate' and 'Delete' 134 ScaleDownMode *string `json:"scaleDownMode,omitempty"` 135 136 // SpotMaxPrice defines max price to pay for spot instance. Allowed values are any decimal value greater than zero or -1 which indicates the willingness to pay any on-demand price. 137 SpotMaxPrice *resource.Quantity `json:"spotMaxPrice,omitempty"` 138 139 // KubeletConfig specifies the kubelet configurations for nodes. 140 KubeletConfig *KubeletConfig `json:"kubeletConfig,omitempty"` 141 142 // KubeletDiskType specifies the kubelet disk type for each node in the pool. Allowed values are 'OS' and 'Temporary' 143 KubeletDiskType *infrav1.KubeletDiskType `json:"kubeletDiskType,omitempty"` 144 145 // AdditionalTags is an optional set of tags to add to Azure resources managed by the Azure provider, in addition to the ones added by default. 146 AdditionalTags infrav1.Tags 147 148 // LinuxOSConfig specifies the custom Linux OS settings and configurations 149 LinuxOSConfig *infrav1.LinuxOSConfig 150 151 // EnableFIPS indicates whether FIPS is enabled on the node pool 152 EnableFIPS *bool 153 154 // EnableEncryptionAtHost indicates whether host encryption is enabled on the node pool 155 EnableEncryptionAtHost *bool 156 157 // Patches are extra patches to be applied to the ASO resource. 158 Patches []string 159 160 // Preview indicates whether the agent pool is using a preview version of ASO. 161 Preview bool 162 } 163 164 // ResourceRef implements azure.ASOResourceSpecGetter. 165 func (s *AgentPoolSpec) ResourceRef() genruntime.MetaObject { 166 if s.Preview { 167 return &asocontainerservicev1preview.ManagedClustersAgentPool{ 168 ObjectMeta: metav1.ObjectMeta{ 169 Name: s.Name, 170 }, 171 } 172 } 173 return &asocontainerservicev1.ManagedClustersAgentPool{ 174 ObjectMeta: metav1.ObjectMeta{ 175 Name: s.Name, 176 }, 177 } 178 } 179 180 // getManagedMachinePoolVersion gets the desired managed Kubernetes version. 181 // If the auto upgrade channel is set to patch, stable or rapid, clusters can be upgraded to a higher version by AKS. 182 // If auto upgrade is triggered, the existing Kubernetes version will be higher than the user's desired Kubernetes version. 183 // CAPZ should honour the upgrade and it should not downgrade to the lower desired version. 184 func (s *AgentPoolSpec) getManagedMachinePoolVersion(existing *asocontainerservicev1.ManagedClustersAgentPool) *string { 185 if existing == nil || existing.Spec.OrchestratorVersion == nil { 186 return s.Version 187 } 188 if s.Version == nil { 189 return existing.Spec.OrchestratorVersion 190 } 191 v := versions.GetHigherK8sVersion(*s.Version, *existing.Spec.OrchestratorVersion) 192 return ptr.To(v) 193 } 194 195 // Parameters returns the parameters for the agent pool. 196 func (s *AgentPoolSpec) Parameters(ctx context.Context, existingObj genruntime.MetaObject) (params genruntime.MetaObject, err error) { 197 _, _, done := tele.StartSpanWithLogger(ctx, "agentpools.Service.Parameters") 198 defer done() 199 200 // If existing is preview, convert to stable then back to preview at the end of the function. 201 var existing *asocontainerservicev1.ManagedClustersAgentPool 202 var existingStatus asocontainerservicev1preview.ManagedClusters_AgentPool_STATUS 203 if existingObj != nil { 204 if s.Preview { 205 existingPreview := existingObj.(*asocontainerservicev1preview.ManagedClustersAgentPool) 206 existingStatus = existingPreview.Status 207 hub := &asocontainerservicev1hub.ManagedClustersAgentPool{} 208 if err := existingPreview.ConvertTo(hub); err != nil { 209 return nil, err 210 } 211 stable := &asocontainerservicev1.ManagedClustersAgentPool{} 212 if err := stable.ConvertFrom(hub); err != nil { 213 return nil, err 214 } 215 existing = stable 216 } else { 217 existing = existingObj.(*asocontainerservicev1.ManagedClustersAgentPool) 218 } 219 } 220 221 agentPool := existing 222 if agentPool == nil { 223 agentPool = &asocontainerservicev1.ManagedClustersAgentPool{} 224 } 225 226 agentPool.Spec.AzureName = s.AzureName 227 agentPool.Spec.Owner = &genruntime.KnownResourceReference{ 228 Name: s.Cluster, 229 } 230 agentPool.Spec.AvailabilityZones = s.AvailabilityZones 231 agentPool.Spec.Count = &s.Replicas 232 agentPool.Spec.EnableAutoScaling = ptr.To(s.EnableAutoScaling) 233 agentPool.Spec.EnableUltraSSD = s.EnableUltraSSD 234 agentPool.Spec.KubeletDiskType = azure.AliasOrNil[asocontainerservicev1.KubeletDiskType]((*string)(s.KubeletDiskType)) 235 agentPool.Spec.MaxCount = s.MaxCount 236 agentPool.Spec.MaxPods = s.MaxPods 237 agentPool.Spec.MinCount = s.MinCount 238 agentPool.Spec.Mode = ptr.To(asocontainerservicev1.AgentPoolMode(s.Mode)) 239 agentPool.Spec.NodeLabels = s.NodeLabels 240 agentPool.Spec.NodeTaints = s.NodeTaints 241 agentPool.Spec.OsDiskSizeGB = ptr.To(asocontainerservicev1.ContainerServiceOSDisk(s.OSDiskSizeGB)) 242 agentPool.Spec.OsDiskType = azure.AliasOrNil[asocontainerservicev1.OSDiskType](s.OsDiskType) 243 agentPool.Spec.OsType = azure.AliasOrNil[asocontainerservicev1.OSType](s.OSType) 244 agentPool.Spec.ScaleSetPriority = azure.AliasOrNil[asocontainerservicev1.ScaleSetPriority](s.ScaleSetPriority) 245 agentPool.Spec.ScaleDownMode = azure.AliasOrNil[asocontainerservicev1.ScaleDownMode](s.ScaleDownMode) 246 agentPool.Spec.Type = ptr.To(asocontainerservicev1.AgentPoolType_VirtualMachineScaleSets) 247 agentPool.Spec.EnableNodePublicIP = s.EnableNodePublicIP 248 agentPool.Spec.Tags = s.AdditionalTags 249 agentPool.Spec.EnableFIPS = s.EnableFIPS 250 agentPool.Spec.EnableEncryptionAtHost = s.EnableEncryptionAtHost 251 if kubernetesVersion := s.getManagedMachinePoolVersion(existing); kubernetesVersion != nil { 252 agentPool.Spec.OrchestratorVersion = kubernetesVersion 253 } 254 255 if s.KubeletConfig != nil { 256 agentPool.Spec.KubeletConfig = &asocontainerservicev1.KubeletConfig{ 257 CpuManagerPolicy: s.KubeletConfig.CPUManagerPolicy, 258 CpuCfsQuota: s.KubeletConfig.CPUCfsQuota, 259 CpuCfsQuotaPeriod: s.KubeletConfig.CPUCfsQuotaPeriod, 260 ImageGcHighThreshold: s.KubeletConfig.ImageGcHighThreshold, 261 ImageGcLowThreshold: s.KubeletConfig.ImageGcLowThreshold, 262 TopologyManagerPolicy: s.KubeletConfig.TopologyManagerPolicy, 263 FailSwapOn: s.KubeletConfig.FailSwapOn, 264 ContainerLogMaxSizeMB: s.KubeletConfig.ContainerLogMaxSizeMB, 265 ContainerLogMaxFiles: s.KubeletConfig.ContainerLogMaxFiles, 266 PodMaxPids: s.KubeletConfig.PodMaxPids, 267 AllowedUnsafeSysctls: s.KubeletConfig.AllowedUnsafeSysctls, 268 } 269 } 270 271 if s.SKU != "" { 272 agentPool.Spec.VmSize = &s.SKU 273 } 274 275 if s.SpotMaxPrice != nil { 276 agentPool.Spec.SpotMaxPrice = ptr.To(s.SpotMaxPrice.AsApproximateFloat64()) 277 } 278 279 if s.VnetSubnetID != "" { 280 agentPool.Spec.VnetSubnetReference = &genruntime.ResourceReference{ 281 ARMID: s.VnetSubnetID, 282 } 283 } 284 285 if s.NodePublicIPPrefixID != "" { 286 agentPool.Spec.NodePublicIPPrefixReference = &genruntime.ResourceReference{ 287 ARMID: s.NodePublicIPPrefixID, 288 } 289 } 290 291 if s.LinuxOSConfig != nil { 292 agentPool.Spec.LinuxOSConfig = &asocontainerservicev1.LinuxOSConfig{ 293 SwapFileSizeMB: s.LinuxOSConfig.SwapFileSizeMB, 294 TransparentHugePageEnabled: (*string)(s.LinuxOSConfig.TransparentHugePageEnabled), 295 TransparentHugePageDefrag: (*string)(s.LinuxOSConfig.TransparentHugePageDefrag), 296 } 297 if s.LinuxOSConfig.Sysctls != nil { 298 agentPool.Spec.LinuxOSConfig.Sysctls = &asocontainerservicev1.SysctlConfig{ 299 FsAioMaxNr: s.LinuxOSConfig.Sysctls.FsAioMaxNr, 300 FsFileMax: s.LinuxOSConfig.Sysctls.FsFileMax, 301 FsInotifyMaxUserWatches: s.LinuxOSConfig.Sysctls.FsInotifyMaxUserWatches, 302 FsNrOpen: s.LinuxOSConfig.Sysctls.FsNrOpen, 303 KernelThreadsMax: s.LinuxOSConfig.Sysctls.KernelThreadsMax, 304 NetCoreNetdevMaxBacklog: s.LinuxOSConfig.Sysctls.NetCoreNetdevMaxBacklog, 305 NetCoreOptmemMax: s.LinuxOSConfig.Sysctls.NetCoreOptmemMax, 306 NetCoreRmemDefault: s.LinuxOSConfig.Sysctls.NetCoreRmemDefault, 307 NetCoreRmemMax: s.LinuxOSConfig.Sysctls.NetCoreRmemMax, 308 NetCoreSomaxconn: s.LinuxOSConfig.Sysctls.NetCoreSomaxconn, 309 NetCoreWmemDefault: s.LinuxOSConfig.Sysctls.NetCoreWmemDefault, 310 NetCoreWmemMax: s.LinuxOSConfig.Sysctls.NetCoreWmemMax, 311 NetIpv4IpLocalPortRange: s.LinuxOSConfig.Sysctls.NetIpv4IPLocalPortRange, 312 NetIpv4NeighDefaultGcThresh1: s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh1, 313 NetIpv4NeighDefaultGcThresh2: s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh2, 314 NetIpv4NeighDefaultGcThresh3: s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh3, 315 NetIpv4TcpFinTimeout: s.LinuxOSConfig.Sysctls.NetIpv4TCPFinTimeout, 316 NetIpv4TcpKeepaliveProbes: s.LinuxOSConfig.Sysctls.NetIpv4TCPKeepaliveProbes, 317 NetIpv4TcpKeepaliveTime: s.LinuxOSConfig.Sysctls.NetIpv4TCPKeepaliveTime, 318 NetIpv4TcpMaxSynBacklog: s.LinuxOSConfig.Sysctls.NetIpv4TCPMaxSynBacklog, 319 NetIpv4TcpMaxTwBuckets: s.LinuxOSConfig.Sysctls.NetIpv4TCPMaxTwBuckets, 320 NetIpv4TcpTwReuse: s.LinuxOSConfig.Sysctls.NetIpv4TCPTwReuse, 321 NetIpv4TcpkeepaliveIntvl: s.LinuxOSConfig.Sysctls.NetIpv4TCPkeepaliveIntvl, 322 NetNetfilterNfConntrackBuckets: s.LinuxOSConfig.Sysctls.NetNetfilterNfConntrackBuckets, 323 NetNetfilterNfConntrackMax: s.LinuxOSConfig.Sysctls.NetNetfilterNfConntrackMax, 324 VmMaxMapCount: s.LinuxOSConfig.Sysctls.VMMaxMapCount, 325 VmSwappiness: s.LinuxOSConfig.Sysctls.VMSwappiness, 326 VmVfsCachePressure: s.LinuxOSConfig.Sysctls.VMVfsCachePressure, 327 } 328 } 329 } 330 331 // When autoscaling is set, the count of the nodes differ based on the autoscaler and should not depend on the 332 // count present in MachinePool or AzureManagedMachinePool, hence we should not make an update API call based 333 // on difference in count. 334 if s.EnableAutoScaling && agentPool.Status.Count != nil { 335 agentPool.Spec.Count = agentPool.Status.Count 336 } 337 338 if s.Preview { 339 hub := &asocontainerservicev1hub.ManagedClustersAgentPool{} 340 if err := agentPool.ConvertTo(hub); err != nil { 341 return nil, err 342 } 343 prev := &asocontainerservicev1preview.ManagedClustersAgentPool{} 344 if err := prev.ConvertFrom(hub); err != nil { 345 return nil, err 346 } 347 if existing != nil { 348 prev.Status = existingStatus 349 } 350 return prev, nil 351 } 352 353 return agentPool, nil 354 } 355 356 // WasManaged implements azure.ASOResourceSpecGetter. 357 func (s *AgentPoolSpec) WasManaged(resource genruntime.MetaObject) bool { 358 // CAPZ has never supported BYO agent pools. 359 return true 360 } 361 362 var _ aso.Patcher = (*AgentPoolSpec)(nil) 363 364 // ExtraPatches implements aso.Patcher. 365 func (s *AgentPoolSpec) ExtraPatches() []string { 366 return s.Patches 367 }