Container runtimes
editThe library does not run containers itself: it drives a container runtime installed on the machine.
| Runtime | ContainerRuntime | Talks to |
|---|---|---|
| Docker Engine API | ContainerRuntime.DockerApi | The Docker daemon, over its socket or named pipe, without the docker CLI |
| Docker | ContainerRuntime.Docker | The docker CLI |
| Podman | ContainerRuntime.Podman | The podman CLI |
| Apple container | ContainerRuntime.AppleContainer | Apple's container CLI (macOS) |
| WSL containers | ContainerRuntime.Wslc | The wslc CLI (Windows) |
Automatic detection
A definition uses ContainerRuntime.Auto unless you set another runtime. It uses the first runtime of this list that is available:
wslc, on Windows.- Apple's
container, on macOS. - The Docker Engine API.
- The
dockerCLI. - The
podmanCLI.
A runtime is available when its command line is found on the PATH (the Docker Engine API needs none) and its daemon answers. A daemon that is installed but stopped does not count: start Docker Desktop, the Podman machine, or Apple's container service (container system start) before the tests. The first runtime that answers is kept for the rest of the process; when none answers, the next attempt probes them again, so a daemon started later is still found.
When no runtime is available, StartAsync throws an InvalidOperationException that lists the runtimes it looked for.
On a machine that has several runtimes, the order matters: a Mac with both Apple's container and Docker Desktop uses Apple's container as long as its service runs, and a Windows machine with wslc uses it. Choose the runtime explicitly to use another one.
Choose a runtime
Set Runtime on the definition:
var definition = ContainerDefinition.CreateRedis();
definition.Runtime = ContainerRuntime.Podman; // ContainerRuntime.Auto by defaultTo let each developer and build agent choose, read the runtime from the environment and check that it answers before the tests:
var runtime = Environment.GetEnvironmentVariable("TEST_CONTAINER_RUNTIME") switch
{
"docker" => ContainerRuntime.Docker,
"podman" => ContainerRuntime.Podman,
_ => ContainerRuntime.Auto,
};
// Probes the runtime: runs a command or connects to the daemon
if (!await runtime.IsSupportedAsync())
throw new InvalidOperationException($"The container runtime '{runtime}' is not available.");IsSupportedAsync runs a command or opens a connection to the daemon. It caches a success, not a failure. VolumeDefinition.Runtime chooses the runtime of a volume the same way.
Connect to a Docker daemon
The docker and podman runtimes connect wherever their command line is configured to (contexts, DOCKER_HOST). The Docker Engine API runtime finds the daemon the way the docker CLI does, and uses the first source that is set:
DOCKER_HOST:unix://,npipe://,tcp://,http://orhttps://.The docker context named by
DOCKER_CONTEXT.The current context of
config.json(currentContext, set bydocker context use). The configuration directory isDOCKER_CONFIG,~/.dockerby default. A context reached over TCP uses the TLS certificates stored with it, and honorsskip-tls-verify.Otherwise, or with the
defaultcontext, the sockets of the usual distributions, in this order, and thedocker_enginenamed pipe on Windows:Socket Daemon /var/run/docker.sockDocker Engine, Docker Desktop ~/.docker/run/docker.sock,~/.docker/desktop/docker.sock(Linux)Docker Desktop without the default socket ~/.colima/default/docker.sock,~/.colima/docker.sockColima ~/.orbstack/run/docker.sockOrbStack ~/.rd/docker.sockRancher Desktop $XDG_RUNTIME_DIR/docker.sock(/run/user/$UIDon Linux)Rootless Docker $XDG_RUNTIME_DIR/podman/podman.sockPodman
A DOCKER_HOST or a context that cannot be used (a missing context, an ssh:// address) is not replaced by another daemon: the runtime is unavailable, as the docker CLI would fail.
For DOCKER_HOST with tcp:// or https://, TLS follows the environment variables of the docker CLI:
DOCKER_TLS_VERIFYturns on TLS and verifies the daemon certificate against the authorities ofca.pem. The file can hold several certificates, such as an intermediate authority and its root.DOCKER_TLSalone turns on TLS without verifying the daemon certificate.- The
ca.pem,cert.pemandkey.pemfiles are read fromDOCKER_CERT_PATH, the configuration directory by default.cert.pemandkey.pemare the client certificate, when the daemon requires one.
When no daemon answers, the "not available" exception lists each endpoint the runtime tried and why it failed. The Logger of a container logs, at the Debug level, the endpoint the Docker Engine API uses, or why the Auto runtime did not use it.
A daemon on another machine publishes the ports of the containers on that machine: see Connect to a remote daemon for the address to connect to.
Runtime differences
| Docker Engine API, Docker | Podman | Apple container | wslc | |
|---|---|---|---|---|
| Volumes (TemporaryVolume) | Yes | Yes | Yes, no driver | No |
| Networks (TemporaryNetwork), several networks per container | Yes | Yes | Yes, no driver | No |
| Pause, restart | Yes | Yes | No (a restart is a stop and a start) | Pause only (a restart is a stop and a start) |
| Hostname | Yes | Yes | No | Yes |
| Privileged mode, extra hosts, healthcheck, stop signal and timeout, exposed ports, tmpfs options (Advanced options) | Yes | Yes | No | Not verified |
| HostIp of a port | Yes, except Windows containers | Yes | Yes, IPv4 only | No, loopback forwarding of WSL |
| PullPolicy.Never | Yes | Yes | Yes | No |
| Platform of a container | Yes | Yes | Yes | No |
| Built images removed and cleaned up | Yes | Yes | Yes | No, they are not labeled |
| Anonymous volumes removed with the container | Yes | Yes | Yes | No |
| Reaper | Yes | Yes | No | No |
| Log timestamps, ContainerLogsOptions.Since and Until | Yes | Yes | No | Yes, clock of the WSL virtual machine |
The Docker Engine API cannot send ExecOptions.StandardInput to a daemon reached over a named pipe, the default on Windows: use the docker runtime there.
Every runtime reports a failed operation with a ContainerRuntimeException. See Troubleshooting.