Skip to content

Commit dd8cb73

Browse files
comtalystclaude
andcommitted
feat: add AzureNodeClass CRD at karpenter.azure.com/v1alpha1
Introduce a new AzureNodeClass CRD that provides a generic Azure VM node class, independent of AKS-specific concerns. This CRD supports custom images (imageID), verbatim user bootstrap data (userData), per-NodeClass managed identities, and standard Azure VM configuration. AzureNodeClass is intended for non-AKS control plane scenarios where the user manages their own bootstrap process, while AKSNodeClass continues to serve AKS-managed clusters. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a4c04d6 commit dd8cb73

File tree

8 files changed

+825
-0
lines changed

8 files changed

+825
-0
lines changed
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
---
2+
apiVersion: apiextensions.k8s.io/v1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
annotations:
6+
controller-gen.kubebuilder.io/version: v0.19.0
7+
name: azurenodeclasses.karpenter.azure.com
8+
spec:
9+
group: karpenter.azure.com
10+
names:
11+
categories:
12+
- karpenter
13+
kind: AzureNodeClass
14+
listKind: AzureNodeClassList
15+
plural: azurenodeclasses
16+
shortNames:
17+
- aznc
18+
- azncs
19+
singular: azurenodeclass
20+
scope: Cluster
21+
versions:
22+
- additionalPrinterColumns:
23+
- jsonPath: .status.conditions[?(@.type=='Ready')].status
24+
name: Ready
25+
type: string
26+
- jsonPath: .metadata.creationTimestamp
27+
name: Age
28+
type: date
29+
- jsonPath: .spec.imageID
30+
name: ImageID
31+
priority: 1
32+
type: string
33+
name: v1alpha1
34+
schema:
35+
openAPIV3Schema:
36+
description: |-
37+
AzureNodeClass is the Schema for the AzureNodeClass API.
38+
AzureNodeClass is a more generic node class for provisioning Azure VMs
39+
that are not necessarily managed by AKS. It supports custom images,
40+
custom bootstrap data (userData), and per-NodeClass identity configuration.
41+
properties:
42+
apiVersion:
43+
description: |-
44+
APIVersion defines the versioned schema of this representation of an object.
45+
Servers should convert recognized schemas to the latest internal value, and
46+
may reject unrecognized values.
47+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
48+
type: string
49+
kind:
50+
description: |-
51+
Kind is a string value representing the REST resource this object represents.
52+
Servers may infer this from the endpoint the client submits requests to.
53+
Cannot be updated.
54+
In CamelCase.
55+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
56+
type: string
57+
metadata:
58+
type: object
59+
spec:
60+
description: |-
61+
spec is the top level specification for the Azure Karpenter Provider.
62+
This will contain configuration necessary to launch instances in Azure.
63+
properties:
64+
imageID:
65+
description: |-
66+
imageID is the ARM resource ID of the image that instances use.
67+
This can be a Compute Gallery image, Shared Image Gallery image, or any valid Azure image resource ID.
68+
When set, imageFamily-based image resolution is bypassed entirely.
69+
The user is responsible for ensuring the image is compatible with the selected instance types.
70+
pattern: (?i)^\/subscriptions\/[^\/]+\/resourceGroups\/[^\/]+\/providers\/Microsoft\.(Compute|AzureHybridBenefit)\/.*$
71+
type: string
72+
managedIdentities:
73+
description: |-
74+
managedIdentities is a list of user-assigned managed identity resource IDs
75+
to attach to provisioned VMs. These are merged with any global identities
76+
configured via the --node-identities flag.
77+
items:
78+
type: string
79+
maxItems: 10
80+
type: array
81+
osDiskSizeGB:
82+
description: osDiskSizeGB is the size of the OS disk in GB.
83+
format: int32
84+
maximum: 4096
85+
minimum: 30
86+
type: integer
87+
security:
88+
description: security is a collection of security related karpenter
89+
fields.
90+
properties:
91+
encryptionAtHost:
92+
description: |-
93+
encryptionAtHost specifies whether host-level encryption is enabled for provisioned nodes.
94+
For more information, see:
95+
https://learn.microsoft.com/en-us/azure/virtual-machines/disk-encryption#encryption-at-host---end-to-end-encryption-for-your-vm-data
96+
type: boolean
97+
type: object
98+
tags:
99+
additionalProperties:
100+
type: string
101+
description: tags to be applied on Azure resources like instances.
102+
type: object
103+
x-kubernetes-validations:
104+
- message: tags keys must be less than 512 characters
105+
rule: self.all(k, size(k) <= 512)
106+
- message: tags keys must not contain '<', '>', '%', '&', or '?'
107+
rule: self.all(k, !k.matches('[<>%&?]'))
108+
- message: tags keys must not contain '\'
109+
rule: self.all(k, !k.contains('\\'))
110+
- message: tags values must be less than 256 characters
111+
rule: self.all(k, size(self[k]) <= 256)
112+
userData:
113+
description: |-
114+
userData is verbatim CustomData that will be passed to the VM at creation time.
115+
The Azure SDK will base64-encode this value before sending it to the Azure API.
116+
The user is fully responsible for providing valid bootstrap/cloud-init data.
117+
When this field is set, no Karpenter-managed bootstrapping is performed.
118+
type: string
119+
vnetSubnetID:
120+
description: |-
121+
vnetSubnetID is the subnet used by nics provisioned with this nodeclass.
122+
If not specified, we will use the default --vnet-subnet-id specified in karpenter's options config.
123+
pattern: (?i)^\/subscriptions\/[^\/]+\/resourceGroups\/[a-zA-Z0-9_\-().]{0,89}[a-zA-Z0-9_\-()]\/providers\/Microsoft\.Network\/virtualNetworks\/[^\/]+\/subnets\/[^\/]+$
124+
type: string
125+
type: object
126+
status:
127+
description: status contains the resolved state of the AzureNodeClass.
128+
properties:
129+
conditions:
130+
description: conditions contains signals for health and readiness
131+
items:
132+
description: Condition aliases the upstream type and adds additional
133+
helper methods
134+
properties:
135+
lastTransitionTime:
136+
description: |-
137+
lastTransitionTime is the last time the condition transitioned from one status to another.
138+
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
139+
format: date-time
140+
type: string
141+
message:
142+
description: |-
143+
message is a human readable message indicating details about the transition.
144+
This may be an empty string.
145+
maxLength: 32768
146+
type: string
147+
observedGeneration:
148+
description: |-
149+
observedGeneration represents the .metadata.generation that the condition was set based upon.
150+
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
151+
with respect to the current state of the instance.
152+
format: int64
153+
minimum: 0
154+
type: integer
155+
reason:
156+
description: |-
157+
reason contains a programmatic identifier indicating the reason for the condition's last transition.
158+
Producers of specific condition types may define expected values and meanings for this field,
159+
and whether the values are considered a guaranteed API.
160+
The value should be a CamelCase string.
161+
This field may not be empty.
162+
maxLength: 1024
163+
minLength: 1
164+
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
165+
type: string
166+
status:
167+
description: status of the condition, one of True, False, Unknown.
168+
enum:
169+
- "True"
170+
- "False"
171+
- Unknown
172+
type: string
173+
type:
174+
description: type of condition in CamelCase or in foo.example.com/CamelCase.
175+
maxLength: 316
176+
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
177+
type: string
178+
required:
179+
- lastTransitionTime
180+
- message
181+
- reason
182+
- status
183+
- type
184+
type: object
185+
type: array
186+
type: object
187+
type: object
188+
served: true
189+
storage: true
190+
subresources:
191+
status: {}

