mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
Merge pull request #113609 from haircommander/sandbox-metrics
kubelet: add support for broadcasting metrics from CRI
This commit is contained in:
commit
b4040b3b86
@ -124,6 +124,14 @@ type Runtime interface {
|
|||||||
CheckpointContainer(ctx context.Context, options *runtimeapi.CheckpointContainerRequest) error
|
CheckpointContainer(ctx context.Context, options *runtimeapi.CheckpointContainerRequest) error
|
||||||
// Generate pod status from the CRI event
|
// Generate pod status from the CRI event
|
||||||
GeneratePodStatus(event *runtimeapi.ContainerEventResponse) (*PodStatus, error)
|
GeneratePodStatus(event *runtimeapi.ContainerEventResponse) (*PodStatus, error)
|
||||||
|
// ListMetricDescriptors gets the descriptors for the metrics that will be returned in ListPodSandboxMetrics.
|
||||||
|
// This list should be static at startup: either the client and server restart together when
|
||||||
|
// adding or removing metrics descriptors, or they should not change.
|
||||||
|
// Put differently, if ListPodSandboxMetrics references a name that is not described in the initial
|
||||||
|
// ListMetricDescriptors call, then the metric will not be broadcasted.
|
||||||
|
ListMetricDescriptors(ctx context.Context) ([]*runtimeapi.MetricDescriptor, error)
|
||||||
|
// ListPodSandboxMetrics retrieves the metrics for all pod sandboxes.
|
||||||
|
ListPodSandboxMetrics(ctx context.Context) ([]*runtimeapi.PodSandboxMetrics, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StreamingRuntime is the interface implemented by runtimes that handle the serving of the
|
// StreamingRuntime is the interface implemented by runtimes that handle the serving of the
|
||||||
|
@ -379,6 +379,22 @@ func (f *FakeRuntime) CheckpointContainer(_ context.Context, options *runtimeapi
|
|||||||
return f.Err
|
return f.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FakeRuntime) ListMetricDescriptors(_ context.Context) ([]*runtimeapi.MetricDescriptor, error) {
|
||||||
|
f.Lock()
|
||||||
|
defer f.Unlock()
|
||||||
|
|
||||||
|
f.CalledFunctions = append(f.CalledFunctions, "ListMetricDescriptors")
|
||||||
|
return nil, f.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeRuntime) ListPodSandboxMetrics(_ context.Context) ([]*runtimeapi.PodSandboxMetrics, error) {
|
||||||
|
f.Lock()
|
||||||
|
defer f.Unlock()
|
||||||
|
|
||||||
|
f.CalledFunctions = append(f.CalledFunctions, "ListPodSandboxMetrics")
|
||||||
|
return nil, f.Err
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FakeRuntime) ImageStats(_ context.Context) (*kubecontainer.ImageStats, error) {
|
func (f *FakeRuntime) ImageStats(_ context.Context) (*kubecontainer.ImageStats, error) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
defer f.Unlock()
|
defer f.Unlock()
|
||||||
|
@ -286,6 +286,36 @@ func (mr *MockRuntimeMockRecorder) ListImages(ctx interface{}) *gomock.Call {
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListImages", reflect.TypeOf((*MockRuntime)(nil).ListImages), ctx)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListImages", reflect.TypeOf((*MockRuntime)(nil).ListImages), ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListMetricDescriptors mocks base method.
|
||||||
|
func (m *MockRuntime) ListMetricDescriptors(ctx context.Context) ([]*v10.MetricDescriptor, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "ListMetricDescriptors", ctx)
|
||||||
|
ret0, _ := ret[0].([]*v10.MetricDescriptor)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListMetricDescriptors indicates an expected call of ListMetricDescriptors.
|
||||||
|
func (mr *MockRuntimeMockRecorder) ListMetricDescriptors(ctx interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListMetricDescriptors", reflect.TypeOf((*MockRuntime)(nil).ListMetricDescriptors), ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPodSandboxMetrics mocks base method.
|
||||||
|
func (m *MockRuntime) ListPodSandboxMetrics(ctx context.Context) ([]*v10.PodSandboxMetrics, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "ListPodSandboxMetrics", ctx)
|
||||||
|
ret0, _ := ret[0].([]*v10.PodSandboxMetrics)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPodSandboxMetrics indicates an expected call of ListPodSandboxMetrics.
|
||||||
|
func (mr *MockRuntimeMockRecorder) ListPodSandboxMetrics(ctx interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPodSandboxMetrics", reflect.TypeOf((*MockRuntime)(nil).ListPodSandboxMetrics), ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// PullImage mocks base method.
|
// PullImage mocks base method.
|
||||||
func (m *MockRuntime) PullImage(ctx context.Context, image container.ImageSpec, pullSecrets []v1.Secret, podSandboxConfig *v10.PodSandboxConfig) (string, error) {
|
func (m *MockRuntime) PullImage(ctx context.Context, image container.ImageSpec, pullSecrets []v1.Secret, podSandboxConfig *v10.PodSandboxConfig) (string, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -336,3 +336,23 @@ func (f *RemoteRuntime) CheckpointContainer(ctx context.Context, req *kubeapi.Ch
|
|||||||
func (f *RemoteRuntime) GetContainerEvents(req *kubeapi.GetEventsRequest, ces kubeapi.RuntimeService_GetContainerEventsServer) error {
|
func (f *RemoteRuntime) GetContainerEvents(req *kubeapi.GetEventsRequest, ces kubeapi.RuntimeService_GetContainerEventsServer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListMetricDescriptors gets the descriptors for the metrics that will be returned in ListPodSandboxMetrics.
|
||||||
|
func (f *RemoteRuntime) ListMetricDescriptors(ctx context.Context, req *kubeapi.ListMetricDescriptorsRequest) (*kubeapi.ListMetricDescriptorsResponse, error) {
|
||||||
|
descs, err := f.RuntimeService.ListMetricDescriptors(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &kubeapi.ListMetricDescriptorsResponse{Descriptors: descs}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPodSandboxMetrics retrieves the metrics for all pod sandboxes.
|
||||||
|
func (f *RemoteRuntime) ListPodSandboxMetrics(ctx context.Context, req *kubeapi.ListPodSandboxMetricsRequest) (*kubeapi.ListPodSandboxMetricsResponse, error) {
|
||||||
|
podMetrics, err := f.RuntimeService.ListPodSandboxMetrics(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &kubeapi.ListPodSandboxMetricsResponse{PodMetrics: podMetrics}, nil
|
||||||
|
}
|
||||||
|
@ -815,3 +815,33 @@ func (r *remoteRuntimeService) GetContainerEvents(containerEventsCh chan *runtim
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListMetricDescriptors gets the descriptors for the metrics that will be returned in ListPodSandboxMetrics.
|
||||||
|
func (r *remoteRuntimeService) ListMetricDescriptors(ctx context.Context) ([]*runtimeapi.MetricDescriptor, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, r.timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
resp, err := r.runtimeClient.ListMetricDescriptors(ctx, &runtimeapi.ListMetricDescriptorsRequest{})
|
||||||
|
if err != nil {
|
||||||
|
klog.ErrorS(err, "ListMetricDescriptors from runtime service failed")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
klog.V(10).InfoS("[RemoteRuntimeService] ListMetricDescriptors Response", "stats", resp.GetDescriptors())
|
||||||
|
|
||||||
|
return resp.GetDescriptors(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPodSandboxMetrics retrieves the metrics for all pod sandboxes.
|
||||||
|
func (r *remoteRuntimeService) ListPodSandboxMetrics(ctx context.Context) ([]*runtimeapi.PodSandboxMetrics, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, r.timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
resp, err := r.runtimeClient.ListPodSandboxMetrics(ctx, &runtimeapi.ListPodSandboxMetricsRequest{})
|
||||||
|
if err != nil {
|
||||||
|
klog.ErrorS(err, "ListPodSandboxMetrics from runtime service failed")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
klog.V(10).InfoS("[RemoteRuntimeService] ListPodSandboxMetrics Response", "stats", resp.GetPodMetrics())
|
||||||
|
|
||||||
|
return resp.GetPodMetrics(), nil
|
||||||
|
}
|
||||||
|
@ -2562,6 +2562,16 @@ func (kl *Kubelet) CheckpointContainer(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListMetricDescriptors gets the descriptors for the metrics that will be returned in ListPodSandboxMetrics.
|
||||||
|
func (kl *Kubelet) ListMetricDescriptors(ctx context.Context) ([]*runtimeapi.MetricDescriptor, error) {
|
||||||
|
return kl.containerRuntime.ListMetricDescriptors(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPodSandboxMetrics retrieves the metrics for all pod sandboxes.
|
||||||
|
func (kl *Kubelet) ListPodSandboxMetrics(ctx context.Context) ([]*runtimeapi.PodSandboxMetrics, error) {
|
||||||
|
return kl.containerRuntime.ListPodSandboxMetrics(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (kl *Kubelet) supportLocalStorageCapacityIsolation() bool {
|
func (kl *Kubelet) supportLocalStorageCapacityIsolation() bool {
|
||||||
return kl.GetConfiguration().LocalStorageCapacityIsolation
|
return kl.GetConfiguration().LocalStorageCapacityIsolation
|
||||||
}
|
}
|
||||||
|
@ -343,3 +343,21 @@ func (in instrumentedRuntimeService) GetContainerEvents(containerEventsCh chan *
|
|||||||
recordError(operation, err)
|
recordError(operation, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (in instrumentedRuntimeService) ListMetricDescriptors(ctx context.Context) ([]*runtimeapi.MetricDescriptor, error) {
|
||||||
|
const operation = "list_metric_descriptors"
|
||||||
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
out, err := in.service.ListMetricDescriptors(ctx)
|
||||||
|
recordError(operation, err)
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (in instrumentedRuntimeService) ListPodSandboxMetrics(ctx context.Context) ([]*runtimeapi.PodSandboxMetrics, error) {
|
||||||
|
const operation = "list_podsandbox_metrics"
|
||||||
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
out, err := in.service.ListPodSandboxMetrics(ctx)
|
||||||
|
recordError(operation, err)
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
@ -1123,3 +1123,11 @@ func (m *kubeGenericRuntimeManager) UpdatePodCIDR(ctx context.Context, podCIDR s
|
|||||||
func (m *kubeGenericRuntimeManager) CheckpointContainer(ctx context.Context, options *runtimeapi.CheckpointContainerRequest) error {
|
func (m *kubeGenericRuntimeManager) CheckpointContainer(ctx context.Context, options *runtimeapi.CheckpointContainerRequest) error {
|
||||||
return m.runtimeService.CheckpointContainer(ctx, options)
|
return m.runtimeService.CheckpointContainer(ctx, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *kubeGenericRuntimeManager) ListMetricDescriptors(ctx context.Context) ([]*runtimeapi.MetricDescriptor, error) {
|
||||||
|
return m.runtimeService.ListMetricDescriptors(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *kubeGenericRuntimeManager) ListPodSandboxMetrics(ctx context.Context) ([]*runtimeapi.PodSandboxMetrics, error) {
|
||||||
|
return m.runtimeService.ListPodSandboxMetrics(ctx)
|
||||||
|
}
|
||||||
|
129
pkg/kubelet/metrics/collectors/cri_metrics.go
Normal file
129
pkg/kubelet/metrics/collectors/cri_metrics.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package collectors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/component-base/metrics"
|
||||||
|
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type criMetricsCollector struct {
|
||||||
|
metrics.BaseStableCollector
|
||||||
|
// The descriptors structure will be populated by one call to ListMetricDescriptors from the runtime.
|
||||||
|
// They will be saved in this map, where the key is the Name and the value is the Desc.
|
||||||
|
descriptors map[string]*metrics.Desc
|
||||||
|
listPodSandboxMetricsFn func(context.Context) ([]*runtimeapi.PodSandboxMetrics, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if criMetricsCollector implements necessary interface
|
||||||
|
var _ metrics.StableCollector = &criMetricsCollector{}
|
||||||
|
|
||||||
|
// NewCRIMetricsCollector implements the metrics.Collector interface
|
||||||
|
func NewCRIMetricsCollector(ctx context.Context, listPodSandboxMetricsFn func(context.Context) ([]*runtimeapi.PodSandboxMetrics, error), listMetricDescriptorsFn func(context.Context) ([]*runtimeapi.MetricDescriptor, error)) metrics.StableCollector {
|
||||||
|
descs, err := listMetricDescriptorsFn(ctx)
|
||||||
|
if err != nil {
|
||||||
|
klog.ErrorS(err, "Error reading MetricDescriptors")
|
||||||
|
return &criMetricsCollector{
|
||||||
|
listPodSandboxMetricsFn: listPodSandboxMetricsFn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c := &criMetricsCollector{
|
||||||
|
listPodSandboxMetricsFn: listPodSandboxMetricsFn,
|
||||||
|
descriptors: make(map[string]*metrics.Desc, len(descs)),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, desc := range descs {
|
||||||
|
c.descriptors[desc.Name] = criDescToProm(desc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe implements the metrics.DescribeWithStability interface.
|
||||||
|
func (c *criMetricsCollector) DescribeWithStability(ch chan<- *metrics.Desc) {
|
||||||
|
for _, desc := range c.descriptors {
|
||||||
|
ch <- desc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect implements the metrics.CollectWithStability interface.
|
||||||
|
// TODO(haircommander): would it be better if these were processed async?
|
||||||
|
func (c *criMetricsCollector) CollectWithStability(ch chan<- metrics.Metric) {
|
||||||
|
podMetrics, err := c.listPodSandboxMetricsFn(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
klog.ErrorS(err, "Failed to get pod metrics")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, podMetric := range podMetrics {
|
||||||
|
for _, metric := range podMetric.GetMetrics() {
|
||||||
|
promMetric, err := c.criMetricToProm(metric)
|
||||||
|
if err == nil {
|
||||||
|
ch <- promMetric
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, ctrMetric := range podMetric.GetContainerMetrics() {
|
||||||
|
for _, metric := range ctrMetric.GetMetrics() {
|
||||||
|
promMetric, err := c.criMetricToProm(metric)
|
||||||
|
if err == nil {
|
||||||
|
ch <- promMetric
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func criDescToProm(m *runtimeapi.MetricDescriptor) *metrics.Desc {
|
||||||
|
// Labels in the translation are variableLabels, as opposed to constant labels.
|
||||||
|
// This is because the values of the labels will be different for each container.
|
||||||
|
return metrics.NewDesc(m.Name, m.Help, m.LabelKeys, nil, metrics.INTERNAL, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *criMetricsCollector) criMetricToProm(m *runtimeapi.Metric) (metrics.Metric, error) {
|
||||||
|
desc, ok := c.descriptors[m.Name]
|
||||||
|
if !ok {
|
||||||
|
err := fmt.Errorf("error converting CRI Metric to prometheus format")
|
||||||
|
klog.V(5).ErrorS(err, "Descriptor not present in pre-populated list of descriptors", "descriptor name", m.Name)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := criTypeToProm[m.MetricType]
|
||||||
|
|
||||||
|
pm, err := metrics.NewConstMetric(desc, typ, float64(m.GetValue().Value), m.LabelValues...)
|
||||||
|
if err != nil {
|
||||||
|
klog.ErrorS(err, "Error getting CRI prometheus metric", "descriptor", desc.String())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// If Timestamp is 0, then the runtime did not cache the result.
|
||||||
|
// In this case, a cached result is a metric that was collected ahead of time,
|
||||||
|
// as opposed to on-demand.
|
||||||
|
// If the metric was requested as needed, then Timestamp==0.
|
||||||
|
if m.Timestamp == 0 {
|
||||||
|
return pm, nil
|
||||||
|
}
|
||||||
|
return metrics.NewLazyMetricWithTimestamp(time.Unix(0, m.Timestamp), pm), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var criTypeToProm = map[runtimeapi.MetricType]metrics.ValueType{
|
||||||
|
runtimeapi.MetricType_COUNTER: metrics.CounterValue,
|
||||||
|
runtimeapi.MetricType_GAUGE: metrics.GaugeValue,
|
||||||
|
}
|
@ -250,6 +250,8 @@ type HostInterface interface {
|
|||||||
GetExec(ctx context.Context, podFullName string, podUID types.UID, containerName string, cmd []string, streamOpts remotecommandserver.Options) (*url.URL, error)
|
GetExec(ctx context.Context, podFullName string, podUID types.UID, containerName string, cmd []string, streamOpts remotecommandserver.Options) (*url.URL, error)
|
||||||
GetAttach(ctx context.Context, podFullName string, podUID types.UID, containerName string, streamOpts remotecommandserver.Options) (*url.URL, error)
|
GetAttach(ctx context.Context, podFullName string, podUID types.UID, containerName string, streamOpts remotecommandserver.Options) (*url.URL, error)
|
||||||
GetPortForward(ctx context.Context, podName, podNamespace string, podUID types.UID, portForwardOpts portforward.V4Options) (*url.URL, error)
|
GetPortForward(ctx context.Context, podName, podNamespace string, podUID types.UID, portForwardOpts portforward.V4Options) (*url.URL, error)
|
||||||
|
ListMetricDescriptors(ctx context.Context) ([]*runtimeapi.MetricDescriptor, error)
|
||||||
|
ListPodSandboxMetrics(ctx context.Context) ([]*runtimeapi.PodSandboxMetrics, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer initializes and configures a kubelet.Server object to handle HTTP requests.
|
// NewServer initializes and configures a kubelet.Server object to handle HTTP requests.
|
||||||
@ -386,9 +388,6 @@ func (s *Server) InstallDefaultHandlers() {
|
|||||||
s.addMetricsBucketMatcher("metrics/resource")
|
s.addMetricsBucketMatcher("metrics/resource")
|
||||||
s.restfulCont.Handle(metricsPath, legacyregistry.Handler())
|
s.restfulCont.Handle(metricsPath, legacyregistry.Handler())
|
||||||
|
|
||||||
// cAdvisor metrics are exposed under the secured handler as well
|
|
||||||
r := compbasemetrics.NewKubeRegistry()
|
|
||||||
|
|
||||||
includedMetrics := cadvisormetrics.MetricSet{
|
includedMetrics := cadvisormetrics.MetricSet{
|
||||||
cadvisormetrics.CpuUsageMetrics: struct{}{},
|
cadvisormetrics.CpuUsageMetrics: struct{}{},
|
||||||
cadvisormetrics.MemoryUsageMetrics: struct{}{},
|
cadvisormetrics.MemoryUsageMetrics: struct{}{},
|
||||||
@ -400,14 +399,19 @@ func (s *Server) InstallDefaultHandlers() {
|
|||||||
cadvisormetrics.ProcessMetrics: struct{}{},
|
cadvisormetrics.ProcessMetrics: struct{}{},
|
||||||
cadvisormetrics.OOMMetrics: struct{}{},
|
cadvisormetrics.OOMMetrics: struct{}{},
|
||||||
}
|
}
|
||||||
|
// cAdvisor metrics are exposed under the secured handler as well
|
||||||
cadvisorOpts := cadvisorv2.RequestOptions{
|
r := compbasemetrics.NewKubeRegistry()
|
||||||
IdType: cadvisorv2.TypeName,
|
|
||||||
Count: 1,
|
|
||||||
Recursive: true,
|
|
||||||
}
|
|
||||||
r.RawMustRegister(metrics.NewPrometheusCollector(prometheusHostAdapter{s.host}, containerPrometheusLabelsFunc(s.host), includedMetrics, clock.RealClock{}, cadvisorOpts))
|
|
||||||
r.RawMustRegister(metrics.NewPrometheusMachineCollector(prometheusHostAdapter{s.host}, includedMetrics))
|
r.RawMustRegister(metrics.NewPrometheusMachineCollector(prometheusHostAdapter{s.host}, includedMetrics))
|
||||||
|
if utilfeature.DefaultFeatureGate.Enabled(features.PodAndContainerStatsFromCRI) {
|
||||||
|
r.CustomRegister(collectors.NewCRIMetricsCollector(context.TODO(), s.host.ListPodSandboxMetrics, s.host.ListMetricDescriptors))
|
||||||
|
} else {
|
||||||
|
cadvisorOpts := cadvisorv2.RequestOptions{
|
||||||
|
IdType: cadvisorv2.TypeName,
|
||||||
|
Count: 1,
|
||||||
|
Recursive: true,
|
||||||
|
}
|
||||||
|
r.RawMustRegister(metrics.NewPrometheusCollector(prometheusHostAdapter{s.host}, containerPrometheusLabelsFunc(s.host), includedMetrics, clock.RealClock{}, cadvisorOpts))
|
||||||
|
}
|
||||||
s.restfulCont.Handle(cadvisorMetricsPath,
|
s.restfulCont.Handle(cadvisorMetricsPath,
|
||||||
compbasemetrics.HandlerFor(r, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError}),
|
compbasemetrics.HandlerFor(r, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError}),
|
||||||
)
|
)
|
||||||
|
@ -156,6 +156,14 @@ func (fk *fakeKubelet) CheckpointContainer(_ context.Context, podUID types.UID,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fk *fakeKubelet) ListMetricDescriptors(ctx context.Context) ([]*runtimeapi.MetricDescriptor, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fk *fakeKubelet) ListPodSandboxMetrics(ctx context.Context) ([]*runtimeapi.PodSandboxMetrics, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
type fakeRuntime struct {
|
type fakeRuntime struct {
|
||||||
execFunc func(string, []string, io.Reader, io.WriteCloser, io.WriteCloser, bool, <-chan remotecommand.TerminalSize) error
|
execFunc func(string, []string, io.Reader, io.WriteCloser, io.WriteCloser, bool, <-chan remotecommand.TerminalSize) error
|
||||||
attachFunc func(string, io.Reader, io.WriteCloser, io.WriteCloser, bool, <-chan remotecommand.TerminalSize) error
|
attachFunc func(string, io.Reader, io.WriteCloser, io.WriteCloser, bool, <-chan remotecommand.TerminalSize) error
|
||||||
|
@ -47,6 +47,16 @@ func NewLazyConstMetric(desc *Desc, valueType ValueType, value float64, labelVal
|
|||||||
return prometheus.MustNewConstMetric(desc.toPrometheusDesc(), valueType.toPromValueType(), value, labelValues...)
|
return prometheus.MustNewConstMetric(desc.toPrometheusDesc(), valueType.toPromValueType(), value, labelValues...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewConstMetric is a helper of NewConstMetric.
|
||||||
|
//
|
||||||
|
// Note: If the metrics described by the desc is hidden, the metrics will not be created.
|
||||||
|
func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) {
|
||||||
|
if desc.IsHidden() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return prometheus.NewConstMetric(desc.toPrometheusDesc(), valueType.toPromValueType(), value, labelValues...)
|
||||||
|
}
|
||||||
|
|
||||||
// NewLazyMetricWithTimestamp is a helper of NewMetricWithTimestamp.
|
// NewLazyMetricWithTimestamp is a helper of NewMetricWithTimestamp.
|
||||||
//
|
//
|
||||||
// Warning: the Metric 'm' must be the one created by NewLazyConstMetric(),
|
// Warning: the Metric 'm' must be the one created by NewLazyConstMetric(),
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -121,6 +121,16 @@ service RuntimeService {
|
|||||||
|
|
||||||
// GetContainerEvents gets container events from the CRI runtime
|
// GetContainerEvents gets container events from the CRI runtime
|
||||||
rpc GetContainerEvents(GetEventsRequest) returns (stream ContainerEventResponse) {}
|
rpc GetContainerEvents(GetEventsRequest) returns (stream ContainerEventResponse) {}
|
||||||
|
|
||||||
|
// ListMetricDescriptors gets the descriptors for the metrics that will be returned in ListPodSandboxMetrics.
|
||||||
|
// This list should be static at startup: either the client and server restart together when
|
||||||
|
// adding or removing metrics descriptors, or they should not change.
|
||||||
|
// Put differently, if ListPodSandboxMetrics references a name that is not described in the initial
|
||||||
|
// ListMetricDescriptors call, then the metric will not be broadcasted.
|
||||||
|
rpc ListMetricDescriptors(ListMetricDescriptorsRequest) returns (ListMetricDescriptorsResponse) {}
|
||||||
|
|
||||||
|
// ListPodSandboxMetrics gets pod sandbox metrics from CRI Runtime
|
||||||
|
rpc ListPodSandboxMetrics(ListPodSandboxMetricsRequest) returns (ListPodSandboxMetricsResponse) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageService defines the public APIs for managing images.
|
// ImageService defines the public APIs for managing images.
|
||||||
@ -1716,3 +1726,58 @@ enum ContainerEventType {
|
|||||||
// Container deleted
|
// Container deleted
|
||||||
CONTAINER_DELETED_EVENT = 3;
|
CONTAINER_DELETED_EVENT = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ListMetricDescriptorsRequest {}
|
||||||
|
|
||||||
|
message ListMetricDescriptorsResponse {
|
||||||
|
repeated MetricDescriptor descriptors = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MetricDescriptor {
|
||||||
|
// The name field will be used as a unique identifier of this MetricDescriptor,
|
||||||
|
// and be used in conjunction with the Metric structure to populate the full Metric.
|
||||||
|
string name = 1;
|
||||||
|
string help = 2;
|
||||||
|
// When a metric uses this metric descriptor, it should only define
|
||||||
|
// labels that have previously been declared in label_keys.
|
||||||
|
// It is the responsibility of the runtime to correctly keep sorted the keys and values.
|
||||||
|
// If the two slices have different length, the behavior is undefined.
|
||||||
|
repeated string label_keys = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListPodSandboxMetricsRequest {}
|
||||||
|
|
||||||
|
message ListPodSandboxMetricsResponse {
|
||||||
|
repeated PodSandboxMetrics pod_metrics = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PodSandboxMetrics {
|
||||||
|
string pod_sandbox_id = 1;
|
||||||
|
repeated Metric metrics = 2;
|
||||||
|
repeated ContainerMetrics container_metrics = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ContainerMetrics {
|
||||||
|
string container_id = 1;
|
||||||
|
repeated Metric metrics = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Metric {
|
||||||
|
// Name must match a name previously returned in a MetricDescriptors call,
|
||||||
|
// otherwise, it will be ignored.
|
||||||
|
string name = 1;
|
||||||
|
// Timestamp should be 0 if the metric was gathered live.
|
||||||
|
// If it was cached, the Timestamp should reflect the time it was collected.
|
||||||
|
int64 timestamp = 2;
|
||||||
|
MetricType metric_type = 3;
|
||||||
|
// The corresponding LabelValues to the LabelKeys defined in the MetricDescriptor.
|
||||||
|
// It is the responsibility of the runtime to correctly keep sorted the keys and values.
|
||||||
|
// If the two slices have different length, the behavior is undefined.
|
||||||
|
repeated string label_values = 4;
|
||||||
|
UInt64Value value = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MetricType {
|
||||||
|
COUNTER = 0;
|
||||||
|
GAUGE = 1;
|
||||||
|
}
|
||||||
|
@ -97,6 +97,10 @@ type ContainerStatsManager interface {
|
|||||||
PodSandboxStats(ctx context.Context, podSandboxID string) (*runtimeapi.PodSandboxStats, error)
|
PodSandboxStats(ctx context.Context, podSandboxID string) (*runtimeapi.PodSandboxStats, error)
|
||||||
// ListPodSandboxStats returns stats of all running pods.
|
// ListPodSandboxStats returns stats of all running pods.
|
||||||
ListPodSandboxStats(ctx context.Context, filter *runtimeapi.PodSandboxStatsFilter) ([]*runtimeapi.PodSandboxStats, error)
|
ListPodSandboxStats(ctx context.Context, filter *runtimeapi.PodSandboxStatsFilter) ([]*runtimeapi.PodSandboxStats, error)
|
||||||
|
// ListMetricDescriptors gets the descriptors for the metrics that will be returned in ListPodSandboxMetrics.
|
||||||
|
ListMetricDescriptors(ctx context.Context) ([]*runtimeapi.MetricDescriptor, error)
|
||||||
|
// ListPodSandboxMetrics returns metrics of all running pods.
|
||||||
|
ListPodSandboxMetrics(ctx context.Context) ([]*runtimeapi.PodSandboxMetrics, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuntimeService interface should be implemented by a container runtime.
|
// RuntimeService interface should be implemented by a container runtime.
|
||||||
|
@ -64,11 +64,14 @@ type FakeRuntimeService struct {
|
|||||||
Called []string
|
Called []string
|
||||||
Errors map[string][]error
|
Errors map[string][]error
|
||||||
|
|
||||||
FakeStatus *runtimeapi.RuntimeStatus
|
FakeStatus *runtimeapi.RuntimeStatus
|
||||||
Containers map[string]*FakeContainer
|
Containers map[string]*FakeContainer
|
||||||
Sandboxes map[string]*FakePodSandbox
|
Sandboxes map[string]*FakePodSandbox
|
||||||
FakeContainerStats map[string]*runtimeapi.ContainerStats
|
FakeContainerStats map[string]*runtimeapi.ContainerStats
|
||||||
FakePodSandboxStats map[string]*runtimeapi.PodSandboxStats
|
FakePodSandboxStats map[string]*runtimeapi.PodSandboxStats
|
||||||
|
FakePodSandboxMetrics map[string]*runtimeapi.PodSandboxMetrics
|
||||||
|
FakeMetricDescriptors map[string]*runtimeapi.MetricDescriptor
|
||||||
|
FakeContainerMetrics map[string]*runtimeapi.ContainerMetrics
|
||||||
|
|
||||||
ErrorOnSandboxCreate bool
|
ErrorOnSandboxCreate bool
|
||||||
}
|
}
|
||||||
@ -153,12 +156,14 @@ func (r *FakeRuntimeService) popError(f string) error {
|
|||||||
// NewFakeRuntimeService creates a new FakeRuntimeService.
|
// NewFakeRuntimeService creates a new FakeRuntimeService.
|
||||||
func NewFakeRuntimeService() *FakeRuntimeService {
|
func NewFakeRuntimeService() *FakeRuntimeService {
|
||||||
return &FakeRuntimeService{
|
return &FakeRuntimeService{
|
||||||
Called: make([]string, 0),
|
Called: make([]string, 0),
|
||||||
Errors: make(map[string][]error),
|
Errors: make(map[string][]error),
|
||||||
Containers: make(map[string]*FakeContainer),
|
Containers: make(map[string]*FakeContainer),
|
||||||
Sandboxes: make(map[string]*FakePodSandbox),
|
Sandboxes: make(map[string]*FakePodSandbox),
|
||||||
FakeContainerStats: make(map[string]*runtimeapi.ContainerStats),
|
FakeContainerStats: make(map[string]*runtimeapi.ContainerStats),
|
||||||
FakePodSandboxStats: make(map[string]*runtimeapi.PodSandboxStats),
|
FakePodSandboxStats: make(map[string]*runtimeapi.PodSandboxStats),
|
||||||
|
FakePodSandboxMetrics: make(map[string]*runtimeapi.PodSandboxMetrics),
|
||||||
|
FakeContainerMetrics: make(map[string]*runtimeapi.ContainerMetrics),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,3 +718,65 @@ func (r *FakeRuntimeService) CheckpointContainer(_ context.Context, options *run
|
|||||||
func (f *FakeRuntimeService) GetContainerEvents(containerEventsCh chan *runtimeapi.ContainerEventResponse) error {
|
func (f *FakeRuntimeService) GetContainerEvents(containerEventsCh chan *runtimeapi.ContainerEventResponse) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetFakeMetricDescriptors sets the fake metrics descriptors in the FakeRuntimeService.
|
||||||
|
func (r *FakeRuntimeService) SetFakeMetricDescriptors(descs []*runtimeapi.MetricDescriptor) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
r.FakeMetricDescriptors = make(map[string]*runtimeapi.MetricDescriptor)
|
||||||
|
for _, d := range descs {
|
||||||
|
r.FakeMetricDescriptors[d.Name] = d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListMetricDescriptors gets the descriptors for the metrics that will be returned in ListPodSandboxMetrics.
|
||||||
|
func (r *FakeRuntimeService) ListMetricDescriptors(_ context.Context) ([]*runtimeapi.MetricDescriptor, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
r.Called = append(r.Called, "ListMetricDescriptors")
|
||||||
|
if err := r.popError("ListMetricDescriptors"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
descs := make([]*runtimeapi.MetricDescriptor, 0, len(r.FakeMetricDescriptors))
|
||||||
|
for _, d := range r.FakeMetricDescriptors {
|
||||||
|
descs = append(descs, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
return descs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFakePodSandboxMetrics sets the fake pod sandbox metrics in the FakeRuntimeService.
|
||||||
|
func (r *FakeRuntimeService) SetFakePodSandboxMetrics(podStats []*runtimeapi.PodSandboxMetrics) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
r.FakePodSandboxMetrics = make(map[string]*runtimeapi.PodSandboxMetrics)
|
||||||
|
for _, s := range podStats {
|
||||||
|
r.FakePodSandboxMetrics[s.PodSandboxId] = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPodSandboxMetrics returns the list of all pod sandbox metrics in the FakeRuntimeService.
|
||||||
|
func (r *FakeRuntimeService) ListPodSandboxMetrics(_ context.Context) ([]*runtimeapi.PodSandboxMetrics, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
r.Called = append(r.Called, "ListPodSandboxMetrics")
|
||||||
|
if err := r.popError("ListPodSandboxMetrics"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []*runtimeapi.PodSandboxMetrics
|
||||||
|
for _, sb := range r.Sandboxes {
|
||||||
|
s, found := r.FakePodSandboxMetrics[sb.Id]
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user