5

After upgrading spring boot to 2.4 we cannot run the final docker image that we create via this script:

script:
    - echo $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY
    - apk add openjdk11
    - ./gradlew bootBuildImage --imageName=$DOCKER_IMAGE_INTERMEDIATE
    - docker build -f ./docker/Dockerfile --build-arg base_image=$DOCKER_IMAGE_INTERMEDIATE -t $DOCKER_IMAGE_TAGGED .
    - docker push $DOCKER_IMAGE_TAGGED
    - docker tag $DOCKER_IMAGE_TAGGED $DOCKER_IMAGE_LATEST
    - docker push $DOCKER_IMAGE_LATEST

our Dockerfile just creates a folder and chowns it to the CNB user:

# The base_image holds a reference to the image created by ./gradlew bootBuildImage
ARG base_image
FROM ${base_image}

ENV SOME_PATH /var/lib/some/files

USER root

RUN mkdir -p ${SOME_PATH}

RUN chown ${CNB_USER_ID}:${CNB_GROUP_ID} ${SOME_PATH}

USER ${CNB_USER_ID}:${CNB_GROUP_ID}

ENTRYPOINT /cnb/lifecycle/launcher

While this worked fine in spring boot 2.3, we now get this error after upgrading to spring boot 2.4 when trying to run the image:

ERROR: failed to launch: determine start command: when there is no default process a command is required

Edit:

The CI log output shows this line at the end of the bootBuildImage command:

[creator]     Setting default process type 'web'

Edit2:

By further inspecting the differences of the images created by bootBuildImage with spring-boot 2.3 and 2.4 I found a hint that the default ENTRYPOINT no longer is /cnb/lifecycle/launcher but /cnb/process/web.

Updating the last line of our Dockerfile to select this entrypoint:

ENTRYPOINT /cnb/process/web

enables us to start the image! yay! :)

However, I leave the question open, because I still wonder why the default process is no longer used by the lifecycle launcher?!

Stuck
  • 11,225
  • 11
  • 59
  • 104
  • With Spring Boot 2.3 configured by flag - and with 2.4 as the default - the `spring-boot-maven-plugin` and Gradle Plugin both use CNB/Paketo to build Docker images *without* the need to maintain or even write your own `Dockerfile` anymore. It's simply the reasoning behind Paketo that you don't need to bother about those anymore! So I see no reason to do a `docker build` inside GitLab anymore - but to use environment variables to configure the resulting images - and directly push them to the registry using the `bootBuildImage { docker { builderRegistry` configuration of the Gradle plugin. – jonashackt Dec 04 '20 at 11:08
  • To publish a Paketo build image there's an extra `--publishImage` parameter [provided by the Spring Boot Gradle plugin](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#build-image-example-publish) that can be used like that: `gradle bootBuildImage --imageName=yourImageName --publishImage`. You can even [configure your Docker registry credentials in the plugin configuration](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#build-image-example-docker). – jonashackt Dec 04 '20 at 11:12
  • 1
    @jonashackt how can we create a folder that is writeable from within the container? Our dockerfile creates that folder and chowns it to the CNB user. I do not see how the gradle plugin helps here. – Stuck Dec 04 '20 at 11:25
  • @jonashackt see https://stackoverflow.com/questions/64353768/can-bootbuildimage-create-writeable-volumes – Stuck Dec 04 '20 at 11:34
  • 1
    Ah I see! Thanks for the explanation. So you're in desparate need to use your own Dockerfile :( I didn't get the reasoning behind that first, but now it makes sense! The other question is abolutely interesting! Maybe it's possible to rephrase it a bit? `create writable volumes with Paketo` is the core problem if I get it correctly? Since the Gradle (or Maven) Plugin wrapper is only a convenience layer around pack CLI... – jonashackt Dec 04 '20 at 11:51
  • Yes, it is Paketo related, but from a spring boot's user perspective I would not like to fiddle with Paketo. Dockerfiles are still fine as most of our devs are used to Dockerfiles but they no longer need to deal with the layering and spring related stuff. – Stuck Dec 04 '20 at 12:08
  • I find it remarkable, that this use case was not considered by the paketo team - or at least the spring boot team. Is it a rare case to want to be able to have a microservice write to a volume, particularly with a spring boot application? Anyways I have the same problem, my SO post: https://stackoverflow.com/questions/67280070/write-access-on-volume-for-cnb-docker-image plus I opened an issue on the spring-boot repo : https://github.com/spring-projects/spring-boot/issues/26265 – IARI Apr 28 '21 at 06:07

2 Answers2

0

I found a similar issue when defining a Google Cloud Function.

My gut feeling is that you forgot to define an entrypoint for your function.

Riccardo
  • 1,104
  • 13
  • 22
0

This is likely because the specification, and therefore the lifecycle, changed in the time the application was upgraded to use spring boot 2.4

Refer:

The comparison is with v0.3 because that's the fallback when the environment variable CNB_PLATFORM_API is not set.