Skip to content

Commit

Permalink
feat: enable customresource metrics by configuration
Browse files Browse the repository at this point in the history
The main use case is just surfacing fields from custom resources without having to write a lot of code for each one.
  • Loading branch information
iamnoah committed May 6, 2022
1 parent 3e12ba0 commit be1ab05
Show file tree
Hide file tree
Showing 11 changed files with 1,464 additions and 13 deletions.
4 changes: 4 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ sum(kube_pod_container_resource_requests{resource="memory"}) by (namespace, pod,
* on (namespace, pod) group_left() (sum(kube_pod_status_phase{phase="Running"}) by (pod, namespace) == 1)
```

## Metrics from Custom Resources

See [Custom Resource State Metrics](customresourcestate-metrics.md) for more information.

## CLI Arguments

Additionally, options for `kube-state-metrics` can be passed when executing as a CLI, or in a kubernetes / openshift environment. More information can be found here: [CLI Arguments](cli-arguments.md)
212 changes: 212 additions & 0 deletions docs/customresourcestate-metrics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# Custom Resource State Metrics

This section describes how to add metrics based on the state of a custom resource without writing a custom resource
registry and running your own build of KSM.

## Configuration

The `KSM_CUSTOM_RESOURCE_METRICS` environment variable can be used to configure the metrics for custom resources:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: kube-state-metrics
namespace: kube-system
spec:
template:
spec:
containers:
- name: kube-state-metrics
env:
- name: KSM_CUSTOM_RESOURCE_METRICS
value: |
spec:
resources:
- groupVersionKind:
group: myteam.io
version: "v1"
kind: Foo
metrics:
- name: active_count
help: "Count of active Foo"
...
```
### Examples
The examples in this section will use the following custom resource:
```yaml
kind: Foo
apiVersion: myteam.io/vl
metadata:
annotations:
bar: baz
qux: quxx
labels:
foo: bar
name: foo
spec:
order:
- id: 1
value: true
- id: 3
value: false
replicas: 1
status:
active:
type-a: 1
type-b: 3
conditions:
- name: a
value: 45
- name: b
value: 66
sub:
type-a:
active: 1
ready: 2
type-b:
active: 3
ready: 4
uptime: 43.21
```
#### Single Values
```yaml
kind: CustomResourceStateMetrics
spec:
resources:
- groupVersionKind:
group: myteam.io
kind: "Foo"
version: "v1"
metrics:
- name: "uptime"
help: "Foo uptime"
each:
path: [status, uptime]
```
Produces the metric:
```prometheus
kube_myteam_io_v1_Foo_uptime 43.21
```

#### Multiple Metrics/Kitchen Sink

```yaml
kind: CustomResourceStateMetrics
spec:
resources:
- groupVersionKind:
group: myteam.io
kind: "Foo"
version: "v1"
# labels can be added to all metrics from a resource
commonLabels:
crd_type: "foo"
labelsFromPath:
name: [metadata, name]
metrics:
- name: "ready_count"
help: "Number Foo Bars ready"
each:
# targeting an object or array will produce a metric for each element
# labelsFromPath and value are relative to this path
path: [status, sub]

# if path targets an object, the object key will be used as label value
labelFromKey: type
# label values can be resolved specific to this path
labelsFromPath:
active: [active]
# The actual field to use as metric value. Should be a number.
value: [ready]
commonLabels:
custom_metric: "yes"
labelsFromPath:
# whole objects may be copied into labels by prefixing with "*"
# *anything will be copied into labels, with the highest sorted * strings first
"*": [metadata, labels]
"**": [metadata, annotations]

# or specific fields may be copied. these fields will always override values from *s
name: [metadata, name]
foo: [metadata, labels, foo]
```
Produces the following metrics:
```prometheus
kube_myteam_io_v1_Foo_active_count{active="1",custom_metric="yes",foo="bar",name="foo",bar="baz",qux="quxx",type="type-a"} 1
kube_myteam_io_v1_Foo_active_count{active="3",custom_metric="yes",foo="bar",name="foo",bar="baz",qux="quxx",type="type-b"} 3
```

### Naming

The default metric names are prefixed to avoid collisions with other metrics.
By default a namespace of `kube` and a subsystem based on your custom resource's GVK is used.
You can override these with the namespace and subsystem fields.

```yaml
kind: CustomResourceStateMetrics
spec:
resources:
- groupVersionKind: ...
namespace: myteam
subsystem: foos
metrics:
- name: uptime
...
```
Produces:
```prometheus
myteam_foos_uptime 43.21
```

To omit namespace and/or subsystem altogether, set them to `_`.

### Logging

If a metric path is registered but not found on a custom resource, an error will be logged. For some resources,
this may produce a lot of noise. The error log [verbosity][vlog] for a metric or resource can be set with `errorLogV` on
the resource or metric:

```yaml
kind: CustomResourceStateMetrics
spec:
resources:
- groupVersionKind: ...
errorLogV: 0 # 0 = default for errors
metrics:
- name: uptime
errorLogV: 10 # only log at high verbosity
```
[vlog]: https://github.com/go-logr/logr#why-v-levels
### Path Syntax
Paths are specified as a list of strings. Each string is a path segment, resolved dynamically against the data of the custom resource.
If any part of a path is missing, the result is nil.
Examples:
```yaml
# simple path lookup
[spec, replicas] # spec.replicas == 1

# indexing an array
[spec, order, "0", value] # spec.order[0].value = true

# finding an element in a list by key=value
[status, conditions, "[name=a]", value] # status.conditions[0].value = 45

# if the value to be matched is a number or boolean, the value is compared as a number or boolean
[status, conditions, "[value=66]", name] # status.conditions[1].name = "b"
```
13 changes: 9 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ require (
github.com/brancz/gojsontoyaml v0.1.0
github.com/campoy/embedmd v1.0.0
github.com/dgryski/go-jump v0.0.0-20211018200510-ba001c3ffce0
github.com/gobuffalo/flect v0.2.5
github.com/google/go-cmp v0.5.8
github.com/google/go-jsonnet v0.18.0
github.com/jsonnet-bundler/jsonnet-bundler v0.4.1-0.20200708074244-ada055a225fa
Expand All @@ -15,7 +16,9 @@ require (
github.com/prometheus/exporter-toolkit v0.7.1
github.com/robfig/cron/v3 v3.0.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0
golang.org/x/perf v0.0.0-20220411212318-84e58bfe0a7e
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
k8s.io/api v0.23.6
k8s.io/apimachinery v0.23.6
k8s.io/autoscaler/vertical-pod-autoscaler v0.10.0
Expand All @@ -40,6 +43,7 @@ require (
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/fatih/color v1.10.0 // indirect
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-kit/log v0.2.0 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
Expand All @@ -48,15 +52,17 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/imdario/mergo v0.3.5 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.17.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
Expand All @@ -71,12 +77,11 @@ require (
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

go 1.17
Loading

0 comments on commit be1ab05

Please sign in to comment.