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

keps/sig-instrumentation: Add metrics overhaul KEP #2909

Merged
merged 1 commit into from
Nov 28, 2018

Conversation

brancz
Copy link
Member

@brancz brancz commented Nov 6, 2018

This pull requests adds a living KEP that has been brewing within sig-instrumentation for the past few weeks. It outlines an overhaul of metrics defined in kubernetes/kubernetes, to be conform with Prometheus best practices as well as the Kubernetes instrumentation guide. Read on to discover more details 🙂 .

Catch phrase: A road to compatibility guarantees of Kubernetes exposed metrics.

/cc @piosz @DirectXMan12 @coffeepac @metalmatze @s-urbaniak @mxinden

@k8s-ci-robot k8s-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Nov 6, 2018
@k8s-ci-robot
Copy link
Contributor

@brancz: GitHub didn't allow me to request PR reviews from the following users: metalmatze, s-urbaniak, mxinden.

Note that only kubernetes members and repo collaborators can review this PR, and authors cannot review their own PRs.

In response to this:

This pull requests adds a living KEP that has been brewing within sig-instrumentation for the past few weeks. It outlines an overhaul of metrics defined in kubernetes/kubernetes, to be conform with Prometheus best practices as well as the Kubernetes instrumentation guide. Read on to discover more details 🙂 .

/cc @piosz @DirectXMan12 @coffeepac @metalmatze @s-urbaniak @mxinden

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

Copy link
Contributor

@DirectXMan12 DirectXMan12 left a comment

Choose a reason for hiding this comment

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

In general 👍. I'd like to discuss the "passing through registries" a bit, because that can lead to a lot of plumbing, etc.


A number of metrics that Kubernetes is instrumented with do not follow the [official Kubernetes instrumentation guidelines](https://github.com/kubernetes/community/blob/master/contributors/devel/instrumentation.md). This is for a number of reasons, such as the metrics having been created before the instrumentation guidelines were put in place (around two years ago), and just missing it in code reviews. Beyond the Kubernetes instrumentation guidelines, there are several violations of the [Prometheus instrumentation best practices](https://prometheus.io/docs/practices/instrumentation/). In order to have consistently named and high quality metrics, this effort aims to make working with metrics exposed by Kubernetes consistent with the rest of the ecosystem. In fact even metrics exposed by Kubernetes are inconsistent in themselves, making joining of metrics difficult.

Kubernetes also makes extensive use of a global metrics registry to register metrics to be exposed. Aside from general shortcomings of global variables, Kubernetes is seeing actual effects of this, causing a number of components to use `sync.Once` or other mechanisms to ensure to not panic, when registering metrics. Instead a metrics registry should be passed to each component in order to explicitly register metrics instead of through `init` methods or other global, non-obvious executions.
Copy link
Contributor

Choose a reason for hiding this comment

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

My worry with this is that it will lead to excuses for not registering metrics -- e.g. "oh, I don't want to plumb the registry through to this individual function, so I guess I'll just skip adding a metric here". I'm not necessarily entirely against it, but I think the potential cons deserve exploration.

FWIW, we took the approach of having a separate global registry in controller-runtime, so you do metrics.Registry.MustRegister instead of prometheus.MustRegister, but afterwards the workflow feels similar. This lets still lets people choose to separate out the metrics, but doesn't require the extra plumbing.

I'd be curious to see an exploration of the sync.Once -- I seem to recall a decent amount of that was around the idea of metrics being optional, or having optional providers. Perhaps we should just be opinionated about that?

Choose a reason for hiding this comment

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

While it is probably true that people are going to be tempted to not pass down the registry and thus avoid adding metrics in the first place, having another global registry only avoids the overall problem to some degree.
If somebody uses code of the controller-runtime as a library the metrics of that package are still going to be registered against that registry without any explicit configuration. Therefore people might not be aware of that fact and either think that the metrics should show up, but they don't (because they don't use the registry's handler) or due some other mistakes might still show up even though the are writing a completely different component.
We've seen these things happening too often...

Explicitly passing the registry avoids a lot of headache in this case.

Copy link
Member Author

Choose a reason for hiding this comment

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

My own opinion: by introducing a new global registry we actually get the worst of both worlds. It doesn't allow us to capture the metrics that are already being registered by libraries against the canonical prometheus.DefaultRegisterer, and we must create additional work-arounds to collect all metrics as we're forced to have multiple endpoints or even ports. I don't see why the controller-runtime in particular can't inject the registry and default to the canonical global one (similar to the go http client).

Excusing global state with it being easier is a poor argument to make I think, we don't start introducing global variables all over the place for a reason, and it should be the same for metrics/logging/tracing. Plus all of those signals get better by having them plumbed through as that allows us to add extra context.

I think this discussion boils down to any global vs. non-global (dependency injection) discussion, and I think that regardless of metrics/logging/tracing, we can all agree that globals are harmful, or at least encourage harmful patterns.

There are nice abstractions in client-go to make metrics optional, I'd like to see that being explored further as well. I think in terms of this KEP it's more a nice to have, the main goal is that the metrics names don't keep changing, the plumbing can be improved afterwards I think. It's a legacy to work with, but that doesn't mean we can't improve it, in my opinion 🙂 .

Copy link
Contributor

Choose a reason for hiding this comment

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

My own opinion: by introducing a new global registry we actually get the worst of both worlds. It doesn't allow us to capture the metrics that are already being registered by libraries against the canonical prometheus.DefaultRegisterer

The thought was basically that you could plumb it through as an additional collector if you wanted to merge with another registry. I recall going through and figuring out what was required, and it seemed fairly straightforward to serve multiple collectors from a single endpoint (I think).

Plus all of those signals get better by having them plumbed through as that allows us to add extra context.

Sure, agreed. I think we just have to be careful not to make plumbing all that a pain.

I think this discussion boils down to any global vs. non-global (dependency injection) discussion, and I think that regardless of metrics/logging/tracing, we can all agree that globals are harmful, or at least encourage harmful patterns.

I'll agree with that sentiment (on globals).

I think the key for me is that it should have friendly UX while still having sound architectural design -- adding a metric shouldn't necessarily requiring plumbing down a handle to a registry through 5 layers of objects, and updating 20 different test constructions of the intermediate structs that don't use the constructor method and therefore don't get the registry injected, causing the tests to panic (I've had to do similar things before ;-) ). Kubernetes is a twisted maze of structures, and doing changes to one often causes a cascade effect.

I look at it kind-of of like middleware -- you can layer on middleware without having to make much of a change to the core functionality to your web app. In a perfectly ideal world, IMO, you should should be able to "layer in" metrics/logging/etc without causing major ripples in your codebase. It should be there when you want it, and not there when you don't. Of course, we don't have a perfect world, but I think it's something to thing about closely.

🚲 🏠 I've got some other thoughts on workarounds (e.g. our logging promises in controller-runtime), but we can discuss those when the time comes.

There are nice abstractions in client-go to make metrics optional, I'd like to see that being explored further as well.

