docker

package
v1.8.1 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2026 License: Apache-2.0 Imports: 36 Imported by: 0

Documentation

Overview

Package docker is a Docker-backed provider.Provider. It maps each ctrlplane Instance to one Docker container, named "cp-<instanceID>" so lookups by ID are O(1) inspect calls.

ManagedDockerExecutor provides a separate single-mutation custody path. You supply an authenticated authority, effect verifier, protected journal and pinned transport. It records delegation durably before sending. A lost response stays unresolved, and replay never sends again. Creation retains the actual Docker ID; removal uses that exact ID and treats NotFound as uncertainty.

FileManagedDockerJournal requires a private local POSIX directory outside restored controller database state. SDKManagedDockerTransport supports configured Unix sockets or TCP endpoints with optional verified TLS. Images must already be present by digest; the adapter never pulls or implicitly starts a container.

These components do not implement the complete managed provider or recovery profile. Your host still owns authenticated enrollment, fresh writer admission, restore quarantine and native lifecycle integration.

Index

Constants

View Source
const ManagedDockerJournalLimit = 65536

ManagedDockerJournalLimit bounds a complete row, including base64 encoded evidence.

View Source
const ManagedDockerProfile = "ctrlplane.docker.custody.v1"

ManagedDockerProfile identifies exact single-mutation Docker transport custody.

Variables

View Source
var ErrLogsNotImplemented = errors.New("docker: logs not implemented")

ErrLogsNotImplemented is returned when log streaming is requested but the docker exec/logs path hasn't been wired yet.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Host is the Docker daemon address (e.g., unix:///var/run/docker.sock).
	Host string `env:"CP_DOCKER_HOST" json:"host"`

	// Network is the Docker network to attach containers to.
	Network string `default:"bridge" env:"CP_DOCKER_NETWORK" json:"network"`

	// Registry is the default image registry prefix.
	Registry string `env:"CP_DOCKER_REGISTRY" json:"registry,omitempty"`
}

Config holds configuration for the Docker provider.

type FileManagedDockerJournal added in v1.8.0

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

FileManagedDockerJournal is a local POSIX custody adapter. Its directory must be pre-created, owned by the executor UID, mode 0700, on a filesystem supporting flock, atomic same-directory rename and file/directory fsync. It is not an NFS adapter. The trusted launcher must protect its storage and quarantine snapshot restore. This adapter cannot detect privileged rollback or provide cross-host writer admission. There is no deletion API. Closed and delegated rows survive executor restart.

func OpenFileManagedDockerJournal added in v1.8.0

func OpenFileManagedDockerJournal(directory string) (*FileManagedDockerJournal, error)

OpenFileManagedDockerJournal opens an existing protected directory. It neither creates deployment storage nor enrolls an executor or enables a managed profile.

func (*FileManagedDockerJournal) CompareAndSwap added in v1.8.0

func (j *FileManagedDockerJournal) CompareAndSwap(ctx context.Context, key string, expected, next []byte) (bool, error)

CompareAndSwap syncs bytes, atomically renames, and syncs the directory before success. Cancellation or I/O error after rename may leave the transition retained. The caller must recover by reading and must not infer that a failed claim permits a send.

func (*FileManagedDockerJournal) Load added in v1.8.0

func (j *FileManagedDockerJournal) Load(ctx context.Context, key string) ([]byte, error)

Load returns an owned bounded snapshot under the same process-shared lock as CAS.

type ManagedDockerAuthority added in v1.8.0

type ManagedDockerAuthority interface {
	VerifyRequest(ctx context.Context, request ManagedDockerRequest) error
	Admit(ctx context.Context, request ManagedDockerRequest) error
	SealResponse(ctx context.Context, request ManagedDockerRequest, response ManagedDockerResponse) (ManagedDockerCustody, error)
	VerifyCustody(ctx context.Context, request ManagedDockerRequest, response ManagedDockerResponse, custody ManagedDockerCustody) error
	NoDispatch(ctx context.Context, request ManagedDockerRequest, closedDigest string) (managed.ProviderInvocationFailure, error)
	VerifyNoDispatch(ctx context.Context, request ManagedDockerRequest, closedDigest string, witness managed.ProviderInvocationFailure) error
}