pkg/apis/apis.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ var (
3030
//CompatibilityGroup = "compatibility." + Group
3131
//go:embed crds/karpenter.azure.com_aksnodeclasses.yaml
3232
AKSNodeClassCRD []byte
33+
//go:embed crds/karpenter.azure.com_azurenodeclasses.yaml
34+
AzureNodeClassCRD []byte
3335
//go:embed crds/karpenter.sh_nodepools.yaml
3436
NodePoolCRD []byte
3537
//go:embed crds/karpenter.sh_nodeclaims.yaml
@@ -38,6 +40,7 @@ var (
3840
NodeOverlayCRD []byte
3941
CRDs = []*apiextensionsv1.CustomResourceDefinition{
4042
object.Unmarshal[apiextensionsv1.CustomResourceDefinition](AKSNodeClassCRD),
43+
object.Unmarshal[apiextensionsv1.CustomResourceDefinition](AzureNodeClassCRD),
4144
object.Unmarshal[apiextensionsv1.CustomResourceDefinition](NodePoolCRD),
4245
object.Unmarshal[apiextensionsv1.CustomResourceDefinition](NodeClaimCRD),
4346
object.Unmarshal[apiextensionsv1.CustomResourceDefinition](NodeOverlayCRD),

0 commit comments

Comments
 (0)