I have a simple Spring Boot 3.2.4 application. After trying to integrate the Docker Compose support, the application is unable to start with a rather confusing message: Unable to start docker process. Is docker correctly installed? — similar to this issue.

Basically, all I did was add developmentOnly("org.springframework.boot:spring-boot-docker-compose") to build.gradle.kts, and create the compose.yaml file with a standard PostgreSQL service.

I do have Docker installed — I use it extensively, so this shouldn't be the problem. I can certainly post the compose.yaml file I'm using, but as far as I can tell, this is failing here.

The application fails with this stacktrace:

$ ./gradlew bootRun 
Configuration on demand is an incubating feature.
> Task :generateEffectiveLombokConfig UP-TO-DATE
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :resolveMainClassName UP-TO-DATE

> Task :bootRun FAILED

...

2024-04-07 01:39:03,471 |- DEBUG in org.acme.Application:51 [main] - Running with Spring Boot v3.2.4, Spring v6.1.5
2024-04-07 01:39:03,471 |-  INFO in org.acme.Application:660 [main] - The following 1 profile is active: "dev"
2024-04-07 01:39:03,636 |- ERROR in o.s.boot.SpringApplication:851 [main] - Application run failed
org.springframework.boot.docker.compose.core.DockerProcessStartException: Unable to start docker process. Is docker correctly installed?
        at org.springframework.boot.docker.compose.core.DockerCli$DockerCommands.getDockerCommand(DockerCli.java:140)
        at org.springframework.boot.docker.compose.core.DockerCli$DockerCommands.<init>(DockerCli.java:129)
        at org.springframework.boot.docker.compose.core.DockerCli.lambda$new$0(DockerCli.java:65)
        at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1228)
        at org.springframework.boot.docker.compose.core.DockerCli.<init>(DockerCli.java:64)
        at org.springframework.boot.docker.compose.core.DockerCompose.get(DockerCompose.java:92)
        at org.springframework.boot.docker.compose.lifecycle.DockerComposeLifecycleManager.getDockerCompose(DockerComposeLifecycleManager.java:154)
        at org.springframework.boot.docker.compose.lifecycle.DockerComposeLifecycleManager.start(DockerComposeLifecycleManager.java:110)
        at org.springframework.boot.docker.compose.lifecycle.DockerComposeListener.onApplicationEvent(DockerComposeListener.java:53)
        at org.springframework.boot.docker.compose.lifecycle.DockerComposeListener.onApplicationEvent(DockerComposeListener.java:35)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138)
        at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
        at org.springframework.boot.context.event.EventPublishingRunListener.contextLoaded(EventPublishingRunListener.java:98)
        at org.springframework.boot.SpringApplicationRunListeners.lambda$contextLoaded$4(SpringApplicationRunListeners.java:72)
        at java.base/java.lang.Iterable.forEach(Iterable.java:75)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112)
        at org.springframework.boot.SpringApplicationRunListeners.contextLoaded(SpringApplicationRunListeners.java:72)
        at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:432)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:333)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343)
        at org.acme.Application.main(Application.java:23)
Caused by: org.springframework.boot.docker.compose.core.ProcessStartException: Unable to start command docker version --format {{.Client.Version}}
        at org.springframework.boot.docker.compose.core.ProcessRunner.startProcess(ProcessRunner.java:115)
        at org.springframework.boot.docker.compose.core.ProcessRunner.run(ProcessRunner.java:87)
        at org.springframework.boot.docker.compose.core.ProcessRunner.run(ProcessRunner.java:74)
        at org.springframework.boot.docker.compose.core.DockerCli$DockerCommands.getDockerCommand(DockerCli.java:135)
        ... 25 common frames omitted
Caused by: java.io.IOException: Cannot run program "docker": error=2, No such file or directory
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1170)
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1089)
        at org.springframework.boot.docker.compose.core.ProcessRunner.startProcess(ProcessRunner.java:105)
        ... 28 common frames omitted
Caused by: java.io.IOException: error=2, No such file or directory
        at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
        at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:295)
        at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:225)
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1126)
        ... 30 common frames omitted

The GNU/Linux distribution I'm using is Arch Linux. I followed the official guide to install Docker, so it's indeed, installed correctly — and I don't have any problems running any docker or docker compose commands within the operating system's console.

System Configuration
$ uname -a 
Linux uplink 6.6.23-1-lts #1 SMP PREEMPT_DYNAMIC Wed, 27 Mar 2024 07:47:20 +0000 x86_64 GNU/Linux

$ ./gradlew --version 
------------------------------------------------------------
Gradle 8.6
------------------------------------------------------------

Build time:   2024-02-02 16:47:16 UTC
Revision:     d55c486870a0dc6f6278f53d21381396d0741c6e

Kotlin:       1.9.20
Groovy:       3.0.17
Ant:          Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM:          21.0.2 (Eclipse Adoptium 21.0.2+13-LTS)
OS:           Linux 6.6.23-1-lts amd64

$ java --version 
openjdk 21.0.2 2024-01-16 LTS
OpenJDK Runtime Environment Temurin-21.0.2+13 (build 21.0.2+13-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.2+13 (build 21.0.2+13-LTS, mixed mode, sharing)

$ docker --version 
Docker version 26.0.0, build 2ae903e86c

$ docker compose version 
Docker Compose version 2.26.1

$ which docker 
/usr/bin/docker

$ whereis docker 
docker: /usr/bin/docker /usr/lib/docker /usr/share/man/man1/docker.1.gz

The PATH environment variable correctly includes the /usr/bin location — verified with System.getenv().forEach { println("${it.key}=${it.value}") }.

Comment From: wilkinsona

Thanks for the report. Unfortunately, it's hard to tell what may be wrong here without being able to reproduce the problem. I suspect it's something to do with the PATH but that's just a lightly educated guess. You could try adding the following to your build.gradle script:

tasks.named('bootRun') {
    doFirst {
        println environment
    }
}

This should let us check if /usr/bin is on the PATH used by bootRun. It would also be interesting to know if the Docker Compose integration works when you run your app in your IDE or from a packaged jar.

Comment From: x80486

Thank you for spending some time in addressing this issue. I've managed to resolve the problem, although the exact cause remains unclear to me. I didn't make any modifications, but the feature now works as expected.

I did verify that /usr/bin was correctly added to PATH, yet initially encountered difficulties.

$ ./gradlew bootRun 
Configuration on demand is an incubating feature.
> Task :generateEffectiveLombokConfig FROM-CACHE
> Task :compileJava
> Task :processResources UP-TO-DATE
> Task :classes
> Task :resolveMainClassName

> Task :bootRun

...

2024-04-10 17:08:38,836 |- DEBUG in org.acme.Application:51 [main] - Running with Spring Boot v3.2.4, Spring v6.1.5
2024-04-10 17:08:38,836 |-  INFO in org.acme.Application:660 [main] - The following 1 profile is active: "dev"
2024-04-10 17:08:41,667 |-  WARN in liquibase.lockservice:37 [main] - Failed to release change log lock
All objects dropped from spring-boot@jdbc:postgresql://127.0.0.1:5432/spring-boot
Running Changeset: database/migrations/changelog-1.sql::1::liquibase
Liquibase: Update has been successful. Rows affected: 1
2024-04-10 17:08:42,004 |-  INFO in o.s.b.w.e.netty.NettyWebServer:141 [main] - Netty started on port 8080
2024-04-10 17:08:42,011 |-  INFO in org.acme.Application:56 [main] - Started Application in 3.451 seconds (process running for 3.655)

Anyway, thanks for your support and for this feature! It complements the framework in many ways.

Comment From: x80486

Somehow, I think the Gradle daemon is playing tricks here. I've managed to replicate this. Problem is that I'm using the Flatpak version of IntelliJ IDEA, so if I initially start the application from the IDE, it fails to start with the error that it can't find the docker / docker compose commands.

It gets confusing because when I then go to the operating system's terminal, the PATH does have /usr/bin, but somehow the Gradle daemon may not have the correct settings (or something around those lines), and the application still fails to start.

If I kill the Gradle daemon and start the application from the operating system's terminal, everything is fine — but in turn, I get a weird error then if I want to start it from the IDE:

1:49:05 PM: Executing ':classes'...

FAILURE: Build failed with an exception.

* What went wrong:
The specified initialization script '/tmp/ijMapper1.gradle' does not exist.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 611ms