Spring boot - Jasypt - Dockerfile - Build - how to pass environemnt variables - spring-boot

I am following spring io article on how to use docker for spring boot. So using Dockerfile
https://github.com/spring-guides/top-spring-boot-docker/tree/main/demo
Issue: Test failing
Caused by: java.lang.IllegalArgumentException at
PropertyPlaceholderHelper.java:178
My application has a few environment variables dependency
jasypt.encryptor.password=${mjasypt.secret}
jasypt.encryptor.algorithm=${mjasypt.algo}
I am running build as below
docker build --build-arg DEPENDENCY=build/dependency -t ....
I tried 3 new env args into dockerfile
ARG CBS=a
ARG JSP=b
ARG JSA=c
and update entry point
ENTRYPOINT ["java","-noverify","-XX:TieredStopAtLevel=1","-cp","app:app/lib/*","-Dspring.main.lazy-initialization=true","-Dv1=${CBS}", "-Dv2=${JSP}", "-Dv3=${JSA}",...
and running command as, but didn't work
docker build --build-arg DEPENDENCY=build/dependency --build-arg CBS=.. --build-arg JSP=..1 --build-arg JSA=P..ES -t ...
Ive added RUN echo ${CBS} in the dockerfile and I can see the value that I passed from docker build (not a), but how can I know if that is inside ENTRY POINT too
CORRECTION:
Dockerfile is multistage and also has
RUN --mount=type=cache,target=/root/.gradle ./gradlew clean build
How can I pass values to this command , as it runs tests

ARG in Dockerfile is only available in the build stage.
When you want to run it as a container, ARG values will not be available but ENV will be. This means you can not directly access those values in ENTRYPOINT (also not available in CMD). You can read this similar question for more info.
If you want to pass environment parameters to the container using the build arguments (ARG), the simple solution will be to do something like this:
ARG CBS=a
ARG JSP=b
ARG JSA=c
ENV CBS_ENV=$CBS
ENV JSP_ENV=$JSP
ENV JSA_ENV=$JSA
Then update your ENTRYPOINT
ENTRYPOINT ["java","-noverify","-XX:TieredStopAtLevel=1","-cp","app:app/lib/*","-Dspring.main.lazy-initialization=true","-Dv1=${CBS_ENV}", "-Dv2=${JSP_ENV}", "-Dv3=${JSA_ENV}",...
If your values are only used when the container is running, then you can remove ARG entirely, and pass it as arguments when the container is starting. Read this similar question for more info.
e.g.:
docker run -e CBS='a' -e JSP='b' -e JSA='c' mynicevue
UPDATE:
ARG CBS=a
ARG JSP=b
ARG JSA=c
# First stage
FROM openjdk:8-jdk-alpine AS build
WORKDIR /workspace/app
RUN --mount=type=cache,target=/root/.gradle ./gradlew clean build
RUN mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*.jar)
# Second stage
FROM openjdk:8-jdk-alpine
ARG DEPENDENCY=/workspace/app/build/dependency
ARG CBS
ARG JSP
ARG JSA
ENV CBS=$CBS
ENV JSP=$JSP
ENV JSA=$JSA
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java", "-cp", "app:app/lib/*", "hello.Application", "-Dv1=${CBS}", "-Dv2=${JSP}", "-Dv3=${JSA}"]

Related

How to Pass environment as argument for a spring boot docker image?

I created a docker file like this
ARG ENV
FROM openjdk:11-jdk
COPY target/*.jar app.jar
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=${ENV}", "app.jar"]
while doing
docker run -p 8100:8080 anupbiswas1984/docker-env --e ENV=test
it is not identifying ${ENV}
How can I pass the ENV as an argument during "docker run..."
Get rid of the ARG thing, as it's not needed and you aren't using it correctly anyway. Per the documentation:
The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command
So ARG is a build-time thing, and you are trying to use it as a run-time environment variable.
Also, you can get rid of the "-Dspring.profiles.active=${ENV}" part of your ENTRYPOINT because Spring Boot already looks for an environment variable named SPRING_PROFILES_ACTIVE so there's no need to define another thing here, and you're also introducing an issue with the way you are trying to resolve the ENV variable here.
FROM openjdk:11-jdk
COPY target/*.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]
Then run it with:
docker run -e SPRING_PROFILES_ACTIVE=test -p 8100:8080 anupbiswas1984/docker-env

build spring boot (mvnw) with docker can not use cache

Spring Boot Docker Experimental Features
Docker 18.06 comes with some “experimental” features, including a way to cache build dependencies. To switch them on, you need a flag in the daemon (dockerd) and an environment variable when you run the client.
With the experimental features, you get different output on the console, but you can see that a Maven build now only takes a few seconds instead of minutes, provided the cache is warm.
my dockerfile can not use cache.
dockerfile
# syntax=docker/dockerfile:experimental
FROM openjdk:8-jdk-alpine as build
WORKDIR /workspace/app
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src
RUN --mount=type=cache,target=/root/.m2 ./mvnw install -DskipTests -s .mvn/wrapper/settings.xml
RUN mkdir -p target/extracted && java -Djarmode=layertools -jar target/*.jar extract --destination target/extracted
FROM openjdk:8-jre-alpine
ENV TZ Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG EXTRACTED=/workspace/app/target/extracted
ARG JAVA_OPTS="-Xmx100m -Xms100m"
COPY --from=build ${EXTRACTED}/dependencies/ ./
COPY --from=build ${EXTRACTED}/spring-boot-loader/ ./
COPY --from=build ${EXTRACTED}/snapshot-dependencies/ ./
COPY --from=build ${EXTRACTED}/application/ ./
ENTRYPOINT ["sh", "-c","java ${JAVA_OPTS} org.springframework.boot.loader.JarLauncher"]
run shell
DOCKER_BUILDKIT=1 docker build -t org/spring-boot .
every time use many minutes

How to execute gradle build before the Docker build on Heroku?

I want to deploy a dockerized Spring-Boot application built with gradle on the Heroku platform when a commit is pushed on github.
I deployed successfully the docker image with CLI, by building the image locally and then deploying it
I deployed successfully "on github push" with the "heroku-18" stack. After each commit, Heroku detects that my project is a gradle one, build it and deploys it with no problem. This method doesn't trigger Docker.
Now, I want to switch to the "container" stack, for Heroku to build my Dockerfile and deploys my app after each commit. The Dockerfile is correctly detected, but because the JAR is not generated, the Dockerfile step fails.
How can I trigger the generation of the JAR on Heroku side for the Dockerfile to be able to copy this JAR to the container ?
Heroku logs
=== Fetching app code
=== Building web (Dockerfile)
Sending build context to Docker daemon 50.69kBStep 1/11 : FROM openjdk:11-jre-slim
11-jre-slim: Pulling from library/openjdk
...
Step 4/11 : ADD build/libs/myapp-1.0-SNAPSHOT.jar /app/myapp.jar
ADD failed: stat /var/lib/docker/tmp/docker-builder545575378/build/libs/myapp-1.0-SNAPSHOT.jar: no such file or directory
heroku.yml
build:
docker:
web: Dockerfile
Dockerfile
FROM openjdk:11-jre-slim
VOLUME /var/log/my-app
ARG JAR_FILE
ADD build/libs/my-app-1.0-SNAPSHOT.jar /app/my-app.jar
RUN chgrp -R 0 /app
RUN chmod -R g+rwX /app
RUN chgrp -R 0 /var/log/my-app
RUN chmod -R g+rwX /var/log/my-app
CMD [ "-jar", "/app/my-app.jar" ]
ENTRYPOINT ["java"]
EXPOSE 8080
Probably you can't do that outside your Dockerfile.
But you can use Docker multi-stage builds like this:
FROM adoptopenjdk/openjdk14-openj9:alpine as build
COPY . /opt/app/src
WORKDIR /opt/app/src
RUN ./gradlew clean bootJar
FROM adoptopenjdk/openjdk14-openj9:alpine-jre
COPY --from=build opt/app/app.jar /opt/app/app.jar
CMD ["java", "-server", "-XX:MaxRAM=256m", "-jar", "/opt/app/app.jar"]

passing command line parameters to spring boot services inside docker container

I have got a set of spring boot apps that I would like to package as docker containers.
I am using the following Dockerfile to create the container for one of the services:
FROM java:8
VOLUME /tmp
ADD myservice.jar app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
Inside, the services access some environment properties like for instance:
#Value("${my.test.param:default}")
String testParam;
.
.
.
logger.info("param value is = "+testParam);
Now, I would like to be able to override this setting via docker run command line like this
docker run -p 8080:8080 -e my.test.param=changed mygroup/myservice:0.0.1
Unfortunately, this doesn't seem to work. I keep seeing the default value for the parameter my.test.param.
I searched for ways to automatically add all -e parameters at the end of the ENTRYPOINT line, but didn't find any. Is there some general solution for this?

How to override the CMD command in the docker run line

How you can replace the cmd based on the docker documentation:
https://docs.docker.com/reference/builder/#cmd
You can override the CMD command
Dockerfile:
RUN chmod +x /srv/www/bin/* & chmod -R 755 /srv/www/app
RUN pip3 install -r /srv/www/app/pip-requirements.txt
EXPOSE 80
CMD ["/srv/www/bin/gunicorn.sh"]
the docker run command is:
docker run --name test test/test-backend
I tried
docker run --name test test --cmd ["/srv/www/bin/gunicorn.sh"]
docker run --name test test cmd ["/srv/www/bin/gunicorn.sh"]
But the console say this error:
System error: exec: "cmd": executable file not found in $PATH
The right way to do it is deleting cmd ["..."]
docker run --name test test/test-backend /srv/www/bin/gunicorn.sh
The Dockerfile uses CMD instruction which allows defaults for the container being executed.
The below line will execute the script /srv/www/bin/gunicorn.sh as its already provide in CMD instruction in your Dockerfile as a default value, which internally gets executed as /bin/sh -c /srv/www/bin/gunicorn.sh during runtime.
docker run --name test test/test-backend
Now say if you want to run some thing else, just add that at a end of the docker run. Now below line should run bash instead.
docker run --name test test/test-backend /bin/bash
Ref: Dockerfile Best Practices
For those using docker-compose:
docker-compose run [your-service-name-here-from-docker-compose.yml] /srv/www/bin/gunicorn.sh
In my case I'm reusing the same docker service to run the development and production builds of my react application:
docker-compose run my-react-app npm run build
Will run my webpack.config.production.js and build the application to the dist. But yes, to the original question, you can override the CMD in the CLI.
Try this in your Dockerfile
CMD ["sh" , "-c", "command && bash"]

Resources