How to add extra linux dependencies into a spring-boot buildpack image? How to add extra linux dependencies into a spring-boot buildpack image? docker docker

How to add extra linux dependencies into a spring-boot buildpack image?


This answer assumes that by "... spring-boot application to use buildpacks" you mean the use of the spring-boot:build-image maven goal.

The issue lays with the default builder (gcr.io/paketo-buildpacks/builder:base) used by the maven plugin. Builder is responsible for configuring the OS image, and the "base" builder doesn't include fontconfig package. .


The easiest way to enable fontconfig package is to use the "full" builder (gcr.io/paketo-buildpacks/builder:full-cf or gcr.io/paketo-buildpacks/builder:latest); you can do so for example in one of the following ways:

  • by specifying the builder configuration parameter in the maven plugin,

    <project><build>   <plugins>       <plugin>           <groupId>org.springframework.boot</groupId>           <artifactId>spring-boot-maven-plugin</artifactId>           <version>2.3.3.BUILD-SNAPSHOT</version>           <configuration>               <image>                   <builder>gcr.io/paketo-buildpacks/builder:latest</builder>               </image>           </configuration>       </plugin>   </plugins></build></project>
  • or directly on your mvn command line by adding -Dspring-boot.build-image.builder=gcr.io/paketo-buildpacks/builder:latest.

However, this is not ideal because the full OS image is much larger (approx. 1.45GB for "full" vs. 644MB for "base" - observed in docker image listing), a fair bit of overhead "just" for enabling fontconfig.


A more involved approach would require creating a custom builder with custom mixins, in order to create a tailored "base" image with the extra packages. But I personally found it easier to just use the dockerfile approach in this scenario. Some articles on creating a custom builder:


As Michal outlined, using the bigger paketobuildpacks/builder:full builder isn't ideal. Also creating a custom builder & stack would be a huge overhead - since we want to use Cloud Native Buildpacks to free us from the burden of maintaining our own Dockerfile. And creating our own builder/stack would bring in way more complexity then we had before writing the Dockerfile.

On the other hand, the need to install separate packages into the container images created by the spring-boot-maven-plugin or Spring Boot Gradle plugins is widespread. So I thought of a minimally invasive solution - and here it is (as derived from). Let's assume our mvn spring-boot:build-image (or Gradle buildImage) command produced a container image called my-app:0.0.1-SNAPSHOT:

Now first install fontconfig ttf-dejavu into the image with (we need root priviledges for that):

docker run --user="root" --entrypoint launcher my-app:0.0.1-SNAPSHOT "apt-get update && apt-get install fontconfig ttf-dejavu -y"

Crab container id of the stopped container with docker ps -a:

$ docker ps -aCONTAINER ID   IMAGE                                  COMMAND                  CREATED          STATUS                       PORTS     NAMES2ff7db32825f   my-app:0.0.1-SNAPSHOT   "launcher 'apt-get u…"   44 minutes ago   Exited (0) 44 minutes ago              reverent_swanson

Create a new container image based on the one we installed curl into with:

docker commit 2ff7db32825f my-app-with-fontconfig-ttf

Fire up a new container defining the correct ENTRYPOINT to start Spring Boot app & switching back to the CNB's standard cnb user (and not using root anymore to avoid potential security risks):

docker run --rm -p 8080:8080 --user="cnb" --entrypoint /cnb/process/web my-app-with-fontconfig-ttf

For a more detailled background info see this so answer also.