On this point I disagree. I think once of the nice things about the "default" Prometheus setup is that it just gets out of the way. Adding new metrics to client-go is a bit of a pain, IIRC -- last time I looked, it required adding dummy struct implementations, among other things (that might've changed in the interim). I'd prefer to have some setup that was fairly straightforward to understand and update, and didn't require editing multiple files just to add a single metric.

I think in terms of this KEP it's more a nice to have, the main goal is that the metrics names don't keep changing, the plumbing can be improved afterwards I think.

Ack. I'm on board 100% with the rest of the KEP :-)

Copy link
Member Author

Choose a reason for hiding this comment

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

Added:

Within the scope of this KEP, we want to explore other ways, however, it is not blocking for its success, as the primary goal is to make the metrics exposed themselves more consistent and stable.

Making it a non-blocker, and more exploratory territory. All I'm saying is, the apiserver should not have etcd server metrics, because of poor choice of globals, and more generally metrics shouldn't suffer because of poor architecture. A production system is hard work, and making it observable is part of that.

Copy link
Contributor

Choose a reason for hiding this comment

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

cool, sounds good 👍

@justaugustus
Copy link
Member

REMINDER: KEPs are moving to k/enhancements on November 30. Please attempt to merge this KEP before then to signal consensus.
For more details on this change, review this thread.

Any questions regarding this move should be directed to that thread and not asked on GitHub.


Change the container metrics exposed through cAdvisor (which is compiled into the Kubelet) to [use consistent labeling according to the instrumentation guidelines](https://github.com/kubernetes/kubernetes/pull/69099). Concretely what that means is changing all the occurrences of the labels:
`pod_name` to `pod`
`container_name` to `container`
Copy link
Contributor

Choose a reason for hiding this comment

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

How about existing metrics scrapes which rely on the current labeling? Do we provide some deprecation period where old metric labels would still be available?


Risks include users upgrading Kubernetes, but not updating their usage of Kubernetes exposed metrics in alerting and dashboarding potentially causing incidents to go unnoticed.

To prevent this, we will implement recording rules for Prometheus that allow best effort backward compatibility as well as update uses of breaking metric usages in the [Kubernetes monitoring mixin](https://github.com/kubernetes-monitoring/kubernetes-mixin), a widely used collection of Prometheus alerts and Grafana dashboards for Kubernetes.
Copy link
Contributor

Choose a reason for hiding this comment

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

ok, this answered my question from above :-D

@s-urbaniak
Copy link
Contributor

I am 👍 on this proposal :-)

#### Consistent labeling

Change the container metrics exposed through cAdvisor (which is compiled into the Kubelet) to [use consistent labeling according to the instrumentation guidelines](https://github.com/kubernetes/kubernetes/pull/69099). Concretely what that means is changing all the occurrences of the labels:
`pod_name` to `pod`
Copy link
Contributor

Choose a reason for hiding this comment

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

This sounds fine to me. Would we just have a release where both labels are present?

Copy link
Member Author

Choose a reason for hiding this comment

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

As proposed I think I would prefer providing Prometheus recording rules that allow for backward compatibility, this is what’s been done in the Prometheus ecosystem. But I have no strong feelings about this, I’m also happy with a transition release having both.

@DirectXMan12
Copy link
Contributor

modulo my mini-rant above about plumbing through metrics handles, I'm 👍 on this

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Nov 28, 2018
@brancz
Copy link
Member Author

brancz commented Nov 28, 2018

Changed the wording of the "removal" of the global metrics registry pattern to an exploratory topic of enhancing metrics, so we can explore it, but consistency and stability of exposed metrics is the priority. If we can it would be nice if we can get this merged by Nov 30. @DirectXMan12 @piosz @coffeepac @dashpole 🙂

@DirectXMan12
Copy link
Contributor

/approve

from me (not that I can approve it officially, but the content looks good from my side)

@brancz
Copy link
Member Author

brancz commented Nov 28, 2018

/assign @jbeda

@jdumars
Copy link
Member

jdumars commented Nov 28, 2018

/approve

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: DirectXMan12, jdumars

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 Nov 28, 2018
@DirectXMan12
Copy link
Contributor

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 28, 2018
@k8s-ci-robot k8s-ci-robot merged commit 8c7602b into kubernetes:master Nov 28, 2018
@brancz brancz deleted the metric-overhaul branch November 28, 2018 21:46
justaugustus pushed a commit to justaugustus/community that referenced this pull request Dec 1, 2018
keps/sig-instrumentation: Add metrics overhaul KEP
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. lgtm "Looks good to me", indicates that a PR is ready to be merged. sig/architecture Categorizes an issue or PR as relevant to SIG Architecture. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants