mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
This adds a new library, `//pkg/prometheus`, which contains just enough data
structures such that we can encode instrumentation information in Prometheus
information. These data structures are JSON-encodable, such that they can be
used over the `runsc` control channel for export (implemented in a future CL).
The existing `metric.go` library gains new functionality to export its own
data using this new export format.
This change is part of a series of changes to support Prometheus-style metrics
in `runsc`. Doing so requires making several seemingly-odd design decisions,
due to the following architectural constraints:
- Prometheus requires an HTTP server serving the `/metrics` endpoint.
- For performance reasons, the `runsc boot` process cannot run the `netpoller`
goroutine.
- Since we don't want to write our own HTTP server implementation, this
means the HTTP endpoint has to be served by a separate process that
remains running during the lifetime of the container.
- The `runsc boot` process is untrusted.
- This means we cannot trust metrics data that comes out of the Sentry.
Therefore, there needs to be an elaborate dance where we pre-register
metric metadata before starting any untrusted workload. Then, the server
relaying the metric data must verify the validity of metric values against
this metric metadata. This avoids leaking metrics, cardinality blow-ups,
and other such DoS vectors.
- This feature needs to be easy-to-use in a typical Docker setting.
- This means having the ability to just say
`--metrics-server=localhost:1337` in the `runsc` runtime entry in
`/etc/docker/daemon.json` and have that Just Work(TM), even when multiple
containers are running.
- Since only one process may listen on a port at a given time, this means
the metric server needs to be able to multiplex requests out to multiple
running sandboxes, and remain alive for the entire duration of either of
these sandboxes. However, it should also die when there are no sandboxes,
so that we don't end up with leftover metric servers lying around.
- For this reason, the metrics server runs *outside* of the usual
per-container cgroups.
- This also saves system resources by not running one server per sandbox.
- The metrics server must be exposed to the outside world, and cannot assume
that its clients are trustworthy.
- For this reason, a metrics server is bound to a runtime root directory,
and double-checks all that the sandboxes it is asked to follow actually
exist in this root directory.
PiperOrigin-RevId: 498039624
135 lines
4.6 KiB
Protocol Buffer
135 lines
4.6 KiB
Protocol Buffer
// Copyright 2018 The gVisor 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.
|
|
|
|
syntax = "proto3";
|
|
|
|
package gvisor;
|
|
|
|
import "google/protobuf/timestamp.proto";
|
|
|
|
// MetricMetadata contains all of the metadata describing a single metric.
|
|
message MetricMetadata {
|
|
// name is the unique name of the metric, usually in a "directory" format
|
|
// (e.g., /foo/count).
|
|
string name = 1;
|
|
|
|
// prometheus_name is the unique name of the metric in Prometheus format
|
|
// (e.g. foo_count).
|
|
string prometheus_name = 9;
|
|
|
|
// description is a human-readable description of the metric.
|
|
string description = 2;
|
|
|
|
// cumulative indicates that this metric is never decremented.
|
|
// Only applies for uint64-type metrics.
|
|
bool cumulative = 3;
|
|
|
|
// sync indicates that values from the final metric event should be
|
|
// synchronized to the backing monitoring system at exit.
|
|
//
|
|
// If sync is false, values are only sent to the monitoring system
|
|
// periodically. There is no guarantee that values will ever be received by
|
|
// the monitoring system.
|
|
bool sync = 4;
|
|
|
|
enum Type {
|
|
TYPE_UINT64 = 0;
|
|
TYPE_DISTRIBUTION = 1;
|
|
}
|
|
|
|
// type is the type of the metric value.
|
|
Type type = 5;
|
|
|
|
enum Units {
|
|
UNITS_NONE = 0;
|
|
UNITS_NANOSECONDS = 1;
|
|
}
|
|
|
|
// units is the units of the metric value.
|
|
Units units = 6;
|
|
|
|
message Field {
|
|
string field_name = 1;
|
|
repeated string allowed_values = 2;
|
|
}
|
|
|
|
// fields contains the metric fields for this metric.
|
|
repeated Field fields = 7;
|
|
|
|
// For distribution-typed metrics, this list contains the lower bound of all
|
|
// buckets (other than the underflow bucket, which has no lower bound).
|
|
// A distribution with n finite buckets should have n+1 values here.
|
|
// The (n+1)-th value is the upper bound of the n-th bucket, and the lower
|
|
// bound of the "overflow" bucket (which has no upper bound).
|
|
repeated int64 distribution_bucket_lower_bounds = 8;
|
|
}
|
|
|
|
// MetricRegistration contains the metadata for all metrics that will be in
|
|
// future MetricUpdates.
|
|
message MetricRegistration {
|
|
repeated MetricMetadata metrics = 1;
|
|
repeated string stages = 2;
|
|
}
|
|
|
|
// Samples contains the number of samples in each bucket of a distribution.
|
|
message Samples {
|
|
// new_samples contains the number of *new* samples in each bucket of a
|
|
// distribution metric. "New" means the number of new samples added since the
|
|
// last MetricValue update for this metric and combination of fields.
|
|
// Given a distribution metrics with `num_finite_buckets` finite buckets,
|
|
// this means:
|
|
// - num_samples[0] is the number of new samples in the "underflow" bucket,
|
|
// i.e. samples which are smaller than the lower bound of the
|
|
// distribution's first (0-th) finite bucket.
|
|
// - num_samples[i] is the number of new samples in the distribution's
|
|
// 0-based (i-1)-th finite bucket.
|
|
// - num_samples[num_finite_buckets+1] is the number of new samples in the
|
|
// distribution's last bucket, which is infinite (i.e. it has a lower
|
|
// bound but no upper bound).
|
|
repeated uint64 new_samples = 1;
|
|
}
|
|
|
|
// MetricValue the value of a metric at a single point in time.
|
|
message MetricValue {
|
|
// name is the unique name of the metric, as in MetricMetadata.
|
|
string name = 1;
|
|
|
|
// value is the value of the metric at a single point in time. The field set
|
|
// depends on the type of the metric.
|
|
oneof value {
|
|
uint64 uint64_value = 2;
|
|
Samples distribution_value = 3;
|
|
}
|
|
|
|
repeated string field_values = 4;
|
|
}
|
|
|
|
// StageTiming represents a new stage that's been reached by the Sentry.
|
|
message StageTiming {
|
|
string stage = 1;
|
|
google.protobuf.Timestamp started = 2;
|
|
google.protobuf.Timestamp ended = 3;
|
|
}
|
|
|
|
// MetricUpdate contains new values for multiple distinct metrics.
|
|
//
|
|
// Metrics whose values have not changed are not included.
|
|
message MetricUpdate {
|
|
repeated MetricValue metrics = 1;
|
|
// Timing information of initialization stages reached since last update.
|
|
// The first MetricUpdate will include multiple entries, since metric
|
|
// initialization happens relatively late in the Sentry startup process.
|
|
repeated StageTiming stage_timing = 2;
|
|
}
|