Skip to main content

Runtime

Trait Runtime 

Source
pub trait Runtime: Send + Sync {
Show 24 methods // Required methods fn pull_image<'life0, 'life1, 'async_trait>( &'life0 self, image: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn pull_image_with_policy<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, image: &'life1 str, policy: PullPolicy, auth: Option<&'life2 RegistryAuth>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn create_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, spec: &'life2 ServiceSpec, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn start_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn stop_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, timeout: Duration, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn remove_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn container_state<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerState>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn container_logs<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, tail: usize, ) -> Pin<Box<dyn Future<Output = Result<Vec<LogEntry>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn exec<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, cmd: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Result<(i32, String, String)>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn get_container_stats<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerStats>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn wait_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<i32>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn get_logs<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Vec<LogEntry>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn get_container_pid<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<u32>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn get_container_ip<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<IpAddr>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; // Provided methods fn exec_stream<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, cmd: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Result<ExecEventStream>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn wait_outcome<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<WaitOutcome>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn get_container_port_override<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<u16>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn sync_container_volumes<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn list_images<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<ImageInfo>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn remove_image<'life0, 'life1, 'async_trait>( &'life0 self, _image: &'life1 str, _force: bool, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn prune_images<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<PruneResult>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn kill_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _signal: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn tag_image<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _source: &'life1 str, _target: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn inspect_detailed<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerInspectDetails>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... }
}
Expand description

Abstract container runtime trait

This trait abstracts over different container runtimes (containerd, CRI-O, etc.)

Required Methods§

Source

fn pull_image<'life0, 'life1, 'async_trait>( &'life0 self, image: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Pull an image to local storage

Source

fn pull_image_with_policy<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, image: &'life1 str, policy: PullPolicy, auth: Option<&'life2 RegistryAuth>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Pull an image to local storage with a specific policy.

When auth is Some, the runtime uses those inline credentials for the pull (§3.10 of ZLAYER_SDK_FIXES.md). When auth is None, the runtime falls back to its existing credential-store lookup keyed by registry hostname (or anonymous access when no match exists).

Non-Docker runtimes may accept but ignore the auth argument — their OCI puller (zlayer-registry) already resolves credentials from the store by hostname, and inline auth is primarily a Docker-backend concern. Ignoring it is safe: callers that need inline auth should use the Docker runtime.

Source

fn create_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, spec: &'life2 ServiceSpec, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Create a container

Source

fn start_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Start a container

Source

fn stop_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, timeout: Duration, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Stop a container

Source

fn remove_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Remove a container

Source

fn container_state<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerState>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get container state

Source

fn container_logs<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, tail: usize, ) -> Pin<Box<dyn Future<Output = Result<Vec<LogEntry>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get container logs as structured entries

Source

fn exec<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, cmd: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Result<(i32, String, String)>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute command in container

Source

fn get_container_stats<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerStats>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get container resource statistics from cgroups

Returns CPU and memory statistics for the specified container. Used for metrics collection and autoscaling decisions.

Source

fn wait_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<i32>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Wait for a container to exit and return its exit code

This method blocks until the container exits or an error occurs. Used primarily for job execution to implement run-to-completion semantics.

Source

fn get_logs<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Vec<LogEntry>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get container logs (stdout/stderr combined)

Returns logs as structured entries. Used to capture job output after completion.

Source

fn get_container_pid<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<u32>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get the PID of a container’s main process

Returns:

  • Ok(Some(pid)) for runtimes with real processes (Youki, Docker)
  • Ok(None) for runtimes without separate PIDs (WASM in-process)
  • Err if the container doesn’t exist or there’s an error

Used for overlay network attachment and process management.

Source

fn get_container_ip<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<IpAddr>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get the IP address of a container

Returns:

  • Ok(Some(ip)) if the container has a known IP address
  • Ok(None) if the container exists but has no IP assigned yet
  • Err if the container doesn’t exist or there’s an error

Used for proxy backend registration when overlay networking is unavailable.

Provided Methods§

Source

fn exec_stream<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, cmd: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Result<ExecEventStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute a command in a container and stream stdout / stderr / exit events as they are produced.

