David
David

Reputation: 33

How can the locale and encoding set in cloudfoundry buildpack docker image built by spring boot gradle task "bootBuildImage"

When I create a docker image with a spring boot app, I see encoding problems in filenames of directories mounted into the running container with the spring boot app. I create the docker image by the gradle task bootBuildImage as described here.

When I look into the running container, I see the locale is set to posix. In a regular Dockerfile I would run the appropriate commands to setup a german utf-8 locale setting. But spring boot is using cloud foundry buildpacks and I can find no place to hook into for the locale setting. How can I adjust the locale for the image in the build process?

cnb@9d24bfe67b9e:/$ locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

Upvotes: 3

Views: 1309

Answers (3)

chkpnt
chkpnt

Reputation: 387

To tailor the environment variables for the compiled image, consider employing the Environment Variables buildpack, as elaborated here. When working with a Gradle build script, adjust the bootBuildImage task as follows:

tasks.named<BootBuildImage>("bootBuildImage") {
    // ...
    environment["BPE_LANG"] = "de_DE.UTF-8"
    /// ...
}

It's unnecessary to set LC_* variables explicitly since they are automatically inferred from LANG upon container initiation:

cnb@1a31e0852193:/$ locale
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=de_DE.UTF-8
LANGUAGE=
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_COLLATE="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_MESSAGES="de_DE.UTF-8"
LC_PAPER="de_DE.UTF-8"
LC_NAME="de_DE.UTF-8"
LC_ADDRESS="de_DE.UTF-8"
LC_TELEPHONE="de_DE.UTF-8"
LC_MEASUREMENT="de_DE.UTF-8"
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=

The warnings are a result of the specified locale not being pre-generated in the container. While altering the run image, as suggested by Scott, is a solution, it does entail additional maintenance. However, for a JVM-based application, these warnings might be negligible since the JVM utilizes $LANG only to set the default locale.

In my opinion, a cleaner solution for a JVM application within a container built by bootBuildImage is to use C.UTF-8, so you get the desired UTF-8 character encoding without any warnings about non-present locales in the system logs. The locale used by the Java application can in turn be configured via the corresponding JVM system properties (user.language, user.country and user.variant). In the Paketo base images, which are used by default by the Spring Boot Gradle Plugin, C.UTF-8 is preinstalled:

cnb@d94c8fe708ff:/# locale -a
C
C.utf8
POSIX
en_US.utf8

Therefore, this is the bootBuildImage task configuration I would use:

tasks.named<BootBuildImage>("bootBuildImage") {
    // ...
    environment["BPE_APPEND_JAVA_TOOL_OPTIONS"] = "-Duser.language=de -Duser.country=DE"
    environment["BPE_DELIM_JAVA_TOOL_OPTIONS"] = " "
    environment["BPE_LANG"] = "C.UTF-8"
    /// ...
}

Upvotes: 0

keydon
keydon

Reputation: 729

Even though I think Scotts answer ist still the best, as an alternative option you can set enviromentvariables for the builder image, which can control the environment variables for the final image.

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <image>
            <env>
                <BPE_DELIM_JAVA_TOOL_OPTIONS xml:space="preserve"> </BPE_DELIM_JAVA_TOOL_OPTIONS>
<BPE_APPEND_JAVA_TOOL_OPTIONS>-XX:+HeapDumpOnOutOfMemoryError</BPE_APPEND_JAVA_TOOL_OPTIONS>
            </env>
        </image>
    </configuration>
</plugin>

see https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#build-image-example-builder-configuration

Upvotes: 0

Scott Frederick
Scott Frederick

Reputation: 5145

By default, the Spring Boot Gradle plugin uses the Paketo builder image and run image. The run image provides the base OS layer for the generated app image, and this is where the locale is coming from.

One way to override the locale would be to generate a custom run image based on the Paketo run image and setup the locale in your custom run image. A Dockerfile for the custom run image might look something like this:

FROM paketobuildpacks/run:base-cnb

USER root
RUN apt-get install -y locales
RUN locale-gen de_DE.utf8
ENV LANG de_DE.UTF-8
ENV LANGUAGE de_DE:de
ENV LC_ALL de_DE.UTF-8

Once you've built and tagged the custom run image, you can override the default run image in the Spring Boot Gradle plugin configuration with the runImage property or on the command line with the ---runImage flag.

Upvotes: 2

Related Questions