I need to create a specific directory in an image built with a cloud-native build pack. It's a spring-boot application and I use the standard cloud-native build pack included with it.
With a Dockerfile this is a snippet of how I would do it:
FROM openjdk:11-jre-slim
RUN mkdir -p /data/stream-price-service
RUN addgroup kstream && useradd -m kstream -g kstream
RUN chown -R kstream:kstream /data/stream-price-service
USER kstream:kstream
So when the application starts it has access and ownership over the folder /data/stream-price-service
and can use it as it's local storage location.
So with buildpack I also need that when the container starts the directory data/stream-price-service
exists and is rw for the spring-boot application. I have tried using the <directories>
configuration but it doesn't create the directory:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>stream-price-service</name>
</image>
<directories>/data/stream-price-service</directories>
</configuration>
</plugin>
The above configuration doesn't work.
Using spring boot build pack to create the image, how to create the directory structure and assign ownership so when the container starts it's available?
CodePudding user response:
By default, the buildpack runs as a non-root user and group called cnb
. It cannot create arbitrary directories under root, like /data
. It can only create directories within certain locations, like /layers
(where buildpacks install things) or /workspace
(where the application lives, although this is not recommended).
When your application runs, it will execute as the cnb
user and group also, this provides you similar access to where you can write things as the buildpack. For enhanced security, the generated OCI image can be run as a different user. In this case, you can only write to locations that are group writable or world-writable (like /tmp
).
Best case, you can change your application to write somewhere else. Make the directory configurable (@Value
or @ConfigurationProperties
), Spring is very flexible so you can pass in config through env variables, system properties, or arguments. Then write to that location instead.
If you can't change the location, it gets more difficult. At the moment, there's not an easy way to change the base image. You would essentially need to create a custom run image.
The full process to create a custom stack is here, however, you don't need a full stack, just a custom run image.
If you base off of the Paketo run image you're presently using, like paketobuildpacks/builder:base
or paketobuildpacks/builder:tiny
, you can add the location you need to the custom run image, change the permissions to be read/write for the cnb
user, and then switch the run image when you build with the runImage
property with Spring Boot builds or the --run-image
flag with pack build
.
To base off one of the Paketo images, just create a Dockerfile and add FROM <paketo-run-image>
.
Ex:
FROM paketobuildpacks/run:base-cnb
USER root
RUN mkdir /data && chown cnb:cnb /data
USER cnb
Then pack build cool-image --run-image custom-run-base
.