Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Docker detection with Unix sockets #29562

Merged
merged 1 commit into from Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -9,6 +9,8 @@
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -73,8 +75,8 @@ private TestContainersStrategy(boolean silent) {

@Override
public Result get() {
//testcontainers uses the Unreliables library to test if docker is started
//this runs in threads that start with 'ducttape'
// Testcontainers uses the Unreliables library to test if docker is started
// this runs in threads that start with 'ducttape'
StartupLogCompressor compressor = new StartupLogCompressor("Checking Docker Environment", Optional.empty(), null,
(s) -> s.getName().startsWith("ducttape"));
try {
Expand Down Expand Up @@ -104,7 +106,7 @@ public Result get() {
} catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
if (!silent) {
compressor.closeAndDumpCaptured();
LOGGER.debug("Unable to use testcontainers to determine if Docker is working", e);
LOGGER.debug("Unable to use Testcontainers to determine if Docker is working", e);
}
return Result.UNKNOWN;
} finally {
Expand All @@ -122,26 +124,46 @@ public Result get() {
*/
private static class DockerHostStrategy implements Strategy {

private static final String UNIX_SCHEME = "unix";

@Override
public Result get() {

String dockerHost = System.getenv("DOCKER_HOST");
if (dockerHost != null && !dockerHost.startsWith("unix:")) {
try {
URI url = new URI(dockerHost);

if (dockerHost == null) {
return Result.UNKNOWN;
}

try {
URI dockerHostUri = new URI(dockerHost);

if (UNIX_SCHEME.equals(dockerHostUri.getScheme())) {
// Java 11 does not support connecting to Unix sockets so for now let's use a naive approach
Path dockerSocketPath = Path.of(dockerHostUri.getPath());

if (Files.isWritable(dockerSocketPath)) {
return Result.AVAILABLE;
} else {
LOGGER.warnf(
"Unix socket defined in DOCKER_HOST %s is not writable, make sure Docker is running on the specified host",
dockerHost);
}
} else {
try (Socket s = new Socket()) {
s.connect(new InetSocketAddress(url.getHost(), url.getPort()), DOCKER_HOST_CHECK_TIMEOUT);
s.connect(new InetSocketAddress(dockerHostUri.getHost(), dockerHostUri.getPort()),
DOCKER_HOST_CHECK_TIMEOUT);
return Result.AVAILABLE;
} catch (IOException e) {
LOGGER.warnf(
"Unable to connect to DOCKER_HOST URI %s, make sure docker is running on the specified host",
"Unable to connect to DOCKER_HOST URI %s, make sure Docker is running on the specified host",
dockerHost);
}
} catch (URISyntaxException | IllegalArgumentException e) {
LOGGER.warnf("Unable to parse DOCKER_HOST URI %s, it will be ignored for working docker detection",
dockerHost);
}
} catch (URISyntaxException | IllegalArgumentException e) {
LOGGER.warnf("Unable to parse DOCKER_HOST URI %s, it will be ignored for working Docker detection",
dockerHost);
}

return Result.UNKNOWN;
}
}
Expand Down
24 changes: 19 additions & 5 deletions docs/src/main/asciidoc/podman.adoc
Expand Up @@ -93,21 +93,35 @@ sudo apt install podman podman-docker docker-compose

Podman supports two modes of operation: rootful, in which case the container runs as root on the host system, and rootless, where the container runs under a standard Unix user account.
On Linux, the REST API Unix socket is, by default, restricted to only allow the root user to access it.
This prevents someone from using a container to achieve a privilege escalation on the syetem.
This prevents someone from using a container to achieve a privilege escalation on the system.
While these restrictions can be softened to allow a special group instead of just root, the recommended approach is to use rootless Podman on Linux.
To use rootless Podman, you need to set a DOCKER_HOST environment variable to point to the user-specific socket.
To use rootless Podman, you need to set a `DOCKER_HOST` environment variable to point to the user-specific socket.
In both cases, you need to start the REST API by enabling the Podman socket service through systemd.

[source]
----

# Enable the podman socket with Docker REST API (only needs to be done once)
systemctl --user enable podman.socket --now
# Set the required environment variables (need to be run everytime or added to profile)
----

Then, you can obtain the path of the socket with the following command:

[source]
----
$ podman info | grep -A2 'remoteSocket'

remoteSocket:
exists: true
path: /path/to/podman.sock
----

export DOCKER_HOST=unix:///run/user/${UID}/podman/podman.sock
Setting the `DOCKER_HOST` environment variable must be done every time or added to the profile:

[source]
----
export DOCKER_HOST=unix:///path/to/podman.sock <1>
----
<1> Replace `/path/to/podman.sock` with the path you obtained previously.

For a detailed explanation, see this https://quarkus.io/blog/quarkus-devservices-testcontainers-podman/[blog article].

Expand Down