ManagedDockerAuthority is trusted configuration, not a request-selected resolver. VerifyRequest authenticates retained permission, receipt, exact transport semantics, backend identity and any original resource/process custody. Admit additionally checks current authority and the newly issued one-shot grant/marker before delegation. SealResponse recovers stable enrollment evidence without launching or sending Docker commands. VerifyCustody authenticates that evidence against this exact response. NoDispatch signs the permanently closed journal fact; its witness must bind the digest. Implementations must refuse absent enrollment, stale/replaced processes and restore quarantine. The library supplies no permissive default or external launcher setup.

type ManagedDockerCommand added in v1.8.0

type ManagedDockerCommand struct {
	Kind       managed.ProviderStepKind  `json:"kind"`
	Name       string                    `json:"name"`
	ResourceID string                    `json:"resource_id"`
	NetworkID  string                    `json:"network_id"`
	Service    *managed.ProvisionService `json:"service"`
}

ManagedDockerCommand contains non-secret inputs to one Docker mutation. Resource and network IDs are actual create response IDs. Names are creation hints only.

type ManagedDockerCustody added in v1.8.0

type ManagedDockerCustody struct {
	ResourceID      string                        `json:"resource_id"`
	Incarnation     string                        `json:"incarnation"`
	OriginalProcess *managed.OriginalProcessFacts `json:"original_process"`
	Attestation     []byte                        `json:"attestation"`
}

ManagedDockerCustody adds independently authenticated creation/incarnation facts. OriginalProcess is required for start; it is never synthesized from Docker inspection.

type ManagedDockerExecutor added in v1.8.0

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

ManagedDockerExecutor owns a journal and configured authority/transport pair. It is an independently usable single-step component, not the complete ManagedProvider.

func NewManagedDockerExecutor added in v1.8.0

func NewManagedDockerExecutor(journal ManagedDockerJournal, transport ManagedDockerTransport, authority ManagedDockerAuthority, verifier managed.ProviderEffectBindingVerifier, backend string) (*ManagedDockerExecutor, error)

NewManagedDockerExecutor refuses missing or typed-nil trusted dependencies.

func (*ManagedDockerExecutor) Execute added in v1.8.0

Execute claims durable delegation before calling transport once. Replay of delegated refuses, even when the earlier call may have failed before reaching Docker.

func (*ManagedDockerExecutor) Prepare added in v1.8.0

Prepare retains authenticated original inputs without granting a send. Exact replay succeeds; any altered command, permission, receipt or enrollment association refuses.

func (*ManagedDockerExecutor) Read added in v1.8.0

Read observes exact retained facts without producing a delegation grant.

func (*ManagedDockerExecutor) RecoverProviderEffectBinding added in v1.8.0

RecoverProviderEffectBinding only returns evidence retained before the transport.

func (*ManagedDockerExecutor) WitnessManagedProviderNoDispatch added in v1.8.0

WitnessManagedProviderNoDispatch closes prepared custody by the same CAS used by Execute. Once delegated, neither absence nor errors can produce this witness.

type ManagedDockerJournal added in v1.8.0

type ManagedDockerJournal interface {
	Load(ctx context.Context, key string) ([]byte, error)
	CompareAndSwap(ctx context.Context, key string, expected, next []byte) (bool, error)
}

ManagedDockerJournal is a protected durable byte CAS. Empty expected means absent. CompareAndSwap must be atomic across processes and durable before success. An error can mean committed but unacknowledged. Callers must never send after such an error. Rows and permanent closed/delegated states must not be deleted or restored backwards.

type ManagedDockerRecord added in v1.8.0

type ManagedDockerRecord struct {
	SchemaVersion managed.Decimal                    `json:"schema_version"`
	Request       ManagedDockerRequest               `json:"request"`
	State         string                             `json:"state"`
	Response      *ManagedDockerResponse             `json:"response"`
	Custody       *ManagedDockerCustody              `json:"custody"`
	Closure       *managed.ProviderInvocationFailure `json:"closure"`
}

ManagedDockerRecord is a bounded observation. Only complete has authenticated custody. delegated means possible effect; observed retains a response awaiting authentication. Neither state permits resend. Closed is a permanent affirmative no-dispatch fact.

type ManagedDockerRequest added in v1.8.0

type ManagedDockerRequest struct {
	BackendAuthority string                                `json:"backend_authority"`
	Permission       managed.WireProviderStepPermission    `json:"permission"`
	Receipt          managed.WireReceipt                   `json:"receipt"`
	Command          ManagedDockerCommand                  `json:"command"`
	Binding          *managed.ProviderEffectBindingFacts   `json:"binding"`
	Invocation       *managed.ProviderInvocationPermission `json:"invocation"`
	Retry            *ManagedDockerRetryEvidence           `json:"retry,omitempty"`
}

ManagedDockerRequest retains exact permission and independent receipt custody. Nonzero removal invocations require accepted Retry evidence and explicit authority.

type ManagedDockerResponse added in v1.8.0

type ManagedDockerResponse struct {
	ResourceID string    `json:"resource_id"`
	ObservedAt time.Time `json:"observed_at"`
}

ManagedDockerResponse records an actual successful API response, not authenticated process custody. In particular a returned creation ID does not establish enrollment.

type ManagedDockerRetryAuthority added in v1.8.0

type ManagedDockerRetryAuthority interface {
	VerifyRetry(ctx context.Context, request ManagedDockerRequest) error
	AdmitRetry(ctx context.Context, request ManagedDockerRequest) error
}

ManagedDockerRetryAuthority explicitly opts the configured authority into retries. VerifyRetry must reload the exact accepted records and independent receipts from the configured core store, including the retained retry request/event, predecessor closure certificate, root selection and native proof/commit associations. It may inspect historical records but must never manufacture fresh authority from them. AdmitRetry must additionally authenticate current native binding and consume the volatile grant from a newly accepted marker before transport. Reopening a saved marker, journal or receipt cannot recreate this grant. An error may consume it. These methods supplement full VerifyRequest; no permissive default is supplied.

type ManagedDockerRetryEvidence added in v1.8.0

type ManagedDockerRetryEvidence struct {
	Root          managed.RecoveryRecord[managed.ProviderStepRetryRoot]          `json:"root"`
	Permission    managed.RecoveryRecord[managed.ProviderInvocationPermission]   `json:"permission"`
	Authorization managed.RecoveryRecord[managed.ProviderStepRetryAuthorization] `json:"authorization"`
	Marker        managed.RecoveryRecord[managed.ProviderInvocationMarker]       `json:"marker"`
}

ManagedDockerRetryEvidence retains the accepted source and exact retry invocation. Marker is required before preparing transport custody. None of these records grants another send; the configured authority must independently authenticate all of them.

type ManagedDockerStartup added in v1.8.0

type ManagedDockerStartup struct {
	Entrypoint  []string `json:"entrypoint"`
	Arguments   []string `json:"arguments"`
	Environment []string `json:"environment"`
}

ManagedDockerStartup is private fixed startup material. It is never journaled or emitted as evidence. The configured resolver authenticates the complete descriptor.

type ManagedDockerStartupResolver added in v1.8.0

type ManagedDockerStartupResolver interface {
	ResolveManagedDockerStartup(ctx context.Context, service managed.ProvisionService) (ManagedDockerStartup, error)
}

ManagedDockerStartupResolver is read-only trusted host configuration. It must refuse stale enrollment, descriptor substitution or missing private startup inputs.

type ManagedDockerTransport added in v1.8.0

type ManagedDockerTransport interface {
	Execute(ctx context.Context, command ManagedDockerCommand) (string, error)
}

ManagedDockerTransport sends exactly one mutation, with no retry, adoption, name removal, compensating cleanup, pull, or NotFound-to-success conversion.

type Option added in v1.3.0

type Option func(*Provider) error

Option configures a Docker provider.

func WithConfig added in v1.3.0

func WithConfig(cfg Config) Option

WithConfig applies all non-zero fields from a Config struct. This is useful when loading configuration from files or environment variables.

func WithHost added in v1.3.0

func WithHost(host string) Option

WithHost sets the Docker daemon address (e.g., "unix:///var/run/docker.sock").

func WithNetwork added in v1.3.0

func WithNetwork(network string) Option

WithNetwork sets the Docker network to attach containers to.

func WithRegistry added in v1.3.0

func WithRegistry(registry string) Option

WithRegistry sets the default image registry prefix.

type Provider

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

Provider is a Docker-based infrastructure provider. Each Instance becomes one container; the container name encodes the instance ID for stateless lookups (no per-instance ProviderRef storage needed beyond the canonical "docker:<container_name>" string).

func New

func New(opts ...Option) (*Provider, error)

New creates a new Docker provider. Uses standard docker env (DOCKER_HOST, DOCKER_TLS_VERIFY, etc.) by default; pass WithHost to pin a specific socket. Network defaults to "bridge" but should be overridden to a named network when the provider is colocated with a router (e.g. Traefik) that needs to reach containers by DNS name.

func (*Provider) Capabilities

func (p *Provider) Capabilities() []provider.Capability

Capabilities returns the set of features this provider supports.

func (*Provider) Deploy

Deploy applies a new image / env to an existing container by recreating it. Docker doesn't support in-place image swap, so the implementation is: stop+remove the current container, then create a fresh one with the new spec. Same name, same network, new image.

For the initial provision case (where Provision already ran with the right image) Deploy is effectively a no-op — the container stays as-is. The caller (ctrlplane deploy.Service) treats success here as "release applied" and bumps the deployment state. Deploy applies per-service image / env updates, and any command, args, ports or resources the request sets, by recreating only the targeted containers within the live project network. Services not listed in req.Services keep running unchanged.

Per-service rollout for a multi-container project is "stop & replace each targeted container in turn" — Docker doesn't support in-place image swap. The Compose-project network stays up across the recreation so sibling services don't drop their network namespace.

func (*Provider) Deprovision

func (p *Provider) Deprovision(ctx context.Context, instanceID id.ID) error

Deprovision tears down every container in the project + the project network. Not-found is treated as success so deprovision is convergent — the goal is "project gone", not strict accounting.

func (*Provider) Exec

Exec is not yet implemented.

func (*Provider) HealthCheck added in v1.5.1

func (p *Provider) HealthCheck(ctx context.Context) (*provider.HealthStatus, error)

HealthCheck pings the docker daemon and reports reachability. The HealthChecker contract is "is this provider's control plane reachable" — so we use cli.Ping (which round-trips to the daemon) rather than docker info / version which load more state.

func (*Provider) Info

func (p *Provider) Info() provider.ProviderInfo

Info returns metadata about this provider. Local Docker has a fixed region of "local" with a default localhost location so studio catalog endpoints surface a usable region in dev environments where no datacenters have been registered yet.

func (*Provider) Logs

func (p *Provider) Logs(ctx context.Context, instanceID id.ID, opts provider.LogOptions) (io.ReadCloser, error)

Logs returns a stream of structured JSON log events (one {"ts":..., "stream":"stdout"|"stderr", "line":"..."} per line) from the container's stdout + stderr. When opts.Follow is true the stream stays open and emits new lines as the container writes them; the caller closes the returned ReadCloser to stop.

Honours opts.Tail (last N lines, "0" = all), opts.Since (only lines newer than this UTC time), and opts.Follow. Multiplexed docker frames are demuxed by demuxedDockerStream.

func (*Provider) Provision

Provision pulls the image, creates a container with the requested ports/env/labels, starts it, and returns the resulting endpoints.

Endpoints are emitted in two flavours per declared port:

  • in-network: http://cp-<instanceID>:<containerPort> — reachable from other containers on the same docker network. Preferred for service-to-service routing (Traefik joins this network and uses these URLs upstream).
  • public: http://localhost:<hostPort> — the random host port docker assigned. Useful when hitting a workspace from outside the docker network without a host-side proxy.

Re-provisioning the same instance ID is idempotent: any existing container with the same name is force-removed first so the create succeeds with the fresh config.

func (*Provider) Resources

func (p *Provider) Resources(ctx context.Context, instanceID id.ID) (*provider.ResourceUsage, error)

Resources returns a one-shot point-in-time sample of the container's CPU / memory / network usage via the docker stats API. The non-streaming variant gives us a single JSON document per call, which is what the metrics poller wants — it calls us every N seconds and stores the result in its own ring buffer.

Returns a zero-valued ResourceUsage (no error) when the container doesn't exist or the stats response is empty — the metrics poller treats "missing sample" as a gap, not a failure, so transient container-restart windows don't show up as poller errors.

func (*Provider) Restart

func (p *Provider) Restart(ctx context.Context, instanceID id.ID) error

Restart cycles every Main + Sidecar container in the project. Inits stay completed — restart is for live workload bouncing, not init re-runs.

func (*Provider) Rollback

func (p *Provider) Rollback(_ context.Context, _ id.ID, _ id.ID) error

Rollback is a no-op today — docker has no built-in release history, so rollback would have to recreate using the previous image which the deploy service already knows about and could route through Deploy.

func (*Provider) Scale

func (p *Provider) Scale(_ context.Context, _ id.ID, _ provider.ResourceSpec) error

Scale is a no-op for the docker provider — single-container instances don't have a horizontal scale axis. The kubernetes provider is the right home for replica scaling.

func (*Provider) Start

func (p *Provider) Start(ctx context.Context, instanceID id.ID) error

Start starts every Main + Sidecar container in the project. Init services are not restarted — they ran-once during provision.

func (*Provider) Status

func (p *Provider) Status(ctx context.Context, instanceID id.ID) (*provider.InstanceStatus, error)

Status aggregates inspect across every container in the project. Worst-of state wins (any Failed → Failed; otherwise any Restarting → Starting; otherwise any not-Running → Stopped). Ready is true only when every Main + Sidecar reports Running. Init containers don't gate readiness once they've completed (they appear as Stopped/exited 0 — the non-Init aggregation ignores them).

func (*Provider) Stop

func (p *Provider) Stop(ctx context.Context, instanceID id.ID) error

Stop sends SIGTERM to every Main + Sidecar container in the project. Default docker timeout (~10s) per container.

type SDKManagedDockerTransport added in v1.8.0

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

SDKManagedDockerTransport implements the fixed exact mutation profile. The client must be pinned by trusted configuration to the executor's backend authority. A raw client/socket is an authority-bearing dependency and must never be request supplied.

func NewSDKManagedDockerTransport added in v1.8.0

func NewSDKManagedDockerTransport(host, apiVersion string, transport *http.Transport, startup ManagedDockerStartupResolver) (*SDKManagedDockerTransport, error)

NewSDKManagedDockerTransport fixes the host/API version without environment lookup. The supplied transport carries trusted TLS credentials. Only canonical Unix sockets and explicit TCP host:port endpoints are supported. Custom dialers and proxies refuse; the adapter owns exact endpoint dialing. TLS uses verified HTTPS without fallback. Connection reuse, HTTP/2 and redirects are disabled to prevent transparent replay.

func (*SDKManagedDockerTransport) Close added in v1.8.0

func (t *SDKManagedDockerTransport) Close() error

Close releases this adapter's client connections without changing retained custody.

func (*SDKManagedDockerTransport) Execute added in v1.8.0

Execute issues one mutation and returns the actual create response ID or exact removal/start target ID. Docker 404 remains uncertain, never terminal success.

Jump to

Keyboard shortcuts

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