Skip to content

Commit e8ffb2e

Browse files
authored
Add node taint config (#137)
1 parent 7b1773a commit e8ffb2e

8 files changed

Lines changed: 85 additions & 45 deletions

File tree

components/kubelet/action.pb.go

Lines changed: 59 additions & 41 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/kubelet/action.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ message StartKubeletServiceSpec {
6969
NodeAuthInfo node_auth_info = 2;
7070
map<string, string> node_labels = 3;
7171
KubeletConfig kubelet_config = 4;
72+
repeated string register_with_taints = 5;
7273
}
7374

7475
message StartKubeletServiceStatus {

components/kubelet/v20260301/assets/20-flex-node-node-config.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
# You may create a higher-numbered drop-in (e.g. 90-custom-node-config.conf)
55
# to append or override individual env vars.
66
[Service]
7-
Environment="KUBELET_NODE_CONFIG_ARGS=--node-labels={{.NodeLabels}} --v={{.Verbosity}} --client-ca-file={{.ClientCAFile}}{{range .ClusterDNS}} --cluster-dns={{.}}{{end}}"
7+
Environment="KUBELET_NODE_CONFIG_ARGS=--node-labels={{.NodeLabels}} --v={{.Verbosity}} --client-ca-file={{.ClientCAFile}}{{range .ClusterDNS}} --cluster-dns={{.}}{{end}}{{if .RegisterWithTaints}} --register-with-taints={{.RegisterWithTaints}}{{end}}"
88
Environment="KUBELET_TUNING_ARGS=--eviction-hard={{.EvictionHard}} --kube-reserved={{.KubeReserved}} --image-gc-high-threshold={{.ImageGCHighThreshold}} --image-gc-low-threshold={{.ImageGCLowThreshold}} --max-pods={{.MaxPods}}"

components/kubelet/v20260301/kubelet_service.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package v20260301
33
import (
44
"bytes"
55
"context"
6+
"strings"
67

78
"github.com/Azure/AKSFlexNode/components/kubelet"
89
"github.com/Azure/AKSFlexNode/pkg/config"
@@ -74,6 +75,7 @@ func (s *startKubeletServiceAction) ensureSystemdUnit(
7475
"Verbosity": kubeletConfig.GetVerbosity(),
7576
"ClientCAFile": apiServerClientCAPath, // prepared in ensureAPIServerCA
7677
"ClusterDNS": kubeletConfig.GetClusterDns(),
78+
"RegisterWithTaints": strings.Join(spec.GetRegisterWithTaints(), ","),
7779
"EvictionHard": mapPairsToString(kubeletConfig.GetEvictionHard(), "<", ","),
7880
"KubeReserved": mapPairsToString(kubeletConfig.GetKubeReserved(), "=", ","),
7981
"ImageGCHighThreshold": kubeletConfig.GetImageGcHighThreshold(),

pkg/bootstrapper/components.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,9 @@ var startKubelet resolveActionFunc[*kubelet.StartKubeletService] = func(
286286
Server: ptr(cfg.Node.Kubelet.ServerURL),
287287
CertificateAuthorityData: caData,
288288
}.Build(),
289-
NodeAuthInfo: nodeAuthInfo.Build(),
290-
NodeLabels: maps.Clone(cfg.Node.Labels),
289+
NodeAuthInfo: nodeAuthInfo.Build(),
290+
NodeLabels: maps.Clone(cfg.Node.Labels),
291+
RegisterWithTaints: append([]string(nil), cfg.Node.Taints...),
291292
KubeletConfig: kubelet.KubeletConfig_builder{
292293
KubeReserved: maps.Clone(cfg.Node.Kubelet.KubeReserved),
293294
EvictionHard: maps.Clone(cfg.Node.Kubelet.EvictionHard),
@@ -358,6 +359,7 @@ var ensureMachine resolveActionFunc[*aksmachine.EnsureMachine] = func(
358359
KubernetesVersion: ptr(cfg.Kubernetes.Version),
359360
MaxPods: ptr(int32(cfg.Node.MaxPods)),
360361
NodeLabels: maps.Clone(cfg.Node.Labels),
362+
NodeTaints: append([]string(nil), cfg.Node.Taints...),
361363
KubeletConfig: kubeletCfg,
362364
Enabled: ptr(cfg.IsDriftDetectionAndRemediationEnabled()),
363365
AzureCredential: azureCred,

pkg/config/copy.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ func (cfg *Config) DeepCopy() *Config {
4545

4646
// Copy node-level maps.
4747
out.Node.Labels = cloneStringMap(cfg.Node.Labels)
48+
if cfg.Node.Taints != nil {
49+
out.Node.Taints = append([]string(nil), cfg.Node.Taints...)
50+
}
4851
out.Node.Kubelet.KubeReserved = cloneStringMap(cfg.Node.Kubelet.KubeReserved)
4952
out.Node.Kubelet.EvictionHard = cloneStringMap(cfg.Node.Kubelet.EvictionHard)
5053

pkg/config/copy_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func TestConfigDeepCopy_DoesNotSharePointersOrMaps(t *testing.T) {
5252
Agent: AgentConfig{EnableDriftDetectionAndRemediation: &falseVal},
5353
Node: NodeConfig{
5454
Labels: map[string]string{"l": "1"},
55+
Taints: []string{"dedicated=infra:NoSchedule"},
5556
Kubelet: KubeletConfig{
5657
KubeReserved: map[string]string{"cpu": "100m"},
5758
EvictionHard: map[string]string{"memory.available": "200Mi"},
@@ -103,6 +104,15 @@ func TestConfigDeepCopy_DoesNotSharePointersOrMaps(t *testing.T) {
103104
t.Fatalf("Node.Labels shared; orig=%q, want %q", cfg.Node.Labels["l"], "orig")
104105
}
105106

107+
// Taints slice should not be shared.
108+
if len(copy.Node.Taints) != 1 || copy.Node.Taints[0] != "dedicated=infra:NoSchedule" {
109+
t.Fatalf("Node.Taints copy=%v, want [dedicated=infra:NoSchedule]", copy.Node.Taints)
110+
}
111+
cfg.Node.Taints[0] = "mutated:NoExecute"
112+
if copy.Node.Taints[0] != "dedicated=infra:NoSchedule" {
113+
t.Fatalf("Node.Taints shares backing array; copy=%q, want %q", copy.Node.Taints[0], "dedicated=infra:NoSchedule")
114+
}
115+
106116
cfg.Node.Kubelet.KubeReserved["cpu"] = "200m"
107117
if copy.Node.Kubelet.KubeReserved["cpu"] != "100m" {
108118
t.Fatalf("KubeReserved shared; copy=%q, want %q", copy.Node.Kubelet.KubeReserved["cpu"], "100m")

pkg/config/structs.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,11 @@ type ContainerdConfig struct {
119119
type NodeConfig struct {
120120
MaxPods int `json:"maxPods"`
121121
Labels map[string]string `json:"labels"`
122-
Kubelet KubeletConfig `json:"kubelet"`
122+
// Taints to apply at node registration time via --register-with-taints.
123+
// Each entry must use the kubelet taint format: "key=value:Effect" or "key:Effect"
124+
// (e.g. "dedicated=infra:NoSchedule", "gpu:NoExecute").
125+
Taints []string `json:"taints,omitempty"`
126+
Kubelet KubeletConfig `json:"kubelet"`
123127
}
124128

125129
// KubeletConfig holds kubelet-specific configuration settings.

0 commit comments

Comments
 (0)