Skip to content

Commit fc6512a

Browse files
mrclrchtrclaude
andcommitted
feat: add Kubernetes taints support for worker nodes
- Add taints field to worker_nodes variable for workload isolation - Implement registerWithTaints in kubelet configuration per Talos best practices - Update README with taint configuration examples - Add taints to both legacy and new worker configurations - Remove unused debug variable in talos_patch_worker.tf Based on Talos discussion #9895, taints are applied at node registration using kubelet.registerWithTaints to comply with NodeRestriction admission. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 3ca1fbf commit fc6512a

File tree

4 files changed

+53
-16
lines changed

4 files changed

+53
-16
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,20 @@ module "talos" {
234234
"node.kubernetes.io/instance-type" = "cx22"
235235
}
236236
},
237-
# ARM workers for specific workloads
237+
# ARM workers for specific workloads with taints
238238
{
239239
type = "cax22"
240240
labels = {
241241
"node.kubernetes.io/arch" = "arm64"
242242
"affinity.example.com" = "example"
243243
}
244+
taints = [
245+
{
246+
key = "arm64-only"
247+
value = "true"
248+
effect = "NoSchedule"
249+
}
250+
]
244251
}
245252
]
246253
}
@@ -250,6 +257,7 @@ module "talos" {
250257
> The `worker_nodes` variable allows you to:
251258
> - Mix different server types (x86 and ARM)
252259
> - Add custom labels to nodes
260+
> - Apply taints for workload isolation
253261
> - Control the count of each node type independently
254262
>
255263
> The legacy `worker_count` and `worker_server_type` variables are still supported for backward compatibility but are deprecated in favor of `worker_nodes`.

server.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ locals {
4141
ipv6_public_subnet = var.enable_ipv6 ? local.worker_public_ipv6_subnet_list[i] : null
4242
ipv4_private = local.worker_private_ipv4_list[i]
4343
labels = {}
44+
taints = []
4445
node_group_index = 0
4546
node_in_group_index = i
4647
}
@@ -62,6 +63,7 @@ locals {
6263
ipv6_public_subnet = var.enable_ipv6 ? local.worker_public_ipv6_subnet_list[local.legacy_worker_count + i] : null
6364
ipv4_private = local.worker_private_ipv4_list[local.legacy_worker_count + i]
6465
labels = worker.labels
66+
taints = worker.taints
6567
}
6668
]
6769

talos_patch_worker.tf

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ locals {
1010
ipv6_public_subnet = null # Fallback
1111
ipv4_private = cidrhost(local.node_ipv4_cidr, 200) # Use a predictable dummy private IP
1212
labels = {}
13+
taints = []
1314
node_group_index = 0
1415
node_in_group_index = 0
1516
}] : []
@@ -29,20 +30,34 @@ locals {
2930
]
3031
}
3132
certSANs = local.cert_SANs
32-
kubelet = {
33-
extraArgs = merge(
34-
{
35-
"cloud-provider" = "external"
36-
"rotate-server-certificates" = true
37-
},
38-
var.kubelet_extra_args
39-
)
40-
nodeIP = {
41-
validSubnets = [
42-
local.node_ipv4_cidr
43-
]
44-
}
45-
}
33+
kubelet = merge(
34+
{
35+
extraArgs = merge(
36+
{
37+
"cloud-provider" = "external"
38+
"rotate-server-certificates" = true
39+
},
40+
var.kubelet_extra_args
41+
)
42+
nodeIP = {
43+
validSubnets = [
44+
local.node_ipv4_cidr
45+
]
46+
}
47+
},
48+
# Add registerWithTaints if taints are defined
49+
length(worker.taints) > 0 ? {
50+
extraConfig = {
51+
registerWithTaints = [
52+
for taint in worker.taints : {
53+
key = taint.key
54+
value = taint.value
55+
effect = taint.effect
56+
}
57+
]
58+
}
59+
} : {}
60+
)
4661
network = {
4762
extraHostEntries = local.extra_host_entries
4863
kubespan = {
@@ -95,5 +110,4 @@ locals {
95110
}
96111
}
97112
}
98-
value = ""
99113
}

variables.tf

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,19 @@ variable "worker_nodes" {
248248
type = list(object({
249249
type = string
250250
labels = optional(map(string), {})
251+
taints = optional(list(object({
252+
key = string
253+
value = string
254+
effect = string
255+
})), [])
251256
}))
252257
default = []
253258
description = <<EOF
254259
List of worker node configurations. Each object defines a group of worker nodes with the same configuration.
255260
- type: Server type (cx11, cx21, cx22, cx31, cx32, cx41, cx42, cx51, cx52, cpx11, cpx21, cpx31, cpx41, cpx51, cax11, cax21, cax31, cax41, ccx13, ccx23, ccx33, ccx43, ccx53, ccx63)
256261
- count: Number of nodes of this type
257262
- labels: Map of Kubernetes labels to apply to these nodes (default: {})
263+
- taints: List of Kubernetes taints to apply to these nodes (default: [])
258264
259265
Example:
260266
worker_nodes = [
@@ -266,6 +272,13 @@ variable "worker_nodes" {
266272
labels = {
267273
"node.kubernetes.io/arch" = "arm64"
268274
}
275+
taints = [
276+
{
277+
key = "workload-type"
278+
value = "gpu"
279+
effect = "NoSchedule"
280+
}
281+
]
269282
}
270283
]
271284
EOF

0 commit comments

Comments
 (0)