Skip to content

Add a pool option that sets runner environment variables - #20

Merged
clroot merged 2 commits into
mainfrom
pool-env
Nov 9, 2026
Merged

clroot merged 2 commits into
mainfrom
pool-env

Conversation

@clroot

@clroot clroot commented Nov 9, 2026

Copy link
Copy Markdown
Owner

Problem

On Docker Desktop 4.95.0 with host networking (WSL2 backend), JVM builds fail in --docker-socket runners:

  • Gradle: Could not connect to the Gradle daemon, even with --no-daemon. The daemon listens on 127.0.0.1, but the client's connection is refused.
  • Kotlin compiler: Failed connecting to the daemon in 4 retries
  • Testcontainers: Could not connect to Ryuk at 172.17.0.1:<port>

Java opens IPv6 sockets and connects to the IPv4-mapped loopback address, which Docker Desktop's host network does not route. Other programs (for example a Perl IPv4 socket) reach the same loopback port. Testcontainers inside a container connects to the default gateway, where Docker Desktop does not expose the published ports.

Change

Pools take an env table (or pool add --env KEY=VALUE, repeatable) that runnerctl passes to their runner containers with --env. Jobs on the runner inherit the variables.

[pools.env]
JAVA_TOOL_OPTIONS = "-Djava.net.preferIPv4Stack=true"
TESTCONTAINERS_HOST_OVERRIDE = "127.0.0.1"
  • Names must be letters, digits and underscores, not starting with a digit. Values must be single lines.
  • The eight names runnerctl sets (GITHUB_ORG, GITHUB_URL, RUNNER_*) are rejected.
  • Changing the table starts a new runner generation.
  • An empty table is not serialized, so existing configs and state stay unchanged.
  • The docker.rs tests now run on every platform. Only the Windows path mapping test stays Windows-only.
  • docs/operations.md describes the option. docs/platforms.md records the Docker Desktop JVM setup.

The option is explicit rather than detected. Setting JAVA_TOOL_OPTIONS automatically would make every JVM print Picked up JAVA_TOOL_OPTIONS on other runtimes too.

Verification

  • cargo fmt --check, cargo clippy --all-targets --locked -- -D warnings, cargo test --locked: pass. Adds 5 tests (config parsing and validation, CLI parsing, container args, runner generation).
  • Docker lifecycle checks on Docker Desktop 4.95.0 (WSL2): tests/entrypoint.sh, tests/docker-socket.sh, cargo test --locked docker_ -- --ignored pass.
  • In a --network host container on the same Docker Desktop:
Setting Result
none Gradle client cannot connect to its daemon
GRADLE_OPTS=-Djava.net.preferIPv4Stack=true Gradle starts; Kotlin compiler daemon fails
JAVA_TOOL_OPTIONS=-Djava.net.preferIPv4Stack=true compile and unit tests pass; Testcontainers fails to reach Ryuk
plus TESTCONTAINERS_HOST_OVERRIDE=127.0.0.1 Testcontainers integration test passes

🤖 Generated with Claude Code

On Docker Desktop 4.95.0 with host networking (WSL2 backend), a JVM in a
host-network runner cannot connect to 127.0.0.1 in the same runner: Java
connects through the IPv4-mapped address, which is not routed there.
Gradle fails with "Could not connect to the Gradle daemon" even with
--no-daemon, the Kotlin compiler cannot reach its daemon, and
Testcontainers cannot reach the containers it starts through the default
gateway.

Pools now take an env table (or pool add --env KEY=VALUE) that is passed
to their runner containers, so such a pool can set
JAVA_TOOL_OPTIONS=-Djava.net.preferIPv4Stack=true and
TESTCONTAINERS_HOST_OVERRIDE=127.0.0.1. Names runnerctl sets for
registration and the workspace are rejected, values must be single
lines, and changing the table starts a new runner generation. An empty
table is not written, so existing configs are unchanged.

The docker.rs tests now run on every platform; only the Windows path
mapping test stays Windows-only.

Verification: cargo fmt --check, cargo clippy --all-targets --locked -- -D warnings,
cargo test --locked, the Docker lifecycle checks (tests/entrypoint.sh,
tests/docker-socket.sh, cargo test --locked docker_ -- --ignored), and a
Gradle/Kotlin/Testcontainers build in a host-network container on
Docker Desktop with and without the two variables.
@clroot
clroot merged commit 21484aa into main Nov 9, 2026
6 checks passed
@clroot
clroot deleted the pool-env branch November 9, 2026 06:54
clroot added a commit that referenced this pull request Nov 9, 2026
Docker socket pools always used the host network. On Docker Desktop 4.95.0
(WSL2 backend) a JVM there cannot connect to 127.0.0.1 in the same
runner, and JAVA_TOOL_OPTIONS=-Djava.net.preferIPv4Stack=true (#20) only
helps part of a build: Gradle starts worker daemons, which ktlint uses,
without the build's environment, so they still fail to reach the daemon.

network = "host" | "bridge" (or pool add --network) now picks the
network for a pool's runner containers. Unset keeps the previous
behavior: host for Docker socket pools, Docker's default bridge
otherwise. Only a change of the effective network starts a new runner
generation, so writing out the default does not replace runners.

docs/platforms.md now recommends a bridge pool with
TESTCONTAINERS_HOST_OVERRIDE=host.docker.internal for JVM builds on
Docker Desktop, replacing the JAVA_TOOL_OPTIONS advice.
tests/docker-socket.sh takes RUNNER_NETWORK to check a bridge pool.

Verification: cargo fmt --check, cargo clippy --all-targets --locked -- -D warnings,
cargo test --locked, tests/entrypoint.sh, tests/docker-socket.sh with host
and bridge, cargo test --locked docker_ -- --ignored. On the same Docker
Desktop, a Gradle build with ktlint workers, Kotlin compilation and a
Testcontainers MariaDB test passed in a bridge container with the socket
mounted and the override set.
@clroot clroot mentioned this pull request Nov 9, 2026
clroot added a commit that referenced this pull request Nov 9, 2026
Adds two pool options: env (#20) passes environment variables to a
pool's runner containers and their jobs, and network (#22) runs a
Docker socket pool on Docker's bridge network instead of the host
network. Together they let JVM builds with Testcontainers run on Docker
Desktop, where a host-network runner cannot reach 127.0.0.1 from Java.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant