Documentation ¶
Overview ¶
Package whalewatcher watches Docker and containerd containers as they come and go from the perspective of containers that are "alive", that is, only those containers with actual processes. In contrast, freshly created or "dead" containers without any processes are not tracked.
Furthermore, this package understands how containers optionally are organized into composer projects Docker compose.
As the focus of this module is on containers that are either in running or paused states, the envisioned use cases are tools that solely interact with processes, Linux-kernel namespaces, et cetera of these containers (often via various elements of the proc filesystem).
In order to cause only as low system load as possible this module monitors the container engine's container lifecycle-related events instead of stupid polling. In particular, this module decouples an application's access to the current state from tracking this container state.
Optionally, applications can subscribe to an events channel that passes on the lifecycle events whalewatcher receives.
Watcher ¶
A github.com/thediveo/whalewatcher/watcher.Watcher monitors ("watches") the containers of a single container engine instance when running its Watch method in a separate go routine. Cancel its passed context to stop watching and then Close the watcher in order to release any allocated resources.
Watchers return information about alive containers (and optionally their organization into projects) via a Portfolio. Please do not keep the Portfolio reference for long periods of time, as might change in case the watcher needs to reconnect to a container engine after losing API contact.
Please refer to example/main.go as an example:
package main import ( "context" "fmt" "sort" "github.com/thediveo/whalewatcher/watcher/moby" ) func main() { whalewatcher, err := moby.NewWatcher("unix:///var/run/docker.sock") if err != nil { panic(err) } ctx, cancel := context.WithCancel(context.Background()) fmt.Printf("watching engine ID: %s\n", whalewatcher.ID(ctx)) // run the watch in a separate go routine. go whalewatcher.Watch(ctx) // depending on application you don't need to wait for the first results to // become ready; in this example we want to wait for results. <-whalewatcher.Ready() // get list of projects; we add the unnamed "" project which automatically // contains all non-project (standalone) containers. projectnames := append(whalewatcher.Portfolio().Names(), "") sort.Strings(projectnames) for _, projectname := range projectnames { containers := whalewatcher.Portfolio().Project(projectname) if containers == nil { continue // doh ... gone! } fmt.Printf("project %q:\n", projectname) for _, container := range containers.Containers() { fmt.Printf(" container %q with PID %d\n", container.Name, container.PID) } fmt.Println() } // finally stop the watch cancel() whalewatcher.Close() }
Note: if an application needs to watch both Docker and "pure" containerd containers, then it needs to create two separate watchers, one for the Docker engine and another one for the containerd instance. The containerd watcher doesn't watch any Docker-managed containers (it cannot as Docker does not attach all information at the containerd level, especially not the container name).
Information Model ¶
The high-level view on whalewatcher's information model is as follows:
- A Watcher has a Portfolio, which is accessible using github.com/thediveo/whalewatcher/watcher.Watcher.Portfolio.
- A Portfolio consists of ComposerProject objects, including the "unnamed" project.
- A ComposerProject consists of Container descriptions; these descriptions represent only a purposely limited set of information, but can be augmented using "Rucksacks".
Portfolio ¶
The container information model starts with the Portfolio: a Portfolio consists of one or more projects in form of ComposerProject, including the "unnamed" ComposerProject (that contains all non-project containers).
ComposerProject ¶
Composer projects are either explicitly named, or the "zero" project that has no name (that is, the empty name). A ComposerProject consists of Container objects.
Container ¶
Containers store limited aspects about individual containers, such as their names, IDs, and PIDs.
Important: Container objects are immutable. For this reason, fetch the most recent updated state (where necessary) by retrieving the ComposerProject from the Watcher, and then querying for your Container using ComposerProject.Container.
Index ¶
- type ComposerProject
- type Container
- type Portfolio
- func (pf *Portfolio) Add(cntr *Container) bool
- func (pf *Portfolio) Container(nameorid string) *Container
- func (pf *Portfolio) ContainerTotal() (total int)
- func (pf *Portfolio) Names() []string
- func (pf *Portfolio) Project(name string) *ComposerProject
- func (pf *Portfolio) Remove(nameorid string, project string) (cntr *Container)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ComposerProject ¶
type ComposerProject struct { Name string // composer project name, guaranteed to be constant. // contains filtered or unexported fields }
ComposerProject represents a set of either running or paused (but always "somehow" alive) [Container]s belonging to a specific Docker Compose/Composer project.
As composer projects are artefacts above the first-level elements of the Docker container engine we can only reconstruct them in an extremely limited fashion from the live container information available to us. Yet that's fine in our context, as we just want to understand the concrete relationships between projects and their containers.
func (*ComposerProject) Container ¶
func (p *ComposerProject) Container(nameorid string) *Container
Container returns container information about the Container with the specified name or ID. If the name or ID wasn't found in this project, then nil is returned instead.
func (*ComposerProject) ContainerNames ¶
func (p *ComposerProject) ContainerNames() []string
ContainerNames returns the current list of container names belonging to this composer project.
func (*ComposerProject) Containers ¶
func (p *ComposerProject) Containers() []*Container
Containers returns the current list of containers belonging to this composer project.
func (*ComposerProject) SetPaused ¶ added in v0.3.0
func (p *ComposerProject) SetPaused(nameorid string, paused bool) *Container
SetPaused changes a Container's Paused state, obeying the design restriction that Container objects are immutable. It returns the container in its new state.
func (*ComposerProject) String ¶
func (p *ComposerProject) String() string
String returns a textual representation of a composer project with its containers (rendering names, but not IDs).
type Container ¶
type Container struct { ID string // unique identifier of this container. Name string // user-friendly name of this container. Labels map[string]string // labels assigned to this container. PID int // PID of container's initial ("ealdorman") process. Project string // optional composer project name, or zero. Paused bool // true if container is paused, false if running. Rucksack interface{} // optional additional application-specific container information. }
Container is a deliberately limited view on containers, dealing with only those few bits of data we're interested in for watching alive containers and how they optionally are organized into composer projects.
Please note that Container objects are considered immutable, so there's no locking them for updating.
Containers to considered to be alive from the perspective of the whalewatcher module when they have an initial process (which might be frozen) and thus a PID corresponding with that initial process. In contrast, we don't care about containers which are either dead without any container process(es) or are just yet created and thus still without any container process(es).
The Rucksack supports storing additional application-specific container (and container engine-specific) information; see also github.com/thediveo/whalewatcher/engineclient.RucksackPacker.
func (Container) ProjectName ¶
ProjectName returns the name of the composer project for this container, if any; otherwise, it returns "" if a container isn't associated with a composer project.
type Portfolio ¶
type Portfolio struct {
// contains filtered or unexported fields
}
Portfolio represents all known composer projects, including the "zero" (unnamed) project. The "zero" project has the zero name and contains all containers that are not part of any named composer project. The Portfolio manages projects implicitly when adding and removing containers belonging to projects. Thus, there is no need to explicitly add or delete composer projects.
func NewPortfolio ¶ added in v0.2.0
func NewPortfolio() *Portfolio
NewPortfolio returns a new Portfolio.
func (*Portfolio) Add ¶ added in v0.2.0
Add a container to the portfolio, creating also its composer project if that is not yet known. Returns true if the container was newly added, false if it already exists.
func (*Portfolio) Container ¶ added in v0.3.0
Container returns the Container with the specified name, regardless of which project it is in. It returns nil, if no container with the specified name could be found.
func (*Portfolio) ContainerTotal ¶
ContainerTotal returns the total number of containers over all projects, including non-project "standalone" containers.
func (*Portfolio) Project ¶
func (pf *Portfolio) Project(name string) *ComposerProject
Project returns the project with the specified name (including the zero project name), or nil if no project with the specified name currently exists.
func (*Portfolio) Remove ¶ added in v0.2.0
Remove a container identified by its ID or name as well as its composer project name from the portfolio, removing its composer project if it was the only container left in the project.
The information about the removed container is returned, otherwise if no such container exists, nil is returned instead.
Directories ¶
Path | Synopsis |
---|---|
Package engineclient defines the EngineClient interface between concrete container engine adaptor implementations and the engine-neutral watcher core.
|
Package engineclient defines the EngineClient interface between concrete container engine adaptor implementations and the engine-neutral watcher core. |
containerd
Package containerd implements the containerd EngineClient.
|
Package containerd implements the containerd EngineClient. |
moby
Package moby implements the Docker/Moby EngineClient.
|
Package moby implements the Docker/Moby EngineClient. |
test
|
|
matcher
Package matcher provides [Gomega] TDD matchers for certain whalewatcher elements, such as for matching container names or IDs.
|
Package matcher provides [Gomega] TDD matchers for certain whalewatcher elements, such as for matching container names or IDs. |
mockingmoby
Package mockingmoby is a very minimalist Docker mock client designed for simple unit tests in the whalewatcher package.
|
Package mockingmoby is a very minimalist Docker mock client designed for simple unit tests in the whalewatcher package. |
Package watcher allows keeping track of the currently alive containers of a container engine.
|
Package watcher allows keeping track of the currently alive containers of a container engine. |
containerd
Package containerd provides a container Watcher for containerd engines.
|
Package containerd provides a container Watcher for containerd engines. |
moby
Package moby provides a container Watcher for Docker/Moby engines.
|
Package moby provides a container Watcher for Docker/Moby engines. |