Skip to content

Commit 801e4f0

Browse files
tjametThibault Jamet
authored and
Thibault Jamet
committed
Improve support for alternative container runtimes
In several cases, alternative container runtimes offers a docker compatible API and populates the docker context accordingly. However, in the current implementation of testcontainers, the context is often ignored as the `EnvironmentAndSystemPropertyClientProviderStrategy` only considers the `DOCKER_HOST` override either through testcontainers property or the environment variables. Improve the support of multiple container runtimes by honoring the current docker context. In addition, improve the detection of whether the Docker engine runs in a virtual machine without root access for the current user, so it removes the need to configure `TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE` in standard cases. This change has been tested with: - colima - rancher desktop (in non-privileged mode) - docker desktop - orbstack
1 parent 751aa4e commit 801e4f0

File tree

3 files changed

+62
-56
lines changed

3 files changed

+62
-56
lines changed

core/src/main/java/org/testcontainers/DockerClientFactory.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@
3030
import org.testcontainers.utility.ResourceReaper;
3131
import org.testcontainers.utility.TestcontainersConfiguration;
3232

33+
import java.io.IOException;
3334
import java.io.InputStream;
3435
import java.net.URI;
36+
import java.nio.file.Files;
37+
import java.nio.file.Paths;
3538
import java.util.ArrayList;
3639
import java.util.Arrays;
3740
import java.util.Collections;
@@ -174,10 +177,25 @@ public String getRemoteDockerUnixSocketPath() {
174177
}
175178

176179
URI dockerHost = getTransportConfig().getDockerHost();
177-
String path = "unix".equals(dockerHost.getScheme()) ? dockerHost.getRawPath() : "/var/run/docker.sock";
180+
181+
String path = this.isRemoteDockerDaemon(dockerHost) ? "/var/run/docker.sock" : dockerHost.getRawPath();
178182
return SystemUtils.IS_OS_WINDOWS ? "/" + path : path;
179183
}
180184

185+
private Boolean isRemoteDockerDaemon(URI dockerHost) {
186+
if (!"unix".equals(dockerHost.getScheme())) {
187+
return true;
188+
}
189+
// Several privileged less Docker providers exposes the Docker socket within the user's home directory, owned by the users.
190+
// This is the case for Rancher Desktop for example.
191+
// In this case, it is likely that the Docker daemon running in the virtual machine listens on /var/run/docker.sock
192+
try {
193+
return Files.getOwner(Paths.get(dockerHost.getRawPath())).getName().equals(System.getProperty("user.name"));
194+
} catch (IOException e) {
195+
return false;
196+
}
197+
}
198+
181199
/**
182200
* @return a new initialized Docker client
183201
*/

core/src/main/java/org/testcontainers/dockerclient/EnvironmentAndSystemPropertyClientProviderStrategy.java

+22-3
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,26 @@
99

