Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Support scraping pods metrics that is still in scheduling status and has no assigned node #2217

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions examples/daemonsetsharding/deployment-no-node-pods.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.10.0
name: kube-state-metrics-pods
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: kube-state-metrics
template:
metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.10.0
spec:
automountServiceAccountToken: true
containers:
- args:
- --resources=pods
- --node=""
- --enable-no-node-scrape
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.10.0
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 5
name: kube-state-metrics
ports:
- containerPort: 8080
name: http-metrics
- containerPort: 8081
name: telemetry
readinessProbe:
httpGet:
path: /
port: 8081
initialDelaySeconds: 5
timeoutSeconds: 5
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65534
seccompProfile:
type: RuntimeDefault
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: kube-state-metrics
2 changes: 1 addition & 1 deletion pkg/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {

namespaces := opts.Namespaces.GetNamespaces()
nsFieldSelector := namespaces.GetExcludeNSFieldSelector(opts.NamespacesDenylist)
nodeFieldSelector := opts.Node.GetNodeFieldSelector()
nodeFieldSelector := opts.Node.GetNodeFieldSelector(opts.NoNodeScrape)
merged, err := storeBuilder.MergeFieldSelectors([]string{nsFieldSelector, nodeFieldSelector})
if err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions pkg/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type Options struct {
Namespaces NamespaceList `yaml:"namespaces"`
NamespacesDenylist NamespaceList `yaml:"namespaces_denylist"`
Node NodeType `yaml:"node"`
NoNodeScrape bool `yaml:"no_node_scrape"`
Pod string `yaml:"pod"`
Port int `yaml:"port"`
Resources ResourceSet `yaml:"resources"`
Expand Down Expand Up @@ -120,6 +121,7 @@ func (o *Options) AddFlags(cmd *cobra.Command) {

o.cmd.Flags().BoolVar(&o.CustomResourcesOnly, "custom-resource-state-only", false, "Only provide Custom Resource State metrics (experimental)")
o.cmd.Flags().BoolVar(&o.EnableGZIPEncoding, "enable-gzip-encoding", false, "Gzip responses when requested by clients via 'Accept-Encoding: gzip' header.")
o.cmd.Flags().BoolVar(&o.NoNodeScrape, "enable-no-node-scrape", false, "This configuration is used in conjunction with node configuration. When this configuration is true, node configuration is empty and the metric of no scheduled pods is scraped. This is experimental.")
o.cmd.Flags().BoolVarP(&o.Help, "help", "h", false, "Print Help text")
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.")
o.cmd.Flags().Int32Var(&o.Shard, "shard", int32(0), "The instances shard nominal (zero indexed) within the total number of shards. (default 0)")
Expand Down
5 changes: 4 additions & 1 deletion pkg/options/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,13 @@ func (r *ResourceSet) Type() string {
type NodeType string

// GetNodeFieldSelector returns a nodename field selector.
func (n *NodeType) GetNodeFieldSelector() string {
func (n *NodeType) GetNodeFieldSelector(b bool) string {
if string(*n) != "" {
return fields.OneTermEqualSelector("spec.nodeName", string(*n)).String()
}
if b {
return fields.OneTermEqualSelector("spec.nodeName", "").String()
}
return EmptyFieldSelector()
}

Expand Down
22 changes: 20 additions & 2 deletions pkg/options/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,25 @@ func TestNodeFieldSelector(t *testing.T) {

for _, test := range tests {
node := test.Node
actual := node.GetNodeFieldSelector()
actual := node.GetNodeFieldSelector(false)
if !reflect.DeepEqual(actual, test.Wanted) {
t.Errorf("Test error for Desc: %s. Want: %+v. Got: %+v.", test.Desc, test.Wanted, actual)
}
}
tests1 := []struct {
Desc string
Node NodeType
Wanted string
}{
{
Desc: "empty node name",
Node: "",
Wanted: "spec.nodeName=",
},
}
for _, test := range tests1 {
node := test.Node
actual := node.GetNodeFieldSelector(true)
if !reflect.DeepEqual(actual, test.Wanted) {
t.Errorf("Test error for Desc: %s. Want: %+v. Got: %+v.", test.Desc, test.Wanted, actual)
}
Expand Down Expand Up @@ -238,7 +256,7 @@ func TestMergeFieldSelectors(t *testing.T) {
ns := test.Namespaces
deniedNS := test.DeniedNamespaces
selector1 := ns.GetExcludeNSFieldSelector(deniedNS)
selector2 := test.Node.GetNodeFieldSelector()
selector2 := test.Node.GetNodeFieldSelector(false)
actual, err := MergeFieldSelectors([]string{selector1, selector2})
if err != nil {
t.Errorf("Test error for Desc: %s. Can't merge field selector %v.", test.Desc, err)
Expand Down