Feature request
Add support for talking to the Docker daemon that ships inside WSL Containers (wslc) on Windows (Microsoft WSL 2.9+): a wslc:// transport, plus the small amount of lifecycle glue needed for published ports, host bind mounts and user-defined networks to actually work.
Motivation
WSL Containers runs dockerd inside a dedicated lightweight VM. Unlike Docker Desktop or Podman it exposes no Windows named pipe and no TCP port on the host — the only host-visible channel to the daemon is a stdio bridge:
wslc.exe system session run docker system dial-stdio
This is the same shape as the existing ssh:// transport (a child process whose stdin/stdout are the daemon socket). Today docker-java (and Testcontainers on top of it) has no way to reach a wslc-only daemon.
Proposed change
1. Transport (docker-java-transport + -transport-httpclient5) — mirror unix/npipe, dependency-free:
- new WslcSocket extends Socket, streams backed by the wslc … dial-stdio child process (this module is JNA-only / no SLF4J, so it uses java.util.logging — no new dependency);
- add case "wslc": to the scheme switch in ApacheDockerHttpClientImpl and a new WslcSocket(dockerHostPath) branch. Hijacked exec/attach/log streams work for free (they run at the HttpClient5 socket level).
2. Lifecycle integration (docker-java-core) — wslc's Windows integration (the 127.0.0.1 port relay and Windows-path bind mounts) is wired by the wslc control plane only when a container is created/started through the native wslc CLI, not through the Docker API on the same daemon (see microsoft/WSL #40957). A container created via the Docker API reaches the same dockerd but its published ports aren't reachable from Windows and host binds are rejected.
To bridge that, a WslcLifecycleDockerHttpClient (a DockerHttpClient decorator, jackson-only, no new dependency) reconciles just the affected calls with the wslc CLI and delegates everything else unchanged:
- POST /containers/create → wslc create
- POST /containers/{id}/start → wslc start (this is what wires relay + bind)
- POST /networks/create → wslc network create (wslc --network only sees wslc-created networks; the id→name is resolved via a Docker-API inspect)
- GET /containers/{id}/json → the daemon's inspect with NetworkSettings.Ports overridden from wslc list (for a randomly published port the daemon records the create-time port but the start relay binds a different one)
Activation is transparent: DockerClientImpl.getInstance(config, httpClient) wraps the client in this decorator only when the host scheme is wslc. So it never affects unix/npipe/tcp users, and every docker-java consumer picks it up with no extra wiring.
3. Auto-detection (docker-java-core / DefaultDockerClientConfig)
— when DOCKER_HOST is unset, fall back to wslc://localhost on Windows only if the //./pipe/docker_engine pipe is absent AND wslc is available (wslc version exit 0, overridable via WSLC_EXECUTABLE) — so existing Docker Desktop / Podman setups keep winning.
Using it with Testcontainers
Testcontainers shades docker-java-core but consumes docker-java-api / -transport-zerodep as normal dependencies. So with just this PR:
- set DOCKER_HOST=wslc://localhost explicitly, and
- rebuild Testcontainers against the updated (shaded) docker-java so the new getInstance activation is re-shaded into its jar (a plain version bump is not enough — core is shaded).
That combination is verified working end-to-end: a real Testcontainers/Cucumber integration-test suite goes fully green over wslc (containers create/start via the CLI, ports reachable from Windows, custom networks resolved).
The one piece that can't live in docker-java is automatic host selection when DOCKER_HOST is unset — that requires a class implementing Testcontainers' DockerClientProviderStrategy, which docker-java can't provide without depending on Testcontainers. I'll open a separate PR against testcontainers-java to add that automatic fallback to wslc:// when it's the only Docker environment present on Windows, so users won't need to set DOCKER_HOST at all.
Feature request
Add support for talking to the Docker daemon that ships inside WSL Containers (wslc) on Windows (Microsoft WSL 2.9+): a wslc:// transport, plus the small amount of lifecycle glue needed for published ports, host bind mounts and user-defined networks to actually work.
Motivation
WSL Containers runs dockerd inside a dedicated lightweight VM. Unlike Docker Desktop or Podman it exposes no Windows named pipe and no TCP port on the host — the only host-visible channel to the daemon is a stdio bridge:
wslc.exe system session run docker system dial-stdio
This is the same shape as the existing ssh:// transport (a child process whose stdin/stdout are the daemon socket). Today docker-java (and Testcontainers on top of it) has no way to reach a wslc-only daemon.
Proposed change
1. Transport (docker-java-transport + -transport-httpclient5) — mirror unix/npipe, dependency-free:
2. Lifecycle integration (docker-java-core) — wslc's Windows integration (the 127.0.0.1 port relay and Windows-path bind mounts) is wired by the wslc control plane only when a container is created/started through the native wslc CLI, not through the Docker API on the same daemon (see microsoft/WSL #40957). A container created via the Docker API reaches the same dockerd but its published ports aren't reachable from Windows and host binds are rejected.
To bridge that, a WslcLifecycleDockerHttpClient (a DockerHttpClient decorator, jackson-only, no new dependency) reconciles just the affected calls with the wslc CLI and delegates everything else unchanged:
Activation is transparent: DockerClientImpl.getInstance(config, httpClient) wraps the client in this decorator only when the host scheme is wslc. So it never affects unix/npipe/tcp users, and every docker-java consumer picks it up with no extra wiring.
3. Auto-detection (docker-java-core / DefaultDockerClientConfig)
— when DOCKER_HOST is unset, fall back to wslc://localhost on Windows only if the //./pipe/docker_engine pipe is absent AND wslc is available (wslc version exit 0, overridable via WSLC_EXECUTABLE) — so existing Docker Desktop / Podman setups keep winning.
Using it with Testcontainers
Testcontainers shades docker-java-core but consumes docker-java-api / -transport-zerodep as normal dependencies. So with just this PR:
That combination is verified working end-to-end: a real Testcontainers/Cucumber integration-test suite goes fully green over wslc (containers create/start via the CLI, ports reachable from Windows, custom networks resolved).
The one piece that can't live in docker-java is automatic host selection when DOCKER_HOST is unset — that requires a class implementing Testcontainers' DockerClientProviderStrategy, which docker-java can't provide without depending on Testcontainers. I'll open a separate PR against testcontainers-java to add that automatic fallback to wslc:// when it's the only Docker environment present on Windows, so users won't need to set DOCKER_HOST at all.