Skip to content

Commit e96dfc0

Browse files
authored
Merge pull request #2388 from CatherineF-dev/patch-11
fix: use --track-unscheduled-pods to select unscheduled pods in Daemonset sharding
2 parents a3e9266 + aeb9e35 commit e96dfc0

File tree

12 files changed

+227
-123
lines changed

12 files changed

+227
-123
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ spec:
282282
fieldPath: spec.nodeName
283283
```
284284

285-
To track metrics for unassigned pods, you need to add an additional deployment and set `--node=""`, as shown in the following example:
285+
To track metrics for unassigned pods, you need to add an additional deployment and set `--track-unscheduled-pods`, as shown in the following example:
286286

287287
```
288288
apiVersion: apps/v1
@@ -295,7 +295,7 @@ spec:
295295
name: kube-state-metrics
296296
args:
297297
- --resources=pods
298-
- --node=""
298+
- --track-unscheduled-pods
299299
```
300300

301301
Other metrics can be sharded via [Horizontal sharding](#horizontal-sharding).

README.md.tpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ spec:
283283
fieldPath: spec.nodeName
284284
```
285285

286-
To track metrics for unassigned pods, you need to add an additional deployment and set `--node=""`, as shown in the following example:
286+
To track metrics for unassigned pods, you need to add an additional deployment and set `--track-unscheduled-pods`, as shown in the following example:
287287

288288
```
289289
apiVersion: apps/v1
@@ -296,7 +296,7 @@ spec:
296296
name: kube-state-metrics
297297
args:
298298
- --resources=pods
299-
- --node=""
299+
- --track-unscheduled-pods
300300
```
301301

