Skip to content

Commit dd7c2f1

Browse files
sylviah23AndrewSirenkoConnorJC3
committed
Add ALPHA metadata-labeler sidecar and metadata source
Co-authored-by: Drew Sirenko <[email protected]> Co-authored-by: Connor Catlett <[email protected]> Signed-off-by: Connor Catlett <[email protected]>
1 parent a3e3bd9 commit dd7c2f1

27 files changed

+2165
-173
lines changed

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,11 @@ e2e/multi-az: bin/helm bin/ginkgo
147147
.PHONY: e2e/disruptive
148148
e2e/disruptive: bin/helm bin/ginkgo
149149
TEST_PATH=./tests/e2e/... \
150-
GINKGO_FOCUS="\[ebs-csi-e2e\] \[disruptive\]" \
150+
GINKGO_FOCUS="\[ebs-csi-e2e\] \[Disruptive\]" \
151+
GINKGO_SKIP="\[Flaky\]" \
151152
GINKGO_PARALLEL=1 \
152153
EBS_INSTALL_SNAPSHOT=false \
154+
HELM_EXTRA_FLAGS="--set=sidecars.metadataLabeler.enabled=true,node.metadataSources='metadata-labeler'" \
153155
./hack/e2e/run.sh
154156

155157
.PHONY: e2e/external
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{{- if and (not .Values.nodeComponentOnly) (.Values.sidecars.metadataLabeler.enabled) -}}
2+
---
3+
kind: ClusterRole
4+
apiVersion: rbac.authorization.k8s.io/v1
5+
metadata:
6+
name: ebs-metadata-labeler-role
7+
labels:
8+
{{- include "aws-ebs-csi-driver.labels" . | nindent 4 }}
9+
rules:
10+
- apiGroups: [""]
11+
resources: ["nodes"]
12+
verbs: ["patch"]
13+
- apiGroups: [""]
14+
resources: ["persistentvolumes"]
15+
verbs: ["list", "watch", "get"]
16+
{{- end -}}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{{- if and (not .Values.nodeComponentOnly) (.Values.sidecars.metadataLabeler.enabled) -}}
2+
---
3+
kind: ClusterRoleBinding
4+
apiVersion: rbac.authorization.k8s.io/v1
5+
metadata:
6+
name: ebs-csi-metadata-labeler-binding
7+
labels:
8+
{{- include "aws-ebs-csi-driver.labels" . | nindent 4 }}
9+
subjects:
10+
- kind: ServiceAccount
11+
name: {{ .Values.controller.serviceAccount.name }}
12+
namespace: {{ .Release.Namespace }}
13+
roleRef:
14+
apiGroup: rbac.authorization.k8s.io
15+
kind: ClusterRole
16+
name: ebs-metadata-labeler-role
17+
{{- end -}}

charts/aws-ebs-csi-driver/templates/controller.yaml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,40 @@ spec:
489489
{{- end }}
490490
terminationMessagePolicy: FallbackToLogsOnError
491491
{{- end }}
492+
{{- if .Values.sidecars.metadataLabeler.enabled }}
493+
- name: metadata-labeler
494+
image: {{ include "aws-ebs-csi-driver.fullImagePath" $ }}
495+
imagePullPolicy: {{ .Values.image.pullPolicy }}
496+
args:
497+
- metadataLabeler
498+
- --v={{ .Values.sidecars.metadataLabeler.logLevel }}
499+
{{- range .Values.sidecars.metadataLabeler.additionalArgs }}
500+
- {{ . }}
501+
{{- end }}
502+
env:
503+
- name: CSI_NODE_NAME
504+
valueFrom:
505+
fieldRef:
506+
fieldPath: spec.nodeName
507+
{{- if .Values.proxy.http_proxy }}
508+
{{- include "aws-ebs-csi-driver.http-proxy" . | nindent 12 }}
509+
{{- end }}
510+
{{- with .Values.sidecars.metadataLabeler.env }}
511+
{{- . | toYaml | nindent 12 }}
512+
{{- end }}
513+
{{- with .Values.controller.envFrom }}
514+
envFrom:
515+
{{- . | toYaml | nindent 12 }}
516+
{{- end }}
517+
{{- with default .Values.controller.resources .Values.sidecars.metadataLabeler.resources }}
518+
resources:
519+
{{- toYaml . | nindent 12 }}
520+
{{- end }}
521+
{{- with .Values.sidecars.metadataLabeler.securityContext }}
522+
securityContext:
523+
{{- toYaml . | nindent 12 }}
524+
{{- end }}
525+
{{- end }}
492526
- name: csi-resizer
493527
image: {{ printf "%s%s:%s" (default "" .Values.image.containerRegistry) .Values.sidecars.resizer.image.repository .Values.sidecars.resizer.image.tag }}
494528
imagePullPolicy: {{ default .Values.image.pullPolicy .Values.sidecars.resizer.image.pullPolicy }}

charts/aws-ebs-csi-driver/templates/csidriver.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ spec:
99
attachRequired: true
1010
podInfoOnMount: false
1111
{{- if semverCompare ">=1.33.0-0" .Capabilities.KubeVersion.Version }}
12-
{{- with .Values.nodeAllocatableUpdatePeriodSeconds }}
13-
nodeAllocatableUpdatePeriodSeconds: {{ . }}
12+
{{- if eq (.Values.nodeAllocatableUpdatePeriodSeconds | int) -1 }}
13+
nodeAllocatableUpdatePeriodSeconds: {{ (regexMatch "metadata-labeler" (.Values.node.metadataSources | default "")) | ternary "300" "10" }}
14+
{{- else if .Values.nodeAllocatableUpdatePeriodSeconds }}
15+
nodeAllocatableUpdatePeriodSeconds: {{ .Values.nodeAllocatableUpdatePeriodSeconds }}
1416
{{- end }}
1517
{{- end }}
1618
{{- if not .Values.useOldCSIDriver }}

charts/aws-ebs-csi-driver/values.schema.json

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@
108108
},
109109
"nodeAllocatableUpdatePeriodSeconds": {
110110
"type": ["integer", "null"],
111-
"description": "nodeAllocatableUpdatePeriodSeconds updates the node's max attachable volume count by directing Kubelet to periodically call NodeGetInfo at the configured interval. Kubernetes enforces a minimum update interval of 10 seconds. This parameter is supported in Kubernetes 1.33+, the MutableCSINodeAllocatableCount feature gate must be enabled in kubelet and kube-apiserver.",
112-
"default": 10
111+
"description": "nodeAllocatableUpdatePeriodSeconds updates the node's max attachable volume count by directing Kubelet to periodically call NodeGetInfo at the configured interval. Kubernetes enforces a minimum update interval of 10 seconds. A value of -1 uses a automatically determined value dependent on metadata sources. This parameter is supported in Kubernetes 1.33+, the MutableCSINodeAllocatableCount feature gate must be enabled in kubelet and kube-apiserver.",
112+
"default": -1
113113
},
114114
"nodeComponentOnly": {
115115
"type": "boolean",
@@ -673,7 +673,7 @@
673673
"default": false
674674
},
675675
"metadataSources": {
676-
"description": "Comma separated list of metadata sources that override the default used by the EBS CSI Driver. Valid sources include 'imds' and 'kubernetes'",
676+
"description": "Comma separated list of metadata sources that override the default used by the EBS CSI Driver. Valid sources include 'imds', 'kubernetes', and (ALPHA) 'metadata-labeler'",
677677
"type": ["string", "null"],
678678
"default": null
679679
},
@@ -1163,6 +1163,41 @@
11631163
}
11641164
}
11651165
},
1166+
"metadataLabeler": {
1167+
"type": "object",
1168+
"additionalProperties": false,
1169+
"properties": {
1170+
"additionalArgs": {
1171+
"type": "array",
1172+
"description": "Additional arguments passed to the metadataLabeler container",
1173+
"default": [],
1174+
"items": {
1175+
"type": "string"
1176+
}
1177+
},
1178+
"resources": {
1179+
"type": ["object", "null"],
1180+
"default": null
1181+
},
1182+
"enabled": {
1183+
"type": "boolean",
1184+
"description": "ALPHA: Enable the metadata-labeler sidecar to label Kubernetes Nodes with information from the EC2 API (e.g. number of ENIs). Also requires using metadata-labeler as the node's metadata source.",
1185+
"default": false
1186+
},
1187+
"logLevel": {
1188+
"type": "integer",
1189+
"description": "Set the level of verbosity of the logs",
1190+
"default": 4
1191+
},
1192+
"env": {
1193+
"type": "array",
1194+
"default": []
1195+
},
1196+
"securityContext": {
1197+
"type": "object"
1198+
}
1199+
}
1200+
},
11661201
"volumemodifier": {
11671202
"type": "object",
11681203
"additionalProperties": false,

charts/aws-ebs-csi-driver/values.yaml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ sidecars:
9090
type: RuntimeDefault
9191
readOnlyRootFilesystem: true
9292
allowPrivilegeEscalation: false
93+
metadataLabeler:
94+
# ALPHA: Enable the metadata-labeler sidecar to label Kubernetes Nodes with
95+
# information from the EC2 API (e.g. number of ENIs)
96+
# Also requires using metadata-labeler as the node's metadata source
97+
enabled: false
98+
logLevel: 2
99+
# Additional parameters provided by metadataLabeler.
100+
additionalArgs: []
101+
resources: {}
102+
securityContext:
103+
readOnlyRootFilesystem: true
104+
allowPrivilegeEscalation: false
93105
livenessProbe:
94106
image:
95107
pullPolicy: IfNotPresent
@@ -425,6 +437,7 @@ node:
425437
# Enable the linux daemonset creation
426438
enableLinux: true
427439
enableWindows: true
440+
# Comma separated list of metadata sources that override the default used by the EBS CSI Driver. Valid sources include 'imds', 'kubernetes', and (ALPHA) 'metadata-labeler'
428441
metadataSources:
429442
# Warning: This option will be removed in a future release. It is a temporary workaround for users unable to immediately migrate off of older kernel versions.
430443
# Formats XFS volumes with bigtime=0,inobtcount=0,reflink=0, for mounting onto nodes with linux kernel version <= 5.4.
@@ -527,9 +540,9 @@ volumeSnapshotClasses: []
527540
# This parameter should always be false for new installations
528541
useOldCSIDriver: false
529542
# nodeAllocatableUpdatePeriodSeconds updates the node's max attachable volume count by directing Kubelet to periodically call NodeGetInfo at the configured interval.
530-
# Kubernetes enforces a minimum update interval of 10 seconds.
543+
# Kubernetes enforces a minimum update interval of 10 seconds. A value of -1 uses a automatically determined value dependent on metadata sources.
531544
# This parameter is supported in Kubernetes 1.33+ and requires the MutableCSINodeAllocatableCount feature gate to be enabled in kubelet and kube-apiserver.
532-
nodeAllocatableUpdatePeriodSeconds: 10
545+
nodeAllocatableUpdatePeriodSeconds: -1
533546
# Deploy EBS CSI Driver without controller and associated resources
534547
nodeComponentOnly: false
535548
# Set maximum verbosity for logs of each container and other recommended debugging parameters such as enabling AWS SDK debug logging

cmd/main.go

Lines changed: 77 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ import (
2424
"time"
2525

2626
"github.com/kubernetes-sigs/aws-ebs-csi-driver/cmd/hooks"
27-
"github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/cloud"
27+
cloudPkg "github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/cloud"
2828
"github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/cloud/metadata"
2929
"github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/driver"
3030
"github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/metrics"
3131
"github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/mounter"
3232
flag "github.com/spf13/pflag"
33+
"k8s.io/client-go/kubernetes"
3334
"k8s.io/component-base/featuregate"
3435
logsapi "k8s.io/component-base/logs/api/v1"
3536
json "k8s.io/component-base/logs/json"
@@ -54,6 +55,15 @@ func main() {
5455
options = driver.Options{}
5556
)
5657

58+
var (
59+
metadataRequiredModes = map[string]struct{}{
60+
string(driver.ControllerMode): {},
61+
string(driver.NodeMode): {},
62+
string(driver.AllMode): {},
63+
driver.MetadataLabelerMode: {},
64+
}
65+
)
66+
5767
c := logsapi.NewLoggingConfiguration()
5868
err := logsapi.AddFeatureGates(featureGate)
5969
if err != nil {
@@ -66,6 +76,65 @@ func main() {
6676
args = os.Args[2:]
6777
}
6878

79+
options.Mode = driver.Mode(cmd)
80+
options.AddFlags(fs)
81+
82+
if err := fs.Parse(args); err != nil {
83+
klog.ErrorS(err, "Failed to parse options")
84+
klog.FlushAndExit(klog.ExitFlushTimeout, 0)
85+
}
86+
if err := options.Validate(); err != nil {
87+
klog.ErrorS(err, "Invalid options")
88+
klog.FlushAndExit(klog.ExitFlushTimeout, 0)
89+
}
90+
91+
err = logsapi.ValidateAndApply(c, featureGate)
92+
if err != nil {
93+
klog.ErrorS(err, "failed to validate and apply logging configuration")
94+
}
95+
96+
var cloud cloudPkg.Cloud
97+
var k8sClient kubernetes.Interface
98+
var md metadata.MetadataService
99+
cfg := metadata.MetadataServiceConfig{
100+
MetadataSources: options.MetadataSources,
101+
IMDSClient: metadata.DefaultIMDSClient,
102+
K8sAPIClient: metadata.DefaultKubernetesAPIClient(options.Kubeconfig),
103+
}
104+
105+
if _, ok := metadataRequiredModes[cmd]; ok {
106+
region := os.Getenv("AWS_REGION")
107+
var metadataErr error
108+
109+
if region != "" {
110+
klog.InfoS("Region provided via AWS_REGION environment variable", "region", region)
111+
if options.Mode != driver.ControllerMode {
112+
klog.InfoS("Node service requires metadata even if AWS_REGION provided, initializing metadata")
113+
md, metadataErr = metadata.NewMetadataService(cfg, region)
114+
}
115+
} else {
116+
klog.InfoS("Initializing metadata")
117+
md, metadataErr = metadata.NewMetadataService(cfg, region)
118+
}
119+
120+
if metadataErr != nil {
121+
klog.ErrorS(metadataErr, "Failed to initialize metadata when it is required")
122+
if options.Mode == driver.ControllerMode {
123+
klog.InfoS("The region can be manually supplied via the AWS_REGION environment variable")
124+
}
125+
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
126+
} else if region == "" {
127+
region = md.GetRegion()
128+
}
129+
130+
cloud = cloudPkg.NewCloud(region, options.AwsSdkDebugLog, options.UserAgentExtra, options.Batching, options.DeprecatedMetrics)
131+
}
132+
133+
k8sClient, err = cfg.K8sAPIClient()
134+
if err != nil {
135+
klog.V(2).InfoS("Failed to setup k8s client", "err", err)
136+
}
137+
69138
switch cmd {
70139
case "pre-stop-hook":
71140
clientset, clientErr := metadata.DefaultKubernetesAPIClient(options.Kubeconfig)()
@@ -80,28 +149,17 @@ func main() {
80149
}
81150
klog.FlushAndExit(klog.ExitFlushTimeout, 0)
82151
case string(driver.ControllerMode), string(driver.NodeMode), string(driver.AllMode):
83-
options.Mode = driver.Mode(cmd)
152+
case driver.MetadataLabelerMode:
153+
err := metadata.ContinuousUpdateLabelsLeaderElection(k8sClient, cloud, metadata.ControllerMetadataLabelerInterval)
154+
if err != nil {
155+
klog.ErrorS(err, "failed to patch volume/ENI count on node labels")
156+
klog.FlushAndExit(klog.ExitFlushTimeout, 0)
157+
}
84158
default:
85-
klog.Errorf("Unknown driver mode %s: Expected %s, %s, %s, or pre-stop-hook", cmd, driver.ControllerMode, driver.NodeMode, driver.AllMode)
159+
klog.Errorf("Unknown driver mode %s: Expected %s, %s, %s, %s, or pre-stop-hook", cmd, driver.ControllerMode, driver.NodeMode, driver.AllMode, driver.MetadataLabelerMode)
86160
klog.FlushAndExit(klog.ExitFlushTimeout, 0)
87161
}
88162

89-
options.AddFlags(fs)
90-
91-
if err = fs.Parse(args); err != nil {
92-
klog.ErrorS(err, "Failed to parse options")
93-
klog.FlushAndExit(klog.ExitFlushTimeout, 0)
94-
}
95-
if err = options.Validate(); err != nil {
96-
klog.ErrorS(err, "Invalid options")
97-
klog.FlushAndExit(klog.ExitFlushTimeout, 0)
98-
}
99-
100-
err = logsapi.ValidateAndApply(c, featureGate)
101-
if err != nil {
102-
klog.ErrorS(err, "failed to validate and apply logging configuration")
103-
}
104-
105163
if *version {
106164
versionInfo, versionErr := driver.GetVersionJSON()
107165
if versionErr != nil {
@@ -134,27 +192,6 @@ func main() {
134192
}()
135193
}
136194

137-
cfg := metadata.MetadataServiceConfig{
138-
MetadataSources: options.MetadataSources,
139-
IMDSClient: metadata.DefaultIMDSClient,
140-
K8sAPIClient: metadata.DefaultKubernetesAPIClient(options.Kubeconfig),
141-
}
142-
143-
region := os.Getenv("AWS_REGION")
144-
var md metadata.MetadataService
145-
var metadataErr error
146-
147-
if region != "" {
148-
klog.InfoS("Region provided via AWS_REGION environment variable", "region", region)
149-
if options.Mode != driver.ControllerMode {
150-
klog.InfoS("Node service requires metadata even if AWS_REGION provided, initializing metadata")
151-
md, metadataErr = metadata.NewMetadataService(cfg, region)
152-
}
153-
} else {
154-
klog.InfoS("Initializing metadata")
155-
md, metadataErr = metadata.NewMetadataService(cfg, region)
156-
}
157-
158195
if options.HTTPEndpoint != "" {
159196
r := metrics.InitializeRecorder(options.DeprecatedMetrics)
160197
r.InitializeMetricsHandler(options.HTTPEndpoint, "/metrics", options.MetricsCertFile, options.MetricsKeyFile)
@@ -169,29 +206,12 @@ func main() {
169206
}
170207
}
171208

172-
if metadataErr != nil {
173-
klog.ErrorS(metadataErr, "Failed to initialize metadata when it is required")
174-
if options.Mode == driver.ControllerMode {
175-
klog.InfoS("The region can be manually supplied via the AWS_REGION environment variable")
176-
}
177-
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
178-
} else if region == "" {
179-
region = md.GetRegion()
180-
}
181-
182-
cloud := cloud.NewCloud(region, options.AwsSdkDebugLog, options.UserAgentExtra, options.Batching, options.DeprecatedMetrics)
183-
184209
m, err := mounter.NewNodeMounter(options.WindowsHostProcess)
185210
if err != nil {
186211
klog.ErrorS(err, "failed to create node mounter")
187212
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
188213
}
189214

190-
k8sClient, err := cfg.K8sAPIClient()
191-
if err != nil {
192-
klog.V(2).InfoS("Failed to setup k8s client", "err", err)
193-
}
194-
195215
drv, err := driver.NewDriver(cloud, &options, m, md, k8sClient)
196216
if err != nil {
197217
klog.ErrorS(err, "failed to create driver")

0 commit comments

Comments
 (0)