Packaging war file into docker image in multiple layers - spring-boot

I'm trying to put a Spring Boot application with war packaging into a docker image. The simplest way to get this can be using the following Dockerfile:
FROM adoptopenjdk/openjdk8:alpine-slim
VOLUME /tmp
COPY target/demo.war app.war
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.war"]
Following this approach I'm creating a big layer every time I change the project's source code. An alternative to this is to split the war into different docker layers as it is explained in this post: https://spring.io/blog/2018/11/08/spring-boot-in-a-container#a-better-dockerfile
However, I'm afraid this is only possible with jar packaging and not with war. Am I right?
Thanks in advance.

This is the way I get a multilayer docker image with a war applicaton.
First open the war file to find out which folders have to be copied to the image:
jar -xf youapp.war
In my project the war file is composed of these folders:
/WEB-INF
/META-INF
/resources
/org
Based on this, I created the following Dockerfile:
FROM openjdk:8-jdk-alpine AS builder
WORKDIR target/dependency
ARG APPWAR=target/*.war
COPY ${APPWAR} app.war
RUN jar -xf ./app.war
RUN mv WEB-INF/lib-provided lib-provided
RUN mv WEB-INF/lib lib
FROM openjdk:8-jre-alpine
VOLUME /tmp
ARG DEPENDENCY=target/dependency
COPY --from=builder ${DEPENDENCY}/lib /app/WEB-INF/lib
COPY --from=builder ${DEPENDENCY}/lib-provided /app/WEB-INF/lib-provided
COPY --from=builder ${DEPENDENCY}/org /app/org
COPY --from=builder ${DEPENDENCY}/resources /app/resources
COPY --from=builder ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=builder ${DEPENDENCY}/WEB-INF /app/WEB-INF
ENTRYPOINT ["java","-cp","/app/WEB-INF/classes:/app/WEB-INF/lib/*:/app/WEB-INF/lib-provided/*","com.company.project.Application"]
I hope it is useful.

Try using the Tomcat Docker image to deploy your warfile. For example:
FROM tomcat:latest
COPY target/demo.war /usr/local/tomcat/webapps/
Reference:
https://hub.docker.com/_/tomcat

Related

Dockerfile copy file without version

In my project, after the build, there are two files
build/libs
backend-api-0.0.1-SNAPSHOT.jar
backend-api-0.0.1-SNAPSHOT-plain.jar
How can I get rid of the jar version designation when building a docker image
COPY --from=builder /home/source/build/libs/backend-api-0.0.1-SNAPSHOT.jar /home/api/
You can rename the file while copying.
COPY --from=builder \
/home/source/build/libs/backend-api-*-SNAPSHOT.jar \
/home/api/backend.jar
Dockers COPY instruction is using Go’s filepath.Match rules.

Creating Docker image with springboot layertools - does not find profile specific application properties

I am following the tutorial here and here on how to create a layered Docker image from my springboot backend. I end up with the following Dockerfile:
FROM openjdk:8-jre-slim as builder
WORKDIR application
ARG JAR_FILE=target/*-exec.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM openjdk:8-jre-slim
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
The problem is that when I run this in my docker-compose with a Spring profile TST, that it does not find application-tst.properties. I can see from the logs that Spring profile TST is active on startup, yet it only loads the properties from application.properties.
As a sanity check I copied the properties from application-tst.properties over to application.properties and rebuilt my image, which then worked fine (it connects to the database container etc).
I extracted the contents of my executable jar (which is the jar from line 3 in the Dockerfile) and can confirm that application-tst.properties is present there. Anyone know what the issue is?
I found the answer and it's a really dumb one... The Spring profile is case sensitive, so
SPRING_PROFILES_ACTIVE=TST
should become
SPRING_PROFILES_ACTIVE=tst

Docker multi-stage build not running all stages

I am trying to build an image from this Dockerfile:
FROM openjdk:14-slim-buster AS builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM openjdk:14-slim-buster
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/resources/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
The problem is it never reaches the second stage. I can see the total steps in the counter when the image is being built, but it just stops and executes this as a new container which is running the actual application
RUN java -Djarmode=layertools -jar application.jar extract
To answer my own question, it was happening because of the Spring Boot version which was not ready to handle multistage builds, but after upgrading the service to 2.3.x i can build.
I think it is because of the Jar file not in supported form.
That's why jarmode can't process it.
Jarmode is a special system used to extracting Layered Jars.
You can check out: https://spring.io/blog/2020/01/27/creating-docker-images-with-spring-boot-2-3-0-m1 for detail info.

How to natively build a servlet based Quarkus application using a web.xml as the deployment descriptor?

I'm setting up a simple servlet application using Quarkus. Where should I place the web.xml file and how should I deploy the application using the native build feature of Quarkus?
I have tried placing web.xml in project-name/src/main/resources/WEB-INF folder and natively built it using GraalVM docker image, but the built is not working. Dockerfile I used for the build is as of below.
Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/centos-quarkus-maven:19.1.1 AS build
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
USER root
RUN chown -R quarkus /usr/src/app
USER quarkus
RUN mvn -f /usr/src/app/pom.xml -Pnative clean package
Stage 2 : create the docker final image
FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY --from=build /usr/src/app/target/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
I expected the output to be "Welcome", but the actual output is "Not Found".
You can place web.xml file in the project-name/src/main/resources/META-INF directory to get it working.

Dockerfile that is used for building spring-cloud-dataflow-server image

I have downloaded the Spring cloud Dataflow server code from GitHub at https://github.com/spring-cloud/spring-cloud-dataflow. I am trying to understand how the docker image is build for this server. But I am unable to find dockerfile in this codebase.
Reference documentation section "Adding a Custom JDBC Driver" calls for modifying Pom.xml and rebuild with very little information. I need to use a custom jar and rebuild the image.
Already looked into this post https://github.com/spring-cloud/spring-cloud-dataflow/issues/2489 but I am trying to understand how the orginal image for Spring Dataflow server is built.
The Maven configuration to build the Spring Cloud Data Flow server is here
To build the docker image, you can run the following from your cloned repo (assuming you are on the latest):
./mvnw clean install -DskipTests
./mvnw docker:build -pl spring-cloud-dataflow-server
Thanks Gopinathan. I have used the below dockerfile instead of changing the POM.xml and rebuilding the docker image.
FROM mcr.microsoft.com/java/jdk:8u212-zulu-alpine as build
RUN apk add --update \
curl \
&& rm -rf /var/cache/apk/*
WORKDIR /workspace/app
RUN mkdir target
RUN curl -sS -o /workspace/app/target/spring-cloud-dataflow-server-2.1.2.RELEASE.jar https://repo.spring.io/release/org/springframework/cloud/spring-cloud-dataflow-server/2.1.2.RELEASE/spring-cloud-dataflow-server-2.1.2.RELEASE.jar
RUN curl -sS -o /workspace/app/target/mysql-connector-java-8.0.16.jar https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.16/mysql-connector-java-8.0.16.jar
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../spring-cloud-dataflow-server-2.1.2.RELEASE.jar)
RUN cp /workspace/app/target/mysql-connector-java-8.0.16.jar /workspace/app/target/dependency/BOOT-INF/lib/
FROM mcr.microsoft.com/java/jdk:8u212-zulu-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
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
RUN echo "$(ls -lR /app)"
ENTRYPOINT ["java","-cp","app:app/lib/*","org.springframework.cloud.dataflow.server.single.DataFlowServerApplication"]
dockerfile-from-image would help to reverse engineer from docker image.
Upvoted Ilyaperumal Gopinathan's answer, the best way is to build the project. The fabric8 maven docker plugin requires docker to be installed locally however - surely a lot of work to get to the 4 lines below.
This is the image produced by the 2.7.1 build -
FROM springcloud/baseimage:1.0.0
ENV LANG=C.UTF-8
COPY maven /
VOLUME ["/tmp"]
ENTRYPOINT ["java","-jar","/maven/spring-cloud-dataflow-server.jar"]
The spring cloud base image seems to be simply an Ubuntu base with Java 8 installed (https://github.com/spring-cloud/baseimage)?

Resources