Skip to content

KEP-4785: Resource State Metrics #4811

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

Merged
merged 12 commits into from
Jun 17, 2025
Merged

KEP-4785: Resource State Metrics #4811

merged 12 commits into from
Jun 17, 2025

Conversation

rexagod
Copy link
Member

@rexagod rexagod commented Aug 27, 2024

  • One-line PR description: This KEP proposes the incorporation of the CRDMetrics controller into the Kubernetes organization, similar to its existing counterpart for native metrics, Kube State Metrics.

@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/kep Categorizes KEP tracking issues and PRs modifying the KEP directory sig/instrumentation Categorizes an issue or PR as relevant to SIG Instrumentation. labels Aug 27, 2024
@k8s-ci-robot k8s-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Aug 27, 2024
@rexagod rexagod mentioned this pull request Aug 27, 2024
4 tasks
@k8s-ci-robot k8s-ci-robot removed the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 27, 2024
@logicalhan logicalhan self-assigned this Aug 29, 2024
@logicalhan logicalhan added the lead-opted-in Denotes that an issue has been opted in to a release label Aug 29, 2024
Resource State API from Kube State Metrics, and replace it by the CRDMetrics
controller which, in addition to its own benefits, would allow Kube State
Metrics to drop all Custom Resource State API-specific behaviors that can crash
Kube State Metrics, directly affecting the availability of native metrics
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This KEP proposes the incorporation of the CRDMetrics controller into
the Kubernetes organization, similar to its existing counterpart for
native metrics, Kube State Metrics.
Refer: https://github.com/rexagod/crdmetrics
Copy link
Member

@chrischdi chrischdi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to see this :-)

I will follow along and try to engage and help where possible for me!

Copy link

@sftim sftim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR.

I'm afraid I do have questions.

@rexagod rexagod mentioned this pull request Oct 21, 2024
4 tasks
@rexagod rexagod requested review from sftim, dgrisonnet and mrueg November 8, 2024 09:15
Copy link
Member

@mrueg mrueg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your work on this @rexagod ! I added a few comments.

@sftim
Copy link

sftim commented Nov 8, 2024

Is CustomResourceMetricsConfig a better name?

SGTM

@wojtek-t wojtek-t self-assigned this Jan 8, 2025
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jan 20, 2025
@rexagod
Copy link
Member Author

rexagod commented Jan 21, 2025

Thank you for the thorough review, @wojtek-t, the out-of-tree nature of this KEP had me a bit confused. I believe this is good for another round of reviews now 🙇🏼

@rexagod rexagod requested a review from wojtek-t January 27, 2025 16:53
@rexagod
Copy link
Member Author

rexagod commented Feb 5, 2025

cc @wojtek-t for another review here please.

@dashpole dashpole removed the lead-opted-in Denotes that an issue has been opted in to a release label Feb 13, 2025
@rexagod
Copy link
Member Author

rexagod commented Mar 4, 2025

Friendly ping, @wojtek-t for another look here please.

@rexagod
Copy link
Member Author

rexagod commented Mar 10, 2025

Bump.

cc @kubernetes/production-readiness if folks have spare cycles to help get this reviewed and merged.

@@ -0,0 +1,1216 @@
<!--
**Note:** When your KEP is complete, all of these comment blocks should be removed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ are we good to remove all comment blocks? That will make it easier to review I guess? @rexagod

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe "complete" here means stable graduation, but I could be wrong.

Comment on lines 409 to 412
At the moment, the `spec` houses a single `configuration` field, which defines
the metric generation configuration as follows (please note that the schema is
fast-moving at this point and may be subject to change based on the [feedback
obtained](https://github.com/rexagod/resource-state-metrics/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it be considired to be changed in future and have the configuration be a typed api?

WIth having a .spec.configuration field which is a string, we could also just use a configmap or secret instead 🤔

Also to build tooling on top (e.g. to generate a configuration for a CRD from markers) it would be helpful to have this an typed API.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of taking a config parameter reference - eg

  configurationReference:
    apiVersion: v1       # for alpha, has to be ConfigMap
    kind: ConfigMap      # for alpha, has to be ConfigMap
    namespace: example   # optional, but must be set for initial / alpha implementation
    name: rsm-config
    itemPath: >-
      data.config

Copy link
Member Author

@rexagod rexagod Apr 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely, I plan to make the configuration structured in the next CRD version, but a reference to a ConfigMap is definitely doable before that.

help: "Information about a MyPlatform instance" # The help text for the
# metric family, plugged
# in as-is.
metrics: # Set of metrics to generate under the current metrics family.
Copy link
Member

@chrischdi chrischdi Mar 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have an example on how this could look like on arrays inside a resurce?

E.g. metrics for .status.conditions :-)

(let me know if this is too early, as this is technical implementation question)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a first view that one looks different.

.status.conditions normally is an array, not a map.

Example (simplified):

...
status:
  conditions:
  - status: "False"
    type: Ready
  - status: "True"
    type: Foo

The target metrics would be:

metric_name{...,type="Ready",status="True"} 0
metric_name{...,type="Ready",status="False"} 1
metric_name{...,type="Ready",status="Unknown"} 0
metric_name{...,type="Foo",status="True"} 1
metric_name{...,type="Foo",status="False"} 0
metric_name{...,type="Foo",status="Unknown"} 0

However, I want to give it another try :-)

Copy link
Member Author

@rexagod rexagod May 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird, I don't know why I assumed this to be about maps instead of lists. Currently, for the example above, the resulting metrics would look like (assuming .status.condition was the specified expression):

metric_name{...,type="Ready",status="False"} 1
metric_name{...,type="Foo",status="True"} 1

RSM only exposes gauge metrics, as opposed to stateset, counter and info that CRS encompassed, which also proved to be a pain point for its maintenance, as all three of these can be expressed using gauges. RSM takes a different approach in which the nature of metrics are dependant on the constructs supported by the resolver, for e.g.,

value: o.status.phase == 'Running' ? 1 : 0

may be used to achieve a similar effect. In doing so, the intention here is to not expose behaviors (fields) to generate metrics in RSM's configuration itself beyond a point, but instead make them a characteristic of the resolver as much as possible, to avoid the same pitfalls as CRS in the future. To that effect, while the aforementioned behavior can be achieved in CEL, it won't be possible with the unstructured resolver (see kubernetes/kubernetes#128782).

Also, bit off-topic but I've also added recursive parsing for primitive literals as well as composite data-type which also enables generating multiple metric samples from a single metric configuration, something we didn't achieve in CRS.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Sorry for circling back very late on this. Currently don't have bandwidth...)

That's fine.

I wonder if we then would have to create a metric configuration for each value of phase.
value: o.status.phase == 'Running' ? 1 : 0 looks like we have to hardcode for each phase which exists. Does this then work to still have the same metric name for all?

-->

The controller offers a number of improvements over Kube State Metrics' Custom
Resource State API, while maintaining a 3x faster round trip time for metric

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure to understand the 3x faster bit. Do you mind expanding?

Copy link
Member Author

@rexagod rexagod May 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a link to https://github.com/rexagod/resource-state-metrics/blob/main/tests/bench/bench.sh.

This was used to get a rough estimate around build times and RTT.

# NO RESOLVER DEFAULTS TO THE "UNSTRUCTURED" ONE.
# Set of label-sets to generate for the current metric.
labelKeys: # Set of ordered label-keys, static in nature.
- "name"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose that for the vast majority of cases, you'd want a name label (as well as a namespacelabel for namespaced custom resources). Should it be enabled by default?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 towards the idea of having a way to specify default labels. I don't know if it should necessarily be enabled by default and fixed to name and namespace only. Maybe we add a new field at the same level as the g,v,k,r in the config called defaultLabels and allow users to specify the one they want to be applied to all the metrics that will follow. The result would be kind of similar to what we have today in ksm: https://github.com/kubernetes/kube-state-metrics/blob/0b01e3abce1da521b5e620b8aaa76774bb0fda87/internal/store/pod.go#L39

Copy link
Member Author

@rexagod rexagod May 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default labels may be defined at any scope, like so.

At the moment, we only inject the GVK labels into metrics OOTB, to adhere to CRS' current behavior, but giving this some more thought, I think we could either:

  • stop exposing the GVK labels OOTB to allow users to create scalar metrics as well, or,
  • inject name and namespace, as that's common for all CRs, however, this is also the case with other metadata fields (albeit, being less used comparatively), for e.g., uid, creationTimestamp, resourceVersion, etc. which may give rise to users requesting their addition as well.

@wojtek-t
Copy link
Member

Friendly ping, @wojtek-t for another look here please.

Sorry for huge delay - this looks good enough for me, especially for the external component.

/approve PRR

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mrueg, rexagod, wojtek-t

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Apr 25, 2025
supported DSLs to be able to translate their configuration into a format that
the controller can understand, missing which could result in invalid metrics.

Also, since this aims to deprecate the Custom Resource State API, a timeline
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a migration plan?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hoping to have a well-documented configuration mapping for migration once we are closer to GA and the API changes slow down a bit more.

Comment on lines 396 to 405
- Once fetched, the controller `unmarshal`s the configuration YAML directly into
`stores` which are a set of metric `families`, which in turn are a set of
`metrics`.
- Metric `stores` are created based on its respective GVKR (a type that embeds
`schema.GroupVersionKind`, `schema.GroupVersionResource` to avoid
[plural ambiguities]), and reflectors for the specified resource are
initialized, and populate the stores on its update.
- `/metrics` pings on `RSM_MAIN_PORT` trigger the server to write the
raw metrics, combined with its appropriate header(s), in the response. All
generated metrics are hardcoded to `gauge`s by design, as Prometheus lacks
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of things in common with ksm, is rsm already re-using some of ksm's code or should we add new interfaces to avoid deduplicating code between the projects?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can build parts of ksm as a library, so RSM can reuse those bits?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's what I was thinking, but I don't know how much the low level RSM's code differs from KSM

Copy link
Member Author

@rexagod rexagod May 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wherever possible, constructs surfaced to the users are kept conventionally similar to KSM's, to ease migration.

However, something I touched on the KubeCon presentation was having a fail-safe, similar to node_exporter's collector extension pattern, that would allow downstream forks to generate metrics if they do not, or cannot, do so using the supported resolvers. To accomplish this, KSM will need to officially support it's packages, which is something we didn't explicitly do in the past. Currently, /external metrics rely on a 2019 commit for library support.

Do note that we don't strictly need to do this for RSM to graduate, or even support a stable experience to define collectors like so (case in point, openshift-state-metrics that's been and still is in production, which relies on the same commit used in RSM), but it'll be nice to have; and maybe even easier to achieve once KSM is decoupled from CRS.

