Honour the active Docker CLI context for the default client#11826
Open
ebriney wants to merge 6 commits into
Open
Honour the active Docker CLI context for the default client#11826ebriney wants to merge 6 commits into
ebriney wants to merge 6 commits into
Conversation
Mirrors the docker(1) resolution chain (DOCKER_HOST > DOCKER_CONTEXT > currentContext in ~/.docker/config.json) and parses the matching meta.json under ~/.docker/contexts/meta/<sha256(name)>/, exposing the endpoint host URI and any TLS material to callers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds DockerContextClientProviderStrategy (registered via the SPI between the env-var and unix-socket strategies) so a default-configured Testcontainers picks the same daemon as `docker info`. This matters for setups where Docker is only reachable through the configured context (e.g. Docker Desktop on macOS without a /var/run/docker.sock symlink, OrbStack, or any DOCKER_CONTEXT override). A public DockerContextClientProviderStrategy(String contextName) constructor mirrors EnvironmentAndSystemPropertyClientProviderStrategy's package-private hook so callers can pin a specific context by name. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The two unix-socket fixtures embedded an absolute temp-file path into a JSON meta document. On Windows that path contains backslashes, which are invalid JSON escapes and broke Jackson parsing before the production code ran. Use an OS-appropriate endpoint instead: a real unix socket on POSIX (so the socket-existence check is still exercised) and an npipe address on Windows (no backing file needed). Both forms use forward slashes and embed safely into the JSON fixtures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
connectsToLocalDockerThroughActiveContext only guarded the ping/info calls; when Docker Desktop is stopped, getTransportConfig already throws InvalidConfigurationException for the missing socket, which surfaced as a hard failure instead of a skip. Move the transport-resolve and client construction inside the existing try/catch so any failure on the path to the daemon translates to a JUnit assumption skip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mention the new context-aware lookup in the Docker environment discovery list and call out DOCKER_CONTEXT / DOCKER_CONFIG in the host-detection env-var reference. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Result of running ./gradlew :testcontainers:spotlessApply over the new Docker context sources; no behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Testcontainers picks a Docker daemon by walking a chain of provider strategies, but until now the chain did not look at the user's active Docker CLI context. On a machine where Docker Desktop ships the daemon at
~/.docker/run/docker.sockandcurrentContextin~/.docker/config.jsonpoints atdesktop-linux, the existing strategies still happen to work becauseDockerDesktopClientProviderStrategyhard-codes that path. But anyone who switches context — to OrbStack, a remotetcp://host, an SSH endpoint, etc. — ends up driving a different daemon from the rest of their toolchain.This PR adds a new SPI-registered strategy that mirrors
docker(1)'s own resolution:DOCKER_HOSTenv var (handled by the existing env-var strategy).DOCKER_CONTEXTenv var.currentContextin$DOCKER_CONFIG/config.json(default~/.docker/config.json).defaultcontext (no metadata file — strategy steps aside and lets the local-socket strategies handle it).For named contexts, the endpoint host is read from
$DOCKER_CONFIG/contexts/meta/<sha256(name)>/meta.json, and per-context TLS material undercontexts/tls/<sha256(name)>/docker/is wired into aLocalDirectorySSLConfigwhen present.What's in the change
DockerContextResolver— pure utility that does the path math and JSON parsing. Public API is just two static methods plus aDockerContextEndpointvalue object. Env-var lookup is parameterised so it can be tested without touching the process environment.DockerContextClientProviderStrategy— the SPI hook. Priority isEnvironmentAndSystemPropertyClientProviderStrategy.PRIORITY - 10, i.e. between the env-var strategy (100) and the unix-socket strategy (80), soDOCKER_HOSTstill wins as it does in the CLI.isApplicable()returns false for the built-indefaultcontext and for unsupported schemes (e.g.ssh://), letting the chain fall through cleanly.DockerContextClientProviderStrategy(String contextName), lets callers pin a specific context by name, bypassing the auto-resolution.META-INF/services/...DockerClientProviderStrategybetween the env-var and unix-socket strategies.Tests
DockerContextResolverTest— 11 unit tests over a temp config dir covering the resolution chain (env precedence, blank values, missing config), endpoint parsing, TLS discovery, malformed inputs, and a sanity check that the SHA-256 directory name matches what Docker Desktop actually writes fordesktop-linux.DockerContextClientProviderStrategyTest— 9 tests coveringisApplicable()for default/ssh/named contexts, the explicit-name constructor, missing-socket diagnostics, TLS wiring, priority bounds, plus two live tests that exercise an actual Docker daemon end-to-end (one via the strategy, one throughDockerClientFactory.isUsing(...)). Live tests useassumeThatto skip cleanly when no daemon is reachable.unix://paths on POSIX andnpipe://on Windows so JSON parsing stays portable.Docs
Updates
docs/supported_docker_environment/index.md(discovery chain) anddocs/features/configuration.md(DOCKER_CONTEXTandDOCKER_CONFIGenv vars).Test plan
./gradlew :testcontainers:test --tests "org.testcontainers.dockerclient.DockerContext*"passes on macOS with Docker Desktop running (live tests execute)../gradlew :testcontainers:checkstyleMain :testcontainers:checkstyleTest :testcontainers:spotlessApplyis clean.