externalmetrics

package module
v0.0.0-...-85b7df0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 10, 2023 License: MIT Imports: 10 Imported by: 0

README

externalmetrics

GoDoc Go Report Card

package externalmetrics provides a dirt simple, lightweight, easily exstensible external metrics api server for Kubernetes.

Why?

The officialy supported method (https://github.com/kubernetes-sigs/custom-metrics-apiserver) is just f-ing inscruitable.

Not only that, but the documentation for what these servers need to do are awful. The best bet is a design doc on an old branch of some random kubernetes repo. The second bet is a medium article where someone describes how they discovered what one of these APIs needs to do, but not what that is.

This package is pretty simple; it has a New() function, an AddMetric() function, and a Serve() function.

No thrills, no tunables, bugger all excitement.

A complete form of the following example can be found in [./example](./example), but the nuts and bolts look like:

func main() {
    s := externalmetrics.New()
    s.AddMetric(context.Background(), externalmetrics.NamespaceAll, "my-metric", externalmetrics.Tick(time.Second), someIncrementingMetric)
    panic(s.Serve(listenAddr))
}

The function someIncrementingMetric might look like:

func someIncrementingMetric(ctx context.Context, namespace, name string) (result externalmetrics.Value, err error) {
    v := externalmetrics.NewValue(counterA)
    v.AddSelector("some-key", "A", counterA)
    v.AddSelector("some-key", "B", counterB)
    v.AddSelector("some-key", "C", counterC)
    return v, nil
}

The metrics exposed by this service can then be exposed in an HPA

Functions

func Tick

func Tick(d time.Duration) <-chan context.Context

Tick essentially wraps time.Tick, but sends a Notification instead of a time.Time

Types

type MetricFunc

type MetricFunc func(ctx context.Context, namespace, name string) (result Value, err error)

MetricFunc is a function which is run on events to update the latest value of a metric

type Server

type Server struct { ... }

Server provides an HTTP server, which provides metrics to horizontal pod autoscalers in the way which they expect.

This server handles things like retry logic, caching results, and handling namespacing of metrics, should they need it

func (*Server) AddMetric

func (s *Server) AddMetric(ctx context.Context, namespace, name string, c <-chan context.Context, f MetricFunc)

AddMetric registers a new metric function against the server, along with and runs it every in a go func every time something triggers c

c could be anything from a time.Tick, to something listening out for external events

func (Server) Serve

func (s Server) Serve(addr string) (err error)

Serve serves metrics over http on the

type Value

type Value struct { ... }

Value is the value of a metric, either as a basic value, or as a set of selectors for more granular selections

func (*Value) AddSelector

func (v *Value) AddSelector(label, value string, i int64)

AddSelector allows a value to contain a more granular value for HPAs that use labels

Why might you want this? Because each value creates a new go routine, with tickers, and notifiers, and so on, they can be quite expensive to run. If each metric requires a call to an external API, too, then the whole thing becomes a lot.

Not to mention the annoying thing of exposing a million dimensions like "/namespace/default/foo_A", "/namespace/default/foo_B", and "/namespace/default/foo_C" where they all do the same thing.

In this case, your MetricFunc merely needs to do:

v := NewValue(aValue)
v.AddSelector("dimension", "A", aValue)
v.AddSelector("dimension", "B", bValue)
v.AddSelector("dimension", "C", cValue)

Which exposes the metric "/namespace/default/foo?labelSelector=dimension=A" (etc.)

Sub Packages


Readme created from Go doc with goreadme

Documentation

Overview

package externalmetrics provides a dirt simple, lightweight, easily exstensible external metrics api server for Kubernetes.

Why?

The officially supported method (https://github.com/kubernetes-sigs/custom-metrics-apiserver) is just f-ing inscruitable.

Not only that, but the documentation for what these servers need to do are awful. The best bet is a design doc on an old branch of some random kubernetes repo. The second bet is a medium article where someone describes how they discovered what one of these APIs needs to do, but not what that is.

This package is pretty simple; it has a New() function, an AddMetric() function, and a Serve() function.

No thrills, no tunables, bugger all excitement.

A complete form of the following example can be found in `./example`, but the nuts and bolts look like:

func main() {
    s := externalmetrics.New()
    s.AddMetric(context.Background(), externalmetrics.NamespaceAll, "my-metric", externalmetrics.Tick(time.Second), someIncrementingMetric)
    panic(s.Serve(listenAddr))
}

The function `someIncrementingMetric` might look like:

func someIncrementingMetric(ctx context.Context, namespace, name string) (result externalmetrics.Value, err error) {
    v := externalmetrics.NewValue(counterA)
    v.AddSelector("some-key", "A", counterA)
    v.AddSelector("some-key", "B", counterB)
    v.AddSelector("some-key", "C", counterC)
    return v, nil
}

The metrics exposed by this service can then be exposed in an HPA

Index

Constants

View Source
const (
	NamespaceAll     = "*"
	NamespaceDefault = "default"
)

Variables

This section is empty.

Functions

func Tick

func Tick(d time.Duration) <-chan context.Context

Tick essentially wraps time.Tick, but sends a Notification instead of a time.Time

Types

type MetricFunc

type MetricFunc func(ctx context.Context, namespace, name string) (result Value, err error)

MetricFunc is a function which is run on events to update the latest value of a metric

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server provides an HTTP server, which provides metrics to horizontal pod autoscalers in the way which they expect.

This server handles things like retry logic, caching results, and handling namespacing of metrics, should they need it

func New

func New() Server

New creates an empty Server

func (*Server) AddMetric

func (s *Server) AddMetric(ctx context.Context, namespace, name string, c <-chan context.Context, f MetricFunc)

AddMetric registers a new metric function against the server, along with and runs it every in a go func every time something triggers `c`

`c` could be anything from a time.Tick, to something listening out for external events

func (Server) Serve

func (s Server) Serve(addr string) (err error)

Serve serves metrics over http on the

type Value

type Value struct {
	// contains filtered or unexported fields
}

Value is the value of a metric, either as a basic value, or as a set of selectors for more granular selections

func NewValue

func NewValue(v int64) Value

NewValue creates a simple Value, with an int64; this value is returned when an HPA makes a call without a specific selector, and so can be thought of as the base value

func (*Value) AddSelector

func (v *Value) AddSelector(label, value string, i int64)

AddSelector allows a value to contain a more granular value for HPAs that use labels

Why might you want this? Because each value creates a new go routine, with tickers, and notifiers, and so on, they can be quite expensive to run. If each metric requires a call to an external API, too, then the whole thing becomes a lot.

Not to mention the annoying thing of exposing a million dimensions like "/namespace/default/foo_A", "/namespace/default/foo_B", and "/namespace/default/foo_C" where they all do the same thing.

In this case, your MetricFunc merely needs to do:

v := NewValue(aValue)
v.AddSelector("dimension", "A", aValue)
v.AddSelector("dimension", "B", bValue)
v.AddSelector("dimension", "C", cValue)

Which exposes the metric "/namespace/default/foo?labelSelector=dimension=A" (etc.)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL