Piotr Icikowski
9dd25ff024
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
- `ProbeFunction` is now an interface for easier use - `ProbeFunction`s can be auto-updated with specified update interval - `StatefulProbes` changed into `ManualProbes` and implement `ProbeFunction` interface - `ManualProbes` allows for marking probe as unhealthy with custom cause - handlers now return JSON response with failed probes - handler's response can be set to verbose via `Kubeprobes` option or via `?v` request param BREAKING CHANGE: type definitions were replaced with more robust implementation.
136 lines
5.1 KiB
Markdown
136 lines
5.1 KiB
Markdown
# kubeprobes
|
|
|
|
Simple and effective package for implementing [Kubernetes liveness and readiness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/)' handler.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
go get -u pkg.icikowski.pl/kubeprobes
|
|
```
|
|
|
|
## Usage
|
|
|
|
The package provides `kubeprobes.New` function which returns a probes handler of type `kubeprobes.Kubeprobes`, which is compliant with `http.Handler` interface.
|
|
|
|
The handler serves two endpoints, which are used to implement liveness and readiness probes by returning either `200` (healthy) or `503` (unhealthy) status and JSON response with probes results:
|
|
|
|
- `/live` - endpoint for liveness probe;
|
|
- `/ready` - endpoint for readiness probe.
|
|
|
|
Default paths can be overriden with options described below. Accessing any other endpoint will return `404` status. By default, response body only contains a list of failed probes, but this behavior can be changed with provided option or by adding `?v` query parameter.
|
|
|
|
The `kubeprobes.New` function accepts following options as arguments:
|
|
|
|
- `kubeprobes.WithLivenessProbes(...)` - adds particular [probe functions](#probe-functions) to the list of liveness probes;
|
|
- `kubeprobes.WithLivenessPath("/some/liveness/path")` - sets liveness probe path to given path (default is `/live`);
|
|
- `kubeprobes.WithReadinessProbes(...)` - adds particular [probe functions](#probe-functions) to the list of readiness probes;
|
|
- `kubeprobes.WithReadinessPath("/some/readiness/path")` - sets readiness probe path to given path (default is `/ready`);
|
|
- `kubeprobes.WithVerboseOutput()` - enables verbose output by default (returns both failed and passed probes).
|
|
|
|
## Probes
|
|
|
|
In order to determine the state of particular element of application, probes need to be implemented either by creating [status determining function](#probe-functions) or by using simple and thread-safe [manual probes](#manual-probes).
|
|
|
|
### Probe functions
|
|
|
|
Probe functions (instances of `ProbeFunction` interface) are wrappers for functions that performs user defined logic with given interval of updates in order to determine whether the probe should be marked as healthy or not. Those functions should take no arguments and return error (if no error is returned, the probe is considered to be healthy; if error is returned, the probe is considered to be unhealthy). If given interval is less or equal zero, then function is only checked on probe creation and remains in determined state forever.
|
|
|
|
```go
|
|
someProbe := kubeprobes.NewProbeFunction("live", func() error {
|
|
// Some logic here
|
|
if time.Now().Weekday() == time.Wednesday {
|
|
// Fail only on wednesday!
|
|
return errors.New("It's wednesday, my dudes!")
|
|
}
|
|
return nil
|
|
}, 1 * time.Hour)
|
|
|
|
someOtherProbe := kubeprobes.NewProbeFunction("ready", func() error {
|
|
// Always healthy
|
|
return nil
|
|
}, 0) // This probe is checked once
|
|
|
|
// Use functions in probes handler
|
|
kp, _ := kubeprobes.New(
|
|
kubeprobes.WithLivenessProbes(someOtherProbe),
|
|
kubeprobes.WithReadinessProbes(someProbe),
|
|
)
|
|
```
|
|
|
|
### Manual probes
|
|
|
|
Manual probes (instances of `ManualProbe` interface) are objects that can be marked either as healthy or unhealthy and implement `ProbeFunction` for easy integration. Those objects utilize `sync.RMutex` mechanism to ensure thread-safety.
|
|
|
|
Those probes can be changed by user with provided methods:
|
|
|
|
- `Pass()` marks probe as healthy;
|
|
- `Fail()` marks probe as unhealthy with generic cause;
|
|
- `FailWithCause(someError)` marks probe as unhealthy with given error as cause.
|
|
|
|
```go
|
|
// Unhealthy by default
|
|
someProbe := kubeprobes.NewManualProbe("live")
|
|
someOtherProbe := kubeprobes.NewManualProbe("ready")
|
|
|
|
// Use it in probes handler
|
|
kp, _ := kubeprobes.New(
|
|
kubeprobes.WithLivenessProbes(someProbe),
|
|
kubeprobes.WithReadinessProbes(someOtherProbe),
|
|
)
|
|
|
|
// Can be later marked according
|
|
```
|
|
|
|
## Direct handler access
|
|
|
|
It is possible to fetch `http.Handler`s for liveness & readiness probes from `kubeprobes.Kubeprobes` instance as follows:
|
|
|
|
```go
|
|
kp, _ := kubeprobes.New(
|
|
// ...
|
|
)
|
|
|
|
livenessHandler := kp.LivenessHandler()
|
|
readinessHandler := kp.ReadinessHandler()
|
|
```
|
|
|
|
Those handler can be used for manually mounting them on other servers/routers/muxes (eg. `go-chi/chi`, `gorilla/mux`, `http`'s `ServeMux` etc.).
|
|
|
|
## Example usage
|
|
|
|
```go
|
|
// Create probe functions
|
|
appProbe := func() error {
|
|
// Some logic for checking app status
|
|
return nil
|
|
}
|
|
|
|
// Create stateful probes
|
|
live := kubeprobes.NewStatefulProbe()
|
|
ready := kubeprobes.NewStatefulProbe()
|
|
|
|
// Prepare handler
|
|
kp, err := kubeprobes.New(
|
|
kubeprobes.WithLivenessProbes(live),
|
|
kubeprobes.WithReadinessProbes(ready, appProbe),
|
|
kubeprobes.WithLivenessPath("/livez"),
|
|
kubeprobes.WithReadinessPath("/readyz"),
|
|
kubeprobes.WithVerboseOutput(),
|
|
)
|
|
if err != nil {
|
|
// Kubeprobes object is validated for invalid or conflicting paths! ;)
|
|
panic(err)
|
|
}
|
|
|
|
// Start the probes server
|
|
probes := &http.Server{
|
|
Addr: ":8080",
|
|
Handler: kp,
|
|
}
|
|
go probes.ListenAndServe()
|
|
|
|
// Mark probes as healthy
|
|
live.Pass()
|
|
ready.Pass()
|
|
```
|