1010
/**
1111
* Use environment variables and system properties (as supported by the underlying DockerClient DefaultConfigBuilder)
12-
* to try and locate a docker environment.
12+
* to try and locate a docker environment based on the currently active configuration.
1313
* <p>
14-
* Resolution order is:
14+
* Docker Host resolution order is:
1515
* <ol>
1616
* <li>DOCKER_HOST env var</li>
1717
* <li>docker.host in ~/.testcontainers.properties</li>
18+
* <li>docker host pointed by the Docker context</li>
19+
* </ol>
20+
* <p>
21+
* Docker context resolution order is
22+
* <ol>
23+
* <li>DOCKER_CONTEXT env var</li>
24+
* <li>docker.context in ~/.testcontainers.properties</li>
25+
* <li>current docker context pointed by the Docker config</li>
26+
* </ol>
27+
* <p>
28+
* Docker config resolution order is
29+
* <ol>
30+
* <li>DOCKER_CONFIG env var</li>
31+
* <li>$HOME/.docker</li>
1832
* </ol>
1933
*
2034
* @deprecated this class is used by the SPI and should not be used directly
@@ -43,9 +57,14 @@ public EnvironmentAndSystemPropertyClientProviderStrategy() {
4357
case "auto":
4458
Optional<String> dockerHost = getSetting("docker.host");
4559
dockerHost.ifPresent(configBuilder::withDockerHost);
46-
applicable = dockerHost.isPresent();
60+
getSetting("docker.config").ifPresent(configBuilder::withDockerConfig);
61+
getSetting("docker.context").ifPresent(configBuilder::withDockerContext);
4762
getSetting("docker.tls.verify").ifPresent(configBuilder::withDockerTlsVerify);
4863
getSetting("docker.cert.path").ifPresent(configBuilder::withDockerCertPath);
64+
// We don't have access to the docker-java internals to understand whether a docker-context is defined or not.
65+
// Therefore, we assume there is always a docker context defined and try it to start with.
66+
// In case there is an error initializing the docker client with this library, it will fallback to the other resolvers.
67+
applicable = true;
4968
break;
5069
case "autoIgnoringUserProperties":
5170
applicable = configBuilder.isDockerHostSetExplicitly();

docs/supported_docker_environment/index.md

+21-52
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,36 @@ These Docker environments are automatically detected and used by Testcontainers
1111

1212
It is possible to configure Testcontainers to work with alternative container runtimes.
1313
Making use of the free [Testcontainers Desktop](https://testcontainers.com/desktop/) app will take care of most of the manual configuration.
14-
When using those alternatives without Testcontainers Desktop,
14+
Although Testcontainers has a detection for most of the cases, when using those alternatives without Testcontainers Desktop,
1515
sometimes some manual configuration might be necessary
1616
(see further down for specific runtimes, or [Customizing Docker host detection](/features/configuration/#customizing-docker-host-detection) for general configuration mechanisms).
1717
Alternative container runtimes are not actively tested in the main development workflow,
1818
so not all Testcontainers features might be available.
1919
If you have further questions about configuration details for your setup or whether it supports running Testcontainers-based tests,
2020
please contact the Testcontainers team and other users from the Testcontainers community on [Slack](https://slack.testcontainers.org/).
2121

22-
## Colima
22+
## Docker environment discovery
2323

24-
In order to run testcontainers against [colima](https://github.com/abiosoft/colima) the env vars below should be set
24+
Testcontainers will try to connect to a Docker daemon using the following strategies in order:
25+
26+
* Environment variables:
27+
* `DOCKER_HOST`
28+
* `DOCKER_TLS_VERIFY`
29+
* `DOCKER_CERT_PATH`
30+
* `DOCKER_CONTEXT`
31+
* `DOCKER_CONFIG`
32+
* Defaults:
33+
* `DOCKER_HOST=https://localhost:2376`
34+
* `DOCKER_TLS_VERIFY=1`
35+
* `DOCKER_CERT_PATH=~/.docker`
36+
* `DOCKER_CONTEXT=$(docker context show)`
37+
* `DOCKER_CONFIG=~/.docker`
38+
* If the current docker context provides a working Docker environment, it will be preferred to further installation detection.
39+
* If Docker Machine is installed, the docker machine environment for the *first* machine found. Docker Machine needs to be on the PATH for this to succeed.
40+
* If you're going to run your tests inside a container, please read [Patterns for running tests inside a docker container](continuous_integration/dind_patterns.md) first.
41+
42+
Although this detection works in the majority of docker installations, for more complex installations, you may need to [customize the docker host detection](/features/configuration/#customizing-docker-host-detection).
2543

26-
```bash
27-
colima start --network-address
28-
export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock
29-
export TESTCONTAINERS_HOST_OVERRIDE=$(colima ls -j | jq -r '.address')
30-
export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock"
31-
```
3244

3345
## Podman
3446

@@ -59,49 +71,6 @@ export TESTCONTAINERS_RYUK_DISABLED=true
5971
Previous to version 1.19.0, `export TESTCONTAINERS_RYUK_PRIVILEGED=true`
6072
was required for rootful mode. Starting with 1.19.0, this is no longer required.
6173

62-
## Rancher Desktop
63-
64-
In order to run testcontainers against [Rancher Desktop](https://rancherdesktop.io/) the env vars below should be set.
65-
66-
If you're running Rancher Desktop as an administrator in a MacOS (M1) machine:
67-
68-
Using QEMU emulation
69-
70-
```bash
71-
export TESTCONTAINERS_HOST_OVERRIDE=$(rdctl shell ip a show rd0 | awk '/inet / {sub("/.*",""); print $2}')
72-
```
73-
74-
Using VZ emulation
75-
76-
```bash
77-
export TESTCONTAINERS_HOST_OVERRIDE=$(rdctl shell ip a show vznat | awk '/inet / {sub("/.*",""); print $2}')
78-
```
79-
80-
If you're not running Rancher Desktop as an administrator in a MacOS (M1) machine:
81-
82-
Using VZ emulation
83-
84-
```bash
85-
export DOCKER_HOST=unix://$HOME/.rd/docker.sock
86-
export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock
87-
export TESTCONTAINERS_HOST_OVERRIDE=$(rdctl shell ip a show vznat | awk '/inet / {sub("/.*",""); print $2}')
88-
```
89-
90-
## Docker environment discovery
91-
92-
Testcontainers will try to connect to a Docker daemon using the following strategies in order:
93-
94-
* Environment variables:
95-
* `DOCKER_HOST`
96-
* `DOCKER_TLS_VERIFY`
97-
* `DOCKER_CERT_PATH`
98-
* Defaults:
99-
* `DOCKER_HOST=https://localhost:2376`
100-
* `DOCKER_TLS_VERIFY=1`
101-
* `DOCKER_CERT_PATH=~/.docker`
102-
* If Docker Machine is installed, the docker machine environment for the *first* machine found. Docker Machine needs to be on the PATH for this to succeed.
103-
* If you're going to run your tests inside a container, please read [Patterns for running tests inside a docker container](continuous_integration/dind_patterns.md) first.
104-
10574
## Docker registry authentication
10675

10776
Testcontainers will try to authenticate to registries with supplied config using the following strategies in order:

0 commit comments

Comments
 (0)