302302
Other metrics can be sharded via [Horizontal sharding](#horizontal-sharding).

docs/developer/cli-arguments.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ Flags:
8181
--telemetry-port int Port to expose kube-state-metrics self metrics on. (default 8081)
8282
--tls-config string Path to the TLS configuration file
8383
--total-shards int The total number of shards. Sharding is disabled when total shards is set to 1. (default 1)
84+
--track-unscheduled-pods This configuration is used in conjunction with node configuration. When this configuration is true, node configuration is empty and the metric of unscheduled pods is fetched from the Kubernetes API Server. This is experimental.
8485
--use-apiserver-cache Sets resourceVersion=0 for ListWatch requests, using cached resources from the apiserver instead of an etcd quorum read.
8586
-v, --v Level number for the log level verbosity
8687
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
labels:
5+
app.kubernetes.io/component: exporter
6+
app.kubernetes.io/name: kube-state-metrics-no-node-pods
7+
app.kubernetes.io/version: 2.12.0
8+
name: kube-state-metrics-no-node-pods
9+
namespace: kube-system
10+
spec:
11+
clusterIP: None
12+
ports:
13+
- name: http-metrics
14+
port: 8080
15+
targetPort: http-metrics
16+
- name: telemetry
17+
port: 8081
18+
targetPort: telemetry
19+
selector:
20+
app.kubernetes.io/name: kube-state-metrics-no-node-pods

examples/daemonsetsharding/deployment-no-node-pods.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,35 @@ kind: Deployment
33
metadata:
44
labels:
55
app.kubernetes.io/component: exporter
6-
app.kubernetes.io/name: kube-state-metrics-pods
6+
app.kubernetes.io/name: kube-state-metrics-no-node-pods
77
app.kubernetes.io/version: 2.13.0
8-
name: kube-state-metrics-pods
8+
name: kube-state-metrics-no-node-pods
99
namespace: kube-system
1010
spec:
1111
replicas: 1
1212
selector:
1313
matchLabels:
14-
app.kubernetes.io/name: kube-state-metrics
14+
app.kubernetes.io/name: kube-state-metrics-no-node-pods
1515
template:
1616
metadata:
1717
labels:
1818
app.kubernetes.io/component: exporter
19-
app.kubernetes.io/name: kube-state-metrics
19+
app.kubernetes.io/name: kube-state-metrics-no-node-pods
2020
app.kubernetes.io/version: 2.13.0
2121
spec:
2222
automountServiceAccountToken: true
2323
containers:
2424
- args:
2525
- --resources=pods
26-
- --node=""
26+
- --track-unscheduled-pods
2727
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.13.0
2828
livenessProbe:
2929
httpGet:
3030
path: /livez
3131
port: http-metrics
3232
initialDelaySeconds: 5
3333
timeoutSeconds: 5
34-
name: kube-state-metrics
34+
name: kube-state-metrics-no-node-pods
3535
ports:
3636
- containerPort: 8080
3737
name: http-metrics

jsonnet/kube-state-metrics/kube-state-metrics.libsonnet

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,18 +377,27 @@
377377
local c = ksm.deployment.spec.template.spec.containers[0] {
378378
args: [
379379
'--resources=pods',
380-
'--node=""',
380+
'--track-unscheduled-pods',
381381
],
382+
name: shardksmname,
382383
};
383-
local shardksmname = ksm.name + "-pods";
384+
local shardksmname = ksm.name + "-unscheduled-pods-fetching";
384385
std.mergePatch(ksm.deployment,
385386
{
386387
metadata: {
387388
name: shardksmname,
388389
labels: {'app.kubernetes.io/name': shardksmname}
389390
},
390391
spec: {
392+
selector{
393+
matchLabels: {app.kubernetes.io/name': shardksmname}
394+
}
391395
template: {
396+
metadata: {
397+
labels: {
398+
app.kubernetes.io/name': shardksmname
399+
}
400+
}
392401
spec: {
393402
containers: [c],
394403
},
@@ -397,6 +406,27 @@
397406
},
398407
),
399408

409+
deploymentNoNodePodsService:
410+
local c = ksm.deployment.spec.template.spec.containers[0] {
411+
args: [
412+
'--resources=pods',
413+
'--track-unscheduled-pods',
414+
],
415+
};
416+
local shardksmname = ksm.name + "-no-node-pods";
417+
std.mergePatch(ksm.service,
418+
{
419+
metadata: {
420+
name: shardksmname,
421+
labels: {'app.kubernetes.io/name': shardksmname}
422+
},
423+
spec: {
424+
selector: {
425+
'app.kubernetes.io/name': shardksmname
426+
}
427+
}
428+
}
429+
),
400430
daemonset:
401431
// extending the default container from above
402432
local c0 = ksm.deployment.spec.template.spec.containers[0] {

pkg/app/server.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,13 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
224224

225225
namespaces := opts.Namespaces.GetNamespaces()
226226
nsFieldSelector := namespaces.GetExcludeNSFieldSelector(opts.NamespacesDenylist)
227-
nodeFieldSelector := opts.Node.GetNodeFieldSelector()
227+
var nodeFieldSelector string
228+
if opts.TrackUnscheduledPods {
229+
nodeFieldSelector = "spec.nodeName="
230+
klog.InfoS("Using spec.nodeName= to select unscheduable pods without node")
231+
} else {
232+
nodeFieldSelector = opts.Node.GetNodeFieldSelector()
233+
}
228234
merged, err := storeBuilder.MergeFieldSelectors([]string{nsFieldSelector, nodeFieldSelector})
229235
if err != nil {
230236
return err

pkg/options/options.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type Options struct {
5959
Namespaces NamespaceList `yaml:"namespaces"`
6060
NamespacesDenylist NamespaceList `yaml:"namespaces_denylist"`
6161
Node NodeType `yaml:"node"`
62+
TrackUnscheduledPods bool `yaml:"track_unscheduled_pods"`
6263
Pod string `yaml:"pod"`
6364
Port int `yaml:"port"`
6465
Resources ResourceSet `yaml:"resources"`
@@ -90,7 +91,6 @@ func NewOptions() *Options {
9091
MetricAllowlist: MetricSet{},
9192
MetricDenylist: MetricSet{},
9293
MetricOptInList: MetricSet{},
93-
Node: NodeType{},
9494
AnnotationsAllowList: LabelsAllowList{},
9595
LabelsAllowList: LabelsAllowList{},
9696
}
@@ -138,6 +138,7 @@ func (o *Options) AddFlags(cmd *cobra.Command) {
138138

139139
o.cmd.Flags().BoolVar(&o.CustomResourcesOnly, "custom-resource-state-only", false, "Only provide Custom Resource State metrics (experimental)")
140140
o.cmd.Flags().BoolVar(&o.EnableGZIPEncoding, "enable-gzip-encoding", false, "Gzip responses when requested by clients via 'Accept-Encoding: gzip' header.")
141+
o.cmd.Flags().BoolVar(&o.TrackUnscheduledPods, "track-unscheduled-pods", false, "This configuration is used in conjunction with node configuration. When this configuration is true, node configuration is empty and the metric of unscheduled pods is fetched from the Kubernetes API Server. This is experimental.")
141142
o.cmd.Flags().BoolVarP(&o.Help, "help", "h", false, "Print Help text")
142143
o.cmd.Flags().BoolVarP(&o.UseAPIServerCache, "use-apiserver-cache", "", false, "Sets resourceVersion=0 for ListWatch requests, using cached resources from the apiserver instead of an etcd quorum read.")
143144
o.cmd.Flags().Int32Var(&o.Shard, "shard", int32(0), "The instances shard nominal (zero indexed) within the total number of shards. (default 0)")
@@ -156,7 +157,7 @@ func (o *Options) AddFlags(cmd *cobra.Command) {
156157
o.cmd.Flags().StringVar(&o.TLSConfig, "tls-config", "", "Path to the TLS configuration file")
157158
o.cmd.Flags().StringVar(&o.TelemetryHost, "telemetry-host", "::", `Host to expose kube-state-metrics self metrics on.`)
158159
o.cmd.Flags().StringVar(&o.Config, "config", "", "Path to the kube-state-metrics options config file")
159-
o.cmd.Flags().Var(&o.Node, "node", "Name of the node that contains the kube-state-metrics pod. Most likely it should be passed via the downward API. This is used for daemonset sharding. Only available for resources (pod metrics) that support spec.nodeName fieldSelector. This is experimental.")
160+
o.cmd.Flags().StringVar((*string)(&o.Node), "node", "", "Name of the node that contains the kube-state-metrics pod. Most likely it should be passed via the downward API. This is used for daemonset sharding. Only available for resources (pod metrics) that support spec.nodeName fieldSelector. This is experimental.")
160161
o.cmd.Flags().Var(&o.AnnotationsAllowList, "metric-annotations-allowlist", "Comma-separated list of Kubernetes annotations keys that will be used in the resource' labels metric. By default the annotations metrics are not exposed. To include them, provide a list of resource names in their plural form and Kubernetes annotation keys you would like to allow for them (Example: '=namespaces=[kubernetes.io/team,...],pods=[kubernetes.io/team],...)'. A single '*' can be provided per resource instead to allow any annotations, but that has severe performance implications (Example: '=pods=[*]').")
161162
o.cmd.Flags().Var(&o.LabelsAllowList, "metric-labels-allowlist", "Comma-separated list of additional Kubernetes label keys that will be used in the resource' labels metric. By default the labels metrics are not exposed. To include them, provide a list of resource names in their plural form and Kubernetes label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. A single '*' can be provided per resource instead to allow any labels, but that has severe performance implications (Example: '=pods=[*]'). Additionally, an asterisk (*) can be provided as a key, which will resolve to all resources, i.e., assuming '--resources=deployments,pods', '=*=[*]' will resolve to '=deployments=[*],pods=[*]'.")
162163
o.cmd.Flags().Var(&o.MetricAllowlist, "metric-allowlist", "Comma-separated list of metrics to be exposed. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive.")
@@ -186,7 +187,7 @@ func (o *Options) Usage() {
186187
// Validate validates arguments
187188
func (o *Options) Validate() error {
188189
shardableResource := "pods"
189-
if o.Node.String() == "" {
190+
if o.Node == "" {
190191
return nil
191192
}
192193
for _, x := range o.Resources.AsSlice() {

pkg/options/types.go

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package options
1818

1919
import (
2020
"errors"
21-
"regexp"
2221
"sort"
2322
"strings"
2423

@@ -106,56 +105,25 @@ func (r *ResourceSet) Type() string {
106105
}
107106

108107
// NodeType represents a nodeName to query from.
109-
type NodeType map[string]struct{}
108+
type NodeType string
110109

111-
// Set converts a comma-separated string of nodename into a slice and appends it to the NodeList
110+
// Set sets the node name to NodeType.
112111
func (n *NodeType) Set(value string) error {
113-
s := *n
114-
cols := strings.Split(value, ",")
115-
for _, col := range cols {
116-
col = strings.TrimSpace(col)
117-
if len(col) != 0 {
118-
s[col] = struct{}{}
119-
}
120-
}
112+
*n = NodeType(value)
121113
return nil
122114
}
123115

124-
// AsSlice returns the LabelsAllowList in the form of plain string slice.
125-
func (n NodeType) AsSlice() []string {
126-
cols := make([]string, 0, len(n))
127-
for col := range n {
128-
cols = append(cols, col)
129-
}
130-
return cols
131-
}
132-
116+
// String gets node name.
133117
func (n NodeType) String() string {
134-
return strings.Join(n.AsSlice(), ",")
135-
}
136-
137-
// Type returns a descriptive string about the NodeList type.
138-
func (n *NodeType) Type() string {
139-
return "string"
118+
return string(n)
140119
}
141120

142121
// GetNodeFieldSelector returns a nodename field selector.
143122
func (n *NodeType) GetNodeFieldSelector() string {
144-
if nil == n || len(*n) == 0 {
145-
klog.InfoS("Using node type is nil")
146-
return EmptyFieldSelector()
123+
if string(*n) != "" {
124+
return fields.OneTermEqualSelector("spec.nodeName", string(*n)).String()
147125
}
148-
pattern := "[^a-zA-Z0-9_,-]+"
149-
re := regexp.MustCompile(pattern)
150-
result := re.ReplaceAllString(n.String(), "")
151-
klog.InfoS("Using node type", "node", result)
152-
return fields.OneTermEqualSelector("spec.nodeName", result).String()
153-
154-
}
155-
156-
// NodeValue represents a nodeName to query from.
157-
type NodeValue interface {
158-
GetNodeFieldSelector() string
126+
return EmptyFieldSelector()
159127
}
160128

161129
// EmptyFieldSelector returns an empty field selector.

0 commit comments

Comments
 (0)