Documentation ¶
Overview ¶
Package turtlefinder provides a Containerizer that auto-detects container engines and automatically creates workload watchers for them. It supports both “permanent” daemons as well as socket-activated “don't-call-them-daemons”. Additionally, it also detects the hierarchy of container engines, such as containerd-in-Docker and podman-in-Docker.
Supported Container Engines ¶
The following container engines are supported:
- Docker/Moby
- containerd
- CRI-O
- podman (via Docker-compatible API only)
Supported Socket Activators ¶
The following socket activators are supported:
Quick Start ¶
That's all that is necessary:
containerizer := turtlefinder.New()
Boringly simple, right?
The turtlefinder containerizer.Containerizer is safe to be used in concurrent discoveries.
Principles of “Turtle” Discovery ¶
A turtlefinder supports two different container engine discovery mechanisms:
- based on well-known engine process names; please note that this works for “always on” engine daemons, such as “dockerd” (even if this is initially socket-activated on systemd installations).
- based on well-known socket activators, such as “systemd”, in combination with well-known API socket names (rather, suffixes). This method is much more involved when compared to the well-known always-on process name method, but allows discovering especially usually short-lived “podman” services.
The turtlefinder then spins up background watchers as required that synchronize with the workload state of the detected container engines. Also, old engine watchers get retired as their engine processes die. This workload state information is then returned as the list of discovered containers, including the hierarchy of container engines, based on which engine is placed inside a container managed by another engine.
Well-Known Process Name Discovery ¶
Basically, upon a container query the turtlefinder containerizer first looks for any newly seen container engines, based on container engine process names. The engine discovery can be extended by pluging in new engine detectors (and adaptors).
Well-known Socket Activation Name Discovery ¶
For “short-lived” container engine services that terminate themselves whenever they go idle, we unfortunately need a more involved discovery mechanism. More involved, as we don't want to slow down discovery by constantly looking for something that isn't even installed in the system, so we need to do some optimization.
The general idea is to look for well-known socket activators, namely “systemd”. If found (even multiple times!), we scan such an activator for its listening unix domain sockets and determine their file system paths. If we find a matching path (rather, a matching suffix, such as “podman.sock”) we spin up a suitable background watcher. Of course, this background watcher will keep the container engine alive, but then we also need this service in constant monitoring.
The difficult part here is to avoid repeated unnecessary costly socket activator discoveries. We thus keep some state information about a socket activator's socket-related setup and only rediscover upon noticing changes in its socket configuration (which rarely if ever occurs).
Engines in Engines ¶
A defining feature of the turtlefinder is that it additionally determines the hierarchy of container engines, such as when a container engine is hosted inside a container managed by a (parent) container engine. This hierarchy later gets propagated to the individual containers in form of a so-called “prefix”, attached in form of a special container label.
Such engine-in-engine configurations are actually not so unknown:
- Docker Desktop
- Kubernetes in Docker (KinD)
- podman in Docker
Decoration ¶
Finally, the decoration of the discovered containers uses the usual (extensible) lxkns github.com/thediveo/lxkns/decorator.Decorator mechanism as part of the overall discovery.
Index ¶
Constants ¶
const PrefixSeparator = "/"
PrefixSeparator is the separator used in hierarchical prefixes.
const TurtlefinderContainerPrefixLabelName = "turtlefinder/container/prefix"
TurtlefinderContainerPrefixLabelName defines the label name for attaching prefix information about the engine-hierarchy to containers. Discovery client can use these container labels to find out the hierarchy of containers. For instance, if container "A" is managed by a container engine hosted inside container "B", then container "A" is labelled with prefix "B".
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Contexter ¶
Contexter supplies a TurtleFinder with a suitable context for long-running container engine workload watching.
type Engine ¶
type Engine struct { watcher.Watcher // engine watcher (doubles as engine adapter). ID string // engine ID. Version string // engine version. Done chan struct{} // closed when watch is done/has terminated. PPIDHint model.PIDType // PID of engine's process; for container PID translation. }
Engine watches a single container engine process for signs of container workload life, using the supplied "whale watcher".
Engine objects then can be queried for their workload, that is, the list of currently alive (running/paused) containers they manage.
An Engine can be “done” at any time when the container engine process terminates or otherwise disconnects the watcher. In this case, the Done channel will be closed.
func NewEngine ¶
NewEngine returns a new Engine given the specified watcher. As NewEngine returns, the Engine is already "warming up" and has started watching (using the given context).
ppidhint optionally specifies a container engine's immediate parent process. This information is later necessary for lxkns to correctly translate container PIDs. When activating a socket-activated engine, the process tree scan does never include the engine, as this is only activated after the scan. In order to still allow lxkns to translate container PIDs related to newly socket-activated engines, we assume that the engine's parent process PID is in the same PID namespace, so we can also use that for correct PID translation.
func (*Engine) Containers ¶
Containers returns the alive containers managed by this engine, using the associated watcher.
The containers returned will reference a model.ContainerEngine and thus are decoupled from a turtlefinder's (container) Engine object.
type NewOption ¶
type NewOption func(*TurtleFinder)
NewOption represents options to New when creating a new turtle finder.
func WithGettingOnlineWait ¶
WithGettingOnlineWait sets the maximum duration to wait for our workload view of a newly discovered container engine to become synchronized before proceeding with a container discovery. If the initial synchronisation phase takes longer, it won't be aborted. This option instead controls the maximum wait before proceeding with discovering containers from the already known engine workloads.
func WithWorkers ¶
WithWorkers sets the maximum number of parallel container engine queries on the same TurtleFinder. A maximum number of zero or less is taken as GOMAXPROCS instead. Please note that this maximum applies to all concurrent TurtleFinder.Containers calls, and not to individual TurtleFinder.Containers calls separately.
type Overseer ¶
type Overseer interface {
Engines() []*model.ContainerEngine
}
Overseer gives access to information about container engines currently monitored.
turtlefinder.Turtlefinder objects implement the Overseer interface to allow code given only a containerizer.Containerizer to query the currently monitored container engine instances.
var c containerizer.Containerizer o, ok := c.(turtlefinder.Overseer) if ok { engines := o.Engines() }
type TurtleFinder ¶
type TurtleFinder struct {
// contains filtered or unexported fields
}
TurtleFinder implements the lxkns Containerizer interface to discover alive containers from one or more container engines. It can be safely used from multiple goroutines.
On demand, a TurtleFinder scans a process list for signs of container engines and then tries to contact the potential engines in order to watch their containers.
func New ¶
func New(contexter Contexter, opts ...NewOption) *TurtleFinder
New returns a TurtleFinder object for further use. The supplied contexter is called whenever a new container engine has been found and its workload is to be watched: this contexter should return a suitable (long-running) context it preferably has control over, in order to properly shut down the "background" goroutine resources (indirectly) used by a TurtleFinder.
Further options (NewOption, such as WithWorkers and WithGettingOnlineWait) allow to customize the TurtleFinder object returned.
func (*TurtleFinder) Close ¶
func (f *TurtleFinder) Close()
Close closes all resources associated with this turtle finder. This is an asynchronous process. Make sure to also cancel or have already cancelled the context
func (*TurtleFinder) Containers ¶
func (f *TurtleFinder) Containers( ctx context.Context, procs model.ProcessTable, pidmap model.PIDMapper, ) []*model.Container
Containers returns the current container state of (alive) containers from all discovered container engines.
func (*TurtleFinder) EngineCount ¶
func (f *TurtleFinder) EngineCount() int
EngineCount returns the number of container engines currently under watch. Callers might want to use the Engines method instead as EngineCount bases on it (because we don't store an explicit engine count anywhere).
func (*TurtleFinder) Engines ¶
func (f *TurtleFinder) Engines() []*model.ContainerEngine
Engines returns information about the container engines currently being monitored.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package activator defines the plugin interfaces for detecting “socket activators” (such as “systemd”) as well as detecting socket-activated container engines.
|
Package activator defines the plugin interfaces for detecting “socket activators” (such as “systemd”) as well as detecting socket-activated container engines. |
all
Package all pulls in all socket-activator detectors, as well as socket-activated engine detectors.
|
Package all pulls in all socket-activator detectors, as well as socket-activated engine detectors. |
podman
Package podman implements the socket-activated podman engine API endpoint and process detector.
|
Package podman implements the socket-activated podman engine API endpoint and process detector. |
systemd
Package systemd implements the the socket-activator detector for systemd processes.
|
Package systemd implements the the socket-activator detector for systemd processes. |
Package detector defines the plugin interface between the TurtleFinder and its container engine detector plugins.
|
Package detector defines the plugin interface between the TurtleFinder and its container engine detector plugins. |
all
Package all pulls in all turtlefinder engine detectors.
|
Package all pulls in all turtlefinder engine detectors. |
containerd
Package containerd implements the engine detector for containerd processes.
|
Package containerd implements the engine detector for containerd processes. |
crio
Package crio implements the engine detector for cri-o engine processes.
|
Package crio implements the engine detector for cri-o engine processes. |
moby
Package moby implements the engine detector for Docker “dockerd” processes.
|
Package moby implements the engine detector for Docker “dockerd” processes. |
Package unsorted provides the unsorted variant of os.ReadDir, for those many situations where it really doesn't matter whether directory entries are sorted, or not.
|
Package unsorted provides the unsorted variant of os.ReadDir, for those many situations where it really doesn't matter whether directory entries are sorted, or not. |