Documentation
¶
Overview ¶
Package devcontainer is the top-level entry point for the devcontainer runtime library. The high-level engine API will land in subsequent milestones; this milestone exposes the configuration resolution surface.
Index ¶
- Constants
- Variables
- func IsLifecycleError(err error) bool
- type AttachOptions
- type ComposeBackend
- type DownOptions
- type Engine
- func (e *Engine) Attach(ctx context.Context, id WorkspaceID) (*Workspace, error)
- func (e *Engine) AttachWith(ctx context.Context, id WorkspaceID, opts AttachOptions) (*Workspace, error)
- func (e *Engine) Down(ctx context.Context, ws *Workspace, opts DownOptions) error
- func (e *Engine) Exec(ctx context.Context, ws *Workspace, opts ExecOptions) (ExecResult, error)
- func (e *Engine) ExecByID(ctx context.Context, id WorkspaceID, opts ExecOptions) (ExecResult, error)
- func (e *Engine) RunLifecycle(ctx context.Context, ws *Workspace, phase config.LifecyclePhase) error
- func (e *Engine) Shutdown(ctx context.Context, ws *Workspace) error
- func (e *Engine) Up(ctx context.Context, opts UpOptions) (*Workspace, error)
- type EngineOptions
- type ExecOptions
- type ExecResult
- type HostCommand
- type HostExecResult
- type HostExecutor
- type LifecycleError
- type PullPolicy
- type ResolveOptions
- type ResolvedConfig
- type Substituter
- type UpOptions
- type Workspace
- type WorkspaceID
Constants ¶
const ( LabelDevcontainerID = "dev.containers.id" LabelLocalWorkspaceFolder = "dev.containers.localWorkspaceFolder" LabelConfigPath = "dev.containers.configPath" LabelEngine = "dev.containers.engine" )
Common labels written to every container the engine creates. Labels are the source of truth for container ↔ workspace mapping; container names are deterministic but not relied upon for lookup.
Variables ¶
var ErrHostExecutorNotConfigured = errors.New("host executor not configured (set EngineOptions.HostExecutor)")
ErrHostExecutorNotConfigured is returned (wrapped in *LifecycleError) when a host-side hook is configured in devcontainer.json but the engine has no HostExecutor to dispatch it. Callers wanting to detect this specifically use errors.Is.
Functions ¶
func IsLifecycleError ¶
IsLifecycleError reports whether err is a *LifecycleError.
Types ¶
type AttachOptions ¶
type AttachOptions struct {
// LocalEnv overrides os.Environ() for the substituter's localEnv
// pass. Nil means use the current process environment.
LocalEnv map[string]string
}
AttachOptions configures Engine.Attach. The default zero value is fine for most callers — it discovers the container by label and reads the host process environment for any localEnv references the substituter might still need.
type ComposeBackend ¶ added in v0.2.0
type ComposeBackend int
ComposeBackend selects between the legacy shellout and the new runtime-agnostic native orchestrator for compose-source projects.
const ( // ComposeBackendShellout (default) uses runtime.ComposeRuntime // — `docker compose` v2 plugin under the hood. Reliable for // Docker, refused-with-typed-error for backends that don't // implement the sub-interface (i.e. applecontainer). ComposeBackendShellout ComposeBackend = 0 // ComposeBackendNative uses compose.Orchestrator driving // runtime.Runtime primitives. Backend-agnostic; requires the // backend to implement CreateNetwork / CreateVolume / // ListContainers / ListImages / RemoveImage / RemoveNetwork / // RemoveVolume. ComposeBackendNative ComposeBackend = 1 )
type DownOptions ¶
type DownOptions struct {
// Remove, when true, removes the container after stopping it. Default
// false leaves the container in stopped state for fast subsequent Up.
Remove bool
// RemoveVolumes, when true with Remove, also removes anonymous volumes
// the container created. Has no effect when Remove is false.
RemoveVolumes bool
// Events optionally receives structured engine events for the duration
// of this Down call (container.stopped, container.removed). See package
// events (experimental until v1.0.0).
//
// Ownership: the caller owns the channel. The engine only writes —
// it never closes the channel. The caller MUST NOT close it before
// Down returns.
Events chan<- events.Event
}
DownOptions configures Engine.Down.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine drives the devcontainer lifecycle on top of a Runtime.
func New ¶
func New(opts EngineOptions) (*Engine, error)
New constructs an Engine. Returns an error if Runtime is nil or the feature store cannot be built.
func (*Engine) Attach ¶
Attach finds an existing workspace container by its devcontainer id and returns a *Workspace with a substituter bound to its live env.
Returns *runtime.ContainerNotFoundError if no container with the matching label exists. The returned workspace's Config.LocalEnv is the AttachOptions.LocalEnv (or os.Environ() if nil) — note that LocalWorkspaceFolder and ConfigPath cannot be recovered from a running container alone, so callers needing those should use Up.
The returned Workspace.Config is the MINIMAL form (LocalWorkspaceFolder, ContainerWorkspaceFolder, ContainerUser/RemoteUser, source kind plus any image-metadata-merged fields). Devcontainer.json-only fields (Lifecycle hooks, Mounts, Customizations, Features) are NOT reconstructed here — Attach does not re-read the source devcontainer.json. Callers that need the full ResolvedConfig should either call Resolve directly or use Engine.Up. See the Workspace type docs for the full breakdown.
func (*Engine) AttachWith ¶
func (e *Engine) AttachWith(ctx context.Context, id WorkspaceID, opts AttachOptions) (*Workspace, error)
AttachWith is Attach plus options.
func (*Engine) Down ¶
Down stops the workspace's container. With opts.Remove, the container is also removed (matching shutdownAction=stopContainer style cleanup).
For compose workspaces, Down maps to `docker compose stop` (without Remove) or `docker compose down` (with Remove) — i.e., the whole project is treated as a unit. This is asymmetric vs image/build workspaces where Down only touches the workspace's primary container, but matches the spec's stopCompose shutdownAction semantics.
Down is safe to call on a workspace whose container has already been stopped or removed externally — the underlying ContainerNotFoundError is treated as success.
func (*Engine) Exec ¶
func (e *Engine) Exec(ctx context.Context, ws *Workspace, opts ExecOptions) (ExecResult, error)
Exec runs a command inside the workspace's container. Strings in opts.Cmd, opts.Env values, opts.User, and opts.WorkingDir are substituted against the live container's environment before being handed to the runtime. ${containerEnv:VAR} resolves to the container's actual value; missing entries substitute to empty string with a (discarded) warning, matching VS Code semantics.
func (*Engine) ExecByID ¶
func (e *Engine) ExecByID(ctx context.Context, id WorkspaceID, opts ExecOptions) (ExecResult, error)
ExecByID is a convenience wrapper around Attach + Exec for callers that hold only a WorkspaceID. Hot-loop callers that hold a *Workspace from Up should call Exec directly to avoid re-inspecting the container on every invocation.
func (*Engine) RunLifecycle ¶
func (e *Engine) RunLifecycle(ctx context.Context, ws *Workspace, phase config.LifecyclePhase) error
RunLifecycle executes a single named lifecycle phase against the workspace, applying idempotency markers. Phases run in-container except initialize, which runs on the host.
A phase may have multiple LifecycleCommand hooks (one per metadata layer that contributed); they run in order [base image label entries → each feature → user devcontainer.json] per spec. The marker covers the whole phase: any one hook's non-zero exit aborts and re-runs on next Up.
User commands go through the workspace Substituter so ${containerEnv:*} resolves against the live container.
Returns nil if the phase has no commands configured. Returns a *LifecycleError if any hook exited non-zero.
func (*Engine) Shutdown ¶
Shutdown tears the workspace down according to its devcontainer.json `shutdownAction`. Use this for editor-close / idle-timeout style teardown where the spec field should drive behavior. For unconditional teardown (always stop, optionally remove), use Down — it is the caller's explicit "I want this gone" call.
Mapping (per https://containers.dev/implementors/json_reference/):
- "none": no-op; container left running.
- "stop", "stopContainer", "" (unset, image/build source): stop the container; do not remove. Restart-friendly.
- "stopCompose", "" (unset, compose source): `docker compose stop` on the project (containers preserved); for full teardown including volumes, callers should use Down with Remove=true.
"" (unset) defaults to the source-appropriate stop variant, matching upstream @devcontainers/cli behavior.
Idempotent: calling Shutdown on an already-stopped workspace returns nil.
func (*Engine) Up ¶
Up resolves the workspace's devcontainer.json, ensures its container is running, and returns a *Workspace ready for Exec.
Re-attach semantics:
- existing running container with our label → attach (no restart)
- existing stopped container → restart, attach
- existing + UpOptions.Recreate=true → stop + remove, fresh create
- no existing container → fresh create
Image source only in this milestone. Build / compose return runtime.ErrNotImplemented.
type EngineOptions ¶
type EngineOptions struct {
// Runtime is the container backend. Required.
Runtime runtime.Runtime
// FeatureStore overrides the default feature store. Default:
// feature.NewDiskStore with the cache and auth options below. Tests
// substitute this with an in-memory store; production callers
// usually leave it nil and configure via FeatureCacheDir / OCIKeychain
// instead.
FeatureStore feature.Store
// FeatureCacheDir overrides the default OCI / HTTPS feature cache
// location (os.UserCacheDir()/devcontainer-go/features). Ignored if
// FeatureStore is set explicitly.
FeatureCacheDir string
// OCIKeychain provides credentials for OCI feature pulls. Nil falls
// back to authn.DefaultKeychain (ambient docker config / env vars /
// credential helpers). Callers with short-lived registry tokens
// (e.g. ECR via STS, GCR via metadata-server) supply a custom
// Keychain that returns fresh credentials per call. Ignored if
// FeatureStore is set explicitly.
OCIKeychain authn.Keychain
// FeatureDownloadHeaders are additional headers to send on HTTPS
// feature fetches. Ignored if FeatureStore is set explicitly.
FeatureDownloadHeaders map[string]string
// FeatureHTTPSClient overrides the default *http.Client for HTTPS
// feature fetches. Tests use this to drive httptest servers.
// Ignored if FeatureStore is set explicitly.
FeatureHTTPSClient *http.Client
// StrictFeatureVersionMatch controls how the engine decides whether
// a feature recorded in a base image's devcontainer.metadata label
// satisfies the request. Default false (permissive: id match plus
// baked semver >= requested). True requires byte-level equality on
// the resolved digest — for reproducible builds. See
// design/features.md §10.3.
StrictFeatureVersionMatch bool
// HostExecutor enables host-side spec hooks (initializeCommand,
// future secretsCommand). Nil means host hooks return a
// *LifecycleError wrapping ErrHostExecutorNotConfigured, since
// host execution is opt-in and security-sensitive — see
// HostExecutor docs.
HostExecutor HostExecutor
// ComposeBackend selects how compose-source devcontainers are
// brought up. ComposeBackendShellout (default) uses the legacy
// runtime.ComposeRuntime sub-interface, which on docker shells
// out to the `docker compose` v2 plugin. ComposeBackendNative
// uses the runtime-agnostic compose.Orchestrator under compose/
// driving runtime.Runtime primitives directly (no shellout, no
// compose plugin dependency, works on every backend that
// satisfies the §4 primitive surface).
//
// See design/compose-native.md §10 for the rollout schedule:
// Shellout stays default until a confirmed-green release on
// Native; then the default flips and the shellout path is
// deleted.
ComposeBackend ComposeBackend
}
EngineOptions configures a new Engine.
type ExecOptions ¶
type ExecOptions struct {
Cmd []string
Env map[string]string
User string
WorkingDir string
Tty bool
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
// SkipUserEnvProbe, when true, makes Exec bypass the merge of
// probedEnv AND cfg.RemoteEnv into the process environment.
// Only opts.Env (after substitution) plus whatever the runtime
// inherits from the container reaches the exec'd process.
//
// Default false: every Exec inherits both probedEnv (so PATH and
// other vars set by the user's rc files are visible — nvm/asdf/
// feature-installed tools just work) and RemoteEnv (the
// devcontainer.json author's declared env).
//
// Set this for callers that need a clean, deterministic
// environment — internal probes, low-level fs operations,
// DiscoverPath-style helpers that read raw container env.
SkipUserEnvProbe bool
// EmitEvents, when true and Events is non-nil, sends ExecStartEvent
// and ExecCompletedEvent for this call. Default false: hot-loop
// callers (readiness probes that run hundreds of execs per minute)
// would otherwise drown the events channel.
EmitEvents bool
// Events optionally receives ExecStartEvent / ExecCompletedEvent for
// this call. Used only when EmitEvents is true. See package events
// (experimental until v1.0.0).
//
// Ownership: the caller owns the channel. The engine only writes —
// it never closes the channel. The caller MUST NOT close it before
// Exec returns.
Events chan<- events.Event
}
ExecOptions configures Engine.Exec. Cmd, Env, User, and WorkingDir all pass through Workspace.Substituter so ${containerEnv:*} placeholders resolve against the live container.
type ExecResult ¶
type ExecResult struct {
ExitCode int
Stdout string // populated only if ExecOptions.Stdout was nil
Stderr string // populated only if ExecOptions.Stderr was nil
}
ExecResult is the outcome of Engine.Exec.
type HostCommand ¶
type HostCommand struct {
// Shell is a single shell command line (`sh -c <Shell>` style).
// Mutually exclusive with Exec.
Shell string
// Exec is a literal argv invocation (no shell). Mutually
// exclusive with Shell.
Exec []string
// Env is merged on top of the host process environment.
// Implementations decide whether to filter the inherited host
// env (e.g. drop secrets) or pass it through.
Env map[string]string
// WorkingDir is the host directory to run in. Empty leaves the
// choice to the executor; the engine populates this with the
// workspace's LocalWorkspaceFolder for spec hooks.
WorkingDir string
}
HostCommand is the input to HostExecutor.ExecHost. Shape mirrors runtime.ExecOptions / config.Command so callers building both can reuse mental model.
type HostExecResult ¶
HostExecResult is the outcome of HostExecutor.ExecHost.
type HostExecutor ¶
type HostExecutor interface {
// ExecHost runs a host-side command. The executor is responsible
// for the shell / exec dispatch (HostCommand.Shell vs
// HostCommand.Exec — exactly one is set), environment merging,
// and working-directory selection. Cancellation via ctx must
// propagate to the spawned process.
//
// Return a non-nil error only for executor-internal failures
// (process couldn't start, I/O error). A non-zero command exit
// is reported via HostExecResult.ExitCode with a nil error so
// the engine can wrap it consistently with container-side
// execution.
ExecHost(ctx context.Context, cmd HostCommand) (HostExecResult, error)
}
HostExecutor runs commands on the host. Callers supply one via EngineOptions.HostExecutor to enable host-side spec hooks like initializeCommand (and, in a follow-up, secretsCommand). The library does NOT ship a default implementation: host execution is security-sensitive (devcontainer.json can declare arbitrary commands), and the policy decisions — sandboxing, env filtering, timeouts, max output, working directory — belong to the embedding application.
When EngineOptions.HostExecutor is nil and a hook would run, the engine returns a *LifecycleError wrapping ErrHostExecutorNotConfigured. Callers can detect this via errors.Is to surface a useful message ("set EngineOptions.HostExecutor to enable initializeCommand") or to skip silently in environments where host execution isn't permitted.
type LifecycleError ¶
type LifecycleError struct {
Phase config.LifecyclePhase
ExitCode int
Stdout string
Stderr string
Cause error
}
LifecycleError describes a lifecycle phase that ran but exited non-zero. Wrapped errors include exec-level failures (daemon connectivity etc.) and unwrap to those.
func (*LifecycleError) Error ¶
func (e *LifecycleError) Error() string
func (*LifecycleError) Unwrap ¶
func (e *LifecycleError) Unwrap() error
type PullPolicy ¶
type PullPolicy string
PullPolicy controls when images are pulled from a registry.
const ( PullIfNotPresent PullPolicy = "" // default PullAlways PullPolicy = "always" PullNever PullPolicy = "never" )
type ResolveOptions ¶
type ResolveOptions struct {
// LocalWorkspaceFolder is the absolute host path containing the project.
// Required.
LocalWorkspaceFolder string
// ConfigPath is the absolute path to the devcontainer.json file. If
// empty, Resolve looks for:
// <LocalWorkspaceFolder>/.devcontainer/devcontainer.json
// <LocalWorkspaceFolder>/.devcontainer.json
// in that order.
ConfigPath string
// LocalEnv overrides os.Environ() for ${localEnv:*} resolution.
// Nil means use the current process environment.
LocalEnv map[string]string
// DevcontainerIDFunc lets callers customize the workspace id derivation.
// Nil uses config.DevcontainerID(LocalWorkspaceFolder, ConfigPath).
DevcontainerIDFunc func(localWorkspaceFolder, configPath string) string
}
ResolveOptions controls how Resolve loads and resolves a devcontainer.json.
type ResolvedConfig ¶
type ResolvedConfig = config.ResolvedConfig
ResolvedConfig is re-exported from the config package for caller convenience. See config.ResolvedConfig.
func Resolve ¶
func Resolve(ctx context.Context, opts ResolveOptions) (*ResolvedConfig, error)
Resolve loads and resolves a devcontainer.json document.
Image-label metadata merging and feature OCI resolution are stubbed in this milestone (see PRD §13). Build and compose source kinds are parsed and surfaced; actuating them requires the runtime layer landing in M2/M4.
type Substituter ¶
type Substituter struct {
// contains filtered or unexported fields
}
Substituter resolves devcontainer.json substitution placeholders against a fully-populated SubstitutionContext, including the live container's environment. Use it to rewrite Exec / RunLifecycle inputs at call time without mutating the underlying ResolvedConfig.
func (*Substituter) Map ¶
Map applies String to each value and returns a new map. Keys are not substituted.
type UpOptions ¶
type UpOptions struct {
// LocalWorkspaceFolder is the absolute host path to the project. Required.
LocalWorkspaceFolder string
// ConfigPath is the absolute path to devcontainer.json. If empty,
// discovered under LocalWorkspaceFolder per Resolve's rules.
ConfigPath string
// LocalEnv overrides os.Environ() for ${localEnv:*} resolution.
// Nil means use the current process environment.
LocalEnv map[string]string
// Recreate, when true, stops + removes any existing container with our
// label and creates a fresh one. Default false: an existing stopped
// container is restarted (preserving in-container state); an existing
// running container is attached to.
Recreate bool
// PullPolicy controls image pulling. Default IfNotPresent.
PullPolicy PullPolicy
// Events optionally receives structured engine events for the duration
// of this Up call (config resolved, feature resolve, build/pull
// progress, container lifecycle, spec lifecycle phases). Drop-on-full;
// the engine never blocks on send. See package events for the type
// surface (experimental until v1.0.0).
//
// Ownership: the caller owns the channel. The engine only writes —
// it never closes the channel. The caller MUST NOT close it before
// Up returns; closing a channel while the engine is still sending
// races with the engine's send and will panic. Close after Up
// returns (or simply leave the channel open and let it be GC'd).
Events chan<- events.Event
// SkipLifecycle, when true, suppresses automatic invocation of
// devcontainer lifecycle phases (onCreate, postCreate, etc.) from
// Up. Phases can still be run explicitly via Engine.RunLifecycle.
// Default false: Up runs the full configured lifecycle.
SkipLifecycle bool
// RunInitializeCommand, when true, runs the host-side initializeCommand
// before container creation. Default false because the spec lets
// devcontainer.json execute arbitrary host commands; opt-in only.
// Note: v1 initialize execution is a stub that returns an error;
// real host execution requires caller-supplied wiring (PRD §11).
RunInitializeCommand bool
// RunSecretsCommand, when true, runs the host-side secretsCommand
// before container creation and merges its stdout (parsed as
// key=value lines) into the container's environment. Default false
// for the same reason as RunInitializeCommand: arbitrary host
// execution is opt-in. Requires EngineOptions.HostExecutor to be
// set; otherwise a *LifecycleError wrapping
// ErrHostExecutorNotConfigured is returned.
//
// Only applied on fresh container creation. On reattach the
// existing container's env is already baked, so re-running
// secretsCommand would have no effect and we skip it; callers
// wanting a refresh should pass Recreate=true.
RunSecretsCommand bool
// ExtraMounts are appended to the mounts derived from devcontainer.json.
// They layer on top of cfg.WorkspaceMount and cfg.Mounts and are
// preserved across reattach (they only apply on fresh container
// creation, since reattach inherits the original container's mounts).
// For compose sources, only Type == runtime.MountBind entries are
// honored — other mount types are silently dropped to match the
// devcontainer.json `mounts` semantics.
ExtraMounts []runtime.MountSpec
// ExtraContainerEnv is merged into the container's environment, layered
// on top of cfg.ContainerEnv. Entries here are baked into the container
// at start time, so every subsequent exec — including lifecycle scripts
// and feature install — inherits them. Use this for callers that need
// to inject host-derived env (PATH overrides, proxy vars, short-lived
// auth tokens) without mutating devcontainer.json.
ExtraContainerEnv map[string]string
// contains filtered or unexported fields
}
UpOptions configures Engine.Up.
type Workspace ¶
type Workspace struct {
ID WorkspaceID
// Config is the resolved devcontainer.json. Full after Up; minimal
// after Attach — see the type-level docs for the field breakdown.
Config *config.ResolvedConfig
Container *runtime.ContainerDetails
// contains filtered or unexported fields
}
Workspace is a live devcontainer: a resolved config plus a running container plus a substituter bound to the container's effective env.
Workspace is safe for concurrent reads (Exec/Inspect/Logs) but not for concurrent mutation. Engine.Attach returns a fresh Workspace; callers should not share Workspace values across re-attaches.
Config asymmetry between Up and Attach:
Workspaces returned by Engine.Up have a fully-populated Config: every field from devcontainer.json (lifecycle commands, mounts, customizations, features, etc.) is present, image-metadata merged, and warnings accumulated on Config.Warnings.
Workspaces returned by Engine.Attach have a MINIMAL Config reconstructed from container labels and image inspect: LocalWorkspaceFolder, ContainerWorkspaceFolder, ContainerUser, RemoteUser (from image-metadata merge), and the source kind. Lifecycle hooks, Mounts, Customizations, Features, and most other devcontainer.json fields are NOT repopulated — Attach does not re-read devcontainer.json from disk.
This is enough to drive Exec (the substituter is bound to the live container env) and Down, but callers that need the full devcontainer.json view should call Resolve themselves, or use Engine.Up which always returns the full Config.
type WorkspaceID ¶
type WorkspaceID string
WorkspaceID is a stable identifier for a workspace, derived from (LocalWorkspaceFolder, ConfigPath). See config.DevcontainerID.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package compose handles the Docker Compose source kind for devcontainer.json: parsing the user's compose project via compose-spec/compose-go and synthesizing override files that the engine layers on top during `docker compose up`.
|
Package compose handles the Docker Compose source kind for devcontainer.json: parsing the user's compose project via compose-spec/compose-go and synthesizing override files that the engine layers on top during `docker compose up`. |
|
Package config defines the parsed and resolved devcontainer.json configuration types.
|
Package config defines the parsed and resolved devcontainer.json configuration types. |
|
Package events defines the structured event surface emitted by Engine operations (Up / Down / Exec / RunLifecycle) and feature/build/runtime activity reached through them.
|
Package events defines the structured event surface emitted by Engine operations (Up / Down / Exec / RunLifecycle) and feature/build/runtime activity reached through them. |
|
examples
|
|
|
compose
command
compose drives a 2-service devcontainer described by a Docker Compose project: a primary `app` service and a sidecar `db`.
|
compose drives a 2-service devcontainer described by a Docker Compose project: a primary `app` service and a sidecar `db`. |
|
image-source
command
image-source is the smallest end-to-end example: pull an image, run it, exec a command, tear it down.
|
image-source is the smallest end-to-end example: pull an image, run it, exec a command, tear it down. |
|
with-features
command
with-features adds a local devcontainer feature on top of an image- source devcontainer, proves the feature's install.sh ran inside the container, and confirms the feature's containerEnv was applied.
|
with-features adds a local devcontainer feature on top of an image- source devcontainer, proves the feature's install.sh ran inside the container, and confirms the feature's containerEnv was applied. |
|
Package feature implements the devcontainer feature pipeline: reference resolution (OCI / HTTPS / Local), option processing, dependency-graph ordering, and dockerfile generation.
|
Package feature implements the devcontainer feature pipeline: reference resolution (OCI / HTTPS / Local), option processing, dependency-graph ordering, and dockerfile generation. |
|
Package runtime defines the container backend abstraction used by the devcontainer engine.
|
Package runtime defines the container backend abstraction used by the devcontainer engine. |
|
applecontainer
Package applecontainer is an Apple `container` implementation of runtime.Runtime targeting macOS 15+ on arm64.
|
Package applecontainer is an Apple `container` implementation of runtime.Runtime targeting macOS 15+ on arm64. |
|
docker
Package docker is a Docker Engine API implementation of runtime.Runtime.
|
Package docker is a Docker Engine API implementation of runtime.Runtime. |