The default implementation calls the buffered Runtime::exec and emits everything as a single Stdout event, a single Stderr event, and a final Exit event. Runtimes that support true streaming (e.g. Docker via bollard) override this to produce line-by-line events as the command runs.

The returned stream always terminates with exactly one ExecEvent::Exit as the final item on success. Errors that occur before the stream is returned (e.g. container not found, failure to create the exec) are surfaced via the outer Result; errors that occur mid-stream are logged by the runtime and the stream closes.

Source

fn wait_outcome<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<WaitOutcome>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Wait for a container to exit and return a WaitOutcome with richer classification (exit code + reason + signal + finished_at timestamp).

The default implementation delegates to Runtime::wait_container and synthesizes a WaitReason::Exited result with no signal/timestamp. Runtimes that can distinguish OOM kills, signal deaths, or report a finished-at time (e.g. the Docker runtime, which has ContainerInspectResponse.state.oom_killed / .finished_at) should override this.

Source

fn get_container_port_override<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<u16>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get a runtime-assigned port override for a container.

Returns:

  • Ok(Some(port)) if the runtime assigned a dynamic port to this container
  • Ok(None) if the container should use the spec-declared endpoint port

This exists for runtimes where all containers share the host network stack (e.g., macOS sandbox). Without network namespaces, multiple replicas of the same service would conflict on the same port. The runtime assigns each replica a unique port and passes it via the PORT environment variable. The proxy then routes to container_ip:override_port instead of container_ip:spec_port.

Runtimes with per-container networking (overlay, VMs, Docker) return None.

Source

fn sync_container_volumes<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Sync all named volumes associated with this container to S3.

Called after a container is stopped but before it is removed, giving the runtime a chance to flush persistent volume data to remote storage.

The default implementation is a no-op. Runtimes that support S3-backed volume sync (e.g., Youki with the s3 feature) override this.

Source

fn list_images<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<ImageInfo>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

List all images managed by this runtime’s image storage.

The default implementation returns AgentError::Unsupported — individual runtimes override this with backend-specific logic (bollard for Docker, zlayer-registry cache walk for Youki, etc.).

Source

fn remove_image<'life0, 'life1, 'async_trait>( &'life0 self, _image: &'life1 str, _force: bool, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Remove an image by reference from local storage.

When force is true, also removes the image even when other containers reference it. The default implementation returns AgentError::Unsupported.

Source

fn prune_images<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<PruneResult>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Prune dangling / unused images from local storage.

Returns a PruneResult describing what was removed. The default implementation returns AgentError::Unsupported.

Source

fn kill_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _signal: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Send a signal to a running container.

When signal is None, the runtime sends SIGKILL (matching Docker’s docker kill default). Backends validate the signal name and reject anything outside the standard POSIX set (SIGKILL, SIGTERM, SIGINT, SIGHUP, SIGUSR1, SIGUSR2).

Used by POST /api/v1/containers/{id}/kill and Docker-compat docker kill. The default implementation returns AgentError::Unsupported.

Source

fn tag_image<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _source: &'life1 str, _target: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Create a new tag pointing at an existing image.

source is the reference to an already-cached image. target is the new reference to create — it must be a full reference (repository + tag).

Used by POST /api/v1/images/tag and Docker-compat docker tag. The default implementation returns AgentError::Unsupported.

Source

fn inspect_detailed<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerInspectDetails>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Return rich inspect details for a container: published ports, attached networks, first IPv4, health, and most-recent exit code.

Runtimes implement this by translating the backend’s native inspect response (bollard’s ContainerInspectResponse for Docker) into the runtime-level ContainerInspectDetails struct. The API layer merges these fields into ContainerInfo on GET /api/v1/containers and GET /api/v1/containers/{id} (§3.15 of ZLAYER_SDK_FIXES.md).

The default implementation returns ContainerInspectDetails::default — an all-empty record, which the API layer treats as “this runtime doesn’t support rich inspect; skip all the extra fields”. This keeps non-Docker runtimes (Youki, WASM, Mock) backwards compatible; they can override this later if they gain equivalent inspect capability.

Implementors§