obtained](https://github.com/rexagod/resource-state-metrics/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen)):

```yaml
stores: # Set of metrics stores for each CR we want to generate metrics for.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

store is an internal term that is not necessarily easy to understand for end-users. How about calling it resources or metrics?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

metrics being a parent of families (which in turn has metric) sounds a bit odd.

resources conflicts with the resource field internally from a DX perspective.

Would it suffice to document the stores field once we have structured configuration in the CR? Or I could expand the configuration documentation to include information for all such fields as well.

┌[rexagod@thegoldenhind] [/dev/pts/3] [main ⚡] 
└[~/repositories/oss/resource-state-metrics/github.com/rexagod/resource-state-metrics]> k explain resourcemetricsmonitor.spec
GROUP:      resource-state-metrics.instrumentation.k8s-sigs.io
KIND:       ResourceMetricsMonitor
VERSION:    v1alpha1

FIELD: spec <Object>


DESCRIPTION:
    ResourceMetricsMonitorSpec is the spec for a ResourceMetricsMonitor
    resource.
    
FIELDS:
  configuration	<string> -required-
    Configuration is the RSM configuration that generates metrics.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it suffice to document the stores field once we have structured configuration in the CR?

I am fine with that.

Otherwise an option could be to call it generators? Maybe it is more explicit to users

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, generators makes more sense. I'll rename it.

Comment on lines +436 to +443
labelKeys: # Set of ordered label-keys, static in nature.
- "name"
- "static_foo"
labelValues: # Set of ordered label values, dynamic in nature.
# Therefore, these may contain static values or
# parse-able expressions.
- "o.metadata.name" # Parse-able CEL expression.
- "static_foo_value" # Static value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like having two distinct arrays for label keys and values could be prone to errors. Could we perhaps have them in a map instead? Like:

- labels:
  name: "o.metadata.name"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. There's places in the codebase where logic surrounding labels requires ordering, so we'd have to convert labels defined at either of the three scopes (stores, families, and metrics) to list first.

Preserving original order can also help us pass results based on the query to the value field, which can then work based on that contextual data. We've seen requests like this for CRS which demand a shared context between labels and value, and an ordering should help users specify that in the value field.

-->

The controller abides by the following principals:
* Garbage in, garbage out: Invalid configurations will generate invalid metrics.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of an invalid configuration that would produce invalid metrics? As far as I can tell since rsm is aware of the custom resource schemas, most if not all of the user inputs could be validated and instead of silencing configuration errors, rsm could surface them to the users

Copy link
Member Author

@rexagod rexagod May 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configuration errors are surfaced in the logs, as well as the managed resource's status field. I'll add a metric to the self port to surface that there as well.

My intention here was to mainly point out that, for instance, a label key that doesn't follow Prometheus' [a-zA-Z_][a-zA-Z0-9_]* format will not raise an error, and still be present in the generated metric, such as {1="1"}, which will be detected at ingestion. However, we still run some validations that make sense on the RSM-level, such as having the same number of label keys and values, which will be surfaced.

SIG to get the process for these resources started right away.
-->

We request a repository (`kubernetes/resource-state-metrics`) to migrate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it is a subproject it should land in kubernetes-sigs. kube-state-metrics is in the kubernetes org only because the project predates the sigs org and it would be quite a bit of work ot move to the new org

We considered refactoring the Kube State Metrics' Custom Resource State API, but
that has actually been done multiple times in the past which often amounts to
us ending up in the same position, owing to its limited scalability.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could be worth also mentioning kubernetes/kube-state-metrics#1978 as an alternative

Signed-off-by: Pranshu Srivastava <rexagod@gmail.com>
@dgrisonnet
Copy link
Member

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jun 17, 2025
@k8s-ci-robot k8s-ci-robot merged commit 9f63a07 into kubernetes:master Jun 17, 2025
4 checks passed
@k8s-ci-robot k8s-ci-robot added this to the v1.34 milestone Jun 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/kep Categorizes KEP tracking issues and PRs modifying the KEP directory lgtm "Looks good to me", indicates that a PR is ready to be merged. sig/instrumentation Categorizes an issue or PR as relevant to SIG Instrumentation. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.