I'm using Spring buildpacks introduced by Spring Boot 2.3.0.M1 for creating Docker images of Spring based applications. Everything goes well, I can create docker images for each application by executing ./gradlew bootBuildImage
Gradle task, point docker-compose file to created images (e.g. image: spring-test:latest
) and at the end successfully run all applications (docker-compose up
).
Even though I have a bash script to automate the build process, I'd like to get rid of this additional step and make the Spring buildpacks task executed automatically whenever I run docker-compose up --build
command thus the docker image of each application would get built and uploaded to the host's local docker repository from where it would be taken over by docker compose.
My first try was to create a dummy Dockerfile for each application which executes the bootBuildImage
task on the host, but that would require an SSH connection from docker to host and not even sure that would work correctly.
Another thought was to use a similar approach, only change is to first mount or copy the app's source code to docker, configure buildpacks to store image into host's local docker image repo (perhaps SSH connection) and finally execute buildpacks on docker.
I'm wondering if there isn't a better, more elegant solution though.
This question really drove me nuts, since I've been playing around with Spring Boot & Paketo Buildpacks for quite a while now - and I really love the simplicity of Docker-Compose. So the questions was already inside the back of my head, but then you asked it :)
I didn't found a 100% perfect solution, but I think a have some ideas. Let's assume a example project of multiple Spring Boot apps, that are composed by a Maven multi-module setup (I know you're using Gradle, but there's a guide on doing multi module setups with Gradle over at the great spring.io guides): github.com/jonashackt/cxf-spring-cloud-netflix-docker. I created a new branch
buildpacks-paketo
containing all we need - and removed allDockerfiles
from the respective Spring Boot apps. Since we shouldn't need them anymore using Cloud Native Buildpacks (which is kind of their design goal).TLDR: My idea is to use the
spring-boot-maven-plugin
(or it's Gradle equivalent) to issue a fresh Paketo build before every "normaldocker-compose up
like this:The example projects parent
pom.xml
look like this (shortened):The example projects
docker-compose.yml
looks straightforward and uses the container images producted by Paketo (which is triggered by the Maven plugin) - those are named like this:eureka-serviceregistry:0.0.1-SNAPSHOT
. Here's the fulldocker-compose.yml
for all Spring Boot services:=== Possible enhancements =====================
The idea stuck me to also have "on single
docker-compose.yml
and only usedocker-compose up
as you asked for - no additional command. Therefore I created another "Docker Compose build service" that should only build the service images like this:I first integrated this service in the
docker-compose.yml
I already had. Running adocker-compose up paketo-build
did what I was looking for: building all our Spring Boot apps inside the Compose setup:But that didn't feel right because of a bunch of reasons. One is that you need to somehow wait with the startup of all other Compose services until the
paketo-build
service did it's job and build all the images. BUT as the Docker docs tell us, we will need to work against design decisions made in Compose to make that happen! Also did I find this great answer, where Max explains that it's not a good design to "pollute" the "production"docker-compose.yml
with containers that are solely there for the build.After that I extracted the
paketo-build
service into it's own Compose file - calledbuild.yml
inside the example project. With that we're now able to run the Paketo build without relying on the host to have Maven installed - and solely with Docker-Compose:Remember to not detach from the first container with
-d
since the full Paketo build has to be finished before we start ourdocker-compose.yml
. With this approach we also need absolutely noDockerfile
. But at the same time the idea came to me to remove the need for a separate build container fully and simply use Maven (or Gradle) before theup
concatenated by a&&
like already described in the TLDR:Hope this is of help to you. Would be glad to hear your feedback! Here's also a full GitHub actions build showing all the "magic" on a Cloud CI server.
Right now there's afaik no way to use
docker-compose up --build
to trigger a fresh image build of all your Spring Boot apps using Paketo Buildpacks.