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