I have a java project that I am hosting on GitHub. I also have a Docker file that creates an image based off of the generated war files after a build (using Maven).
What I want is for a new Docker image to be generated every time I push new code to the repo. What I am getting confused with is how will Docker build the source and add the generated .war files to the base Tomcat Docker file? Or am I thinking about this wrong?
Alternatively is there a way for Travis CI to generate the war and then push it to a docker image?
So to fix this, I had Travis CI pull data from the repo and after the build have the docker file pull the artifacts from the target directory and push the built docker image to docker hub.
.travis.yml
language: java
sudo: true
services:
- docker
cache:
directories:
- $HOME/.m2
jdk:
- oraclejdk8
os:
- linux
branches:
only:
- master
after_success:
- docker login -e="$DOCKER_EMAIL" -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
- docker build -t blah/blah .
- docker push blah/blah
Dockerfile:
# Pull base image
From tomcat:8-jre8
# Maintainer
MAINTAINER "Joel"
# Copy to images tomcat path
COPY target/blah*.war /usr/local/tomcat/webapps/sacred-text-api.war
Related
How to deploy SpringBoot Java Maven Web Application to Cloud Run?
I have tried with the following link https://cloud.google.com/run/docs/quickstarts/build-and-deploy/java
But in the above tutorials, they specifed about jar file.
Jave 8, SpringBoot 2.3.0.RELEASE versions are using in this project.
We can successfully deploy springboot application to cloud run using the same tutorial. https://cloud.google.com/run/docs/quickstarts/build-and-deploy/java
Dockerfile configuration for war packages
# Use the official maven/Java 8 image to create a build artifact.
# https://hub.docker.com/_/maven
FROM maven:3.8-jdk-11 as builder
# Copy local code to the container image.
WORKDIR /app
COPY pom.xml .
COPY src ./src
# Build a release artifact.
RUN mvn package -DskipTests
# Use AdoptOpenJDK for base image.
# It's important to use OpenJDK 8u191 or above that has container support enabled.
# https://hub.docker.com/r/adoptopenjdk/openjdk8
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM adoptopenjdk/openjdk11:alpine-slim
# Copy the jar to the production image from the builder stage.
COPY --from=builder /app/target/helloworld-*.war/helloworld.war
# Run the web service on container startup.
CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/helloworld.war"]
I had done it!!!.
Note: No need to change the package name from war to jar.
I use docker-compose to launch different Spring Boot apps.
My docker images are defined with this kind of Dockerfile:
FROM openjdk:8-jdk-alpine
ADD app.jar app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"]
However, I would like to benefit from debugging and hot-reload features using something like mvn spring-boot:run without being dependent of a particular IDE.
What is the best way to accomplish debugging and hot-reloading with Spring Boot in a Docker container without being dependent of a particular IDE?
Notes:
my source files are build into a jar (with Maven) which is copied to a different location containing the definition of my Docker images ; meaning my sources files are not in the docker image.
the reason I want to develop in the Docker container is that my apps depend on each other, and are configured in the docker-compose environment, so I cannot easily run one app alone outside the docker network and environment.
I thought of mounting a volume containing my spring boot projects in the docker containers, and then use mvn spring-boot:run in the container ; but I can't prevent maven to download all dependencies from the internet (I tried specifying a local repository containing all my dependencies without success). I would like to know if this a decent solution and how to make it work.
You have to follow the following steps to build and run spring boot application in docker.
Step-1 : Create a File called Dockerfile in your Project.
Step-2 : Write the Following Code on you Dockerfile
# Use the official maven/Java 8 image to create a build artifact.
# https://hub.docker.com/_/maven
FROM maven:3.6-jdk-11 as builder
# Copy local code to the container image.
WORKDIR /app
COPY pom.xml .
COPY src ./src
# Build a release artifact.
RUN mvn package -DskipTests
# Use AdoptOpenJDK for base image.
# It's important to use OpenJDK 8u191 or above that has container support enabled.
# https://hub.docker.com/r/adoptopenjdk/openjdk8
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM adoptopenjdk/openjdk11:alpine-slim
# Copy the jar to the production image from the builder stage.
COPY --from=builder /app/target/your-app-name*.jar /your-app-name.jar
# Run the web service on container startup.
CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/your-app-name.jar"]
Step-3 : Start Your Docker Desktop Application
Step-4 : Open Your Terminal or Windows PowerShell. Then go to Project Directory.
Step-6 : Write the Following Command to create image for your application (You must have internet connection to download all dependencies).
docker build -f Dockerfile -t your-app-name .
Step-7 : After image creation success. Write the following code to run the image in Docker container.
docker run -p docker-port:app-port image-name
Following your line of thinking you can try to copy your dependencies from a volume into the project container and then use the offline mode in something like this:
FROM openjdk:8-jdk-alpine
WORKDIR /app
# copy the Project Object Model file
COPY ./pom.xml ./pom.xml
# copy your dependencies
COPY app.jar app.jar
# copy your other files
COPY ./src ./src
# Set fetch mode to offline to avoid downloading them from the internet
RUN mvn dependency:go-offline
Apparently it's also possible to configure the offline mode globally by setting the offline property in the ~/.m2/settings.xml file, you can setup that and copy your m2 file and reference it when running the container
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<offline>true</offline>
</settings>
mvn -Dmaven.repo.local=~/.m2/settings.xml ...
You can find more information here:
https://www.baeldung.com/maven-offline
Specifying Maven's local repository location as a CLI parameter
I have a microService jar and docker file at my windows dextop x folder.
I have installed docker in my windows PC.
I have the below docker.server file
FROM openjdk:8-jre
ADD target/shopfront-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8010
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
Now I want to build a docker image from this docker file, then what needs to be done.
I opened the docker terminal and paste the below command
docker build --file=Local location of Dockerfile.server
//(which is desktop x folder)\
--tag=microserviceName on my wish latest --rm=true
.
But it's not working.
As well as I get the current directory and I tried to copy the jar and the docker file in the current docker directory that is not happening.
Please guide what needs to be done.
Created basic HelloWorld microservice using Spring Boot (2.1.3), Java 8, Maven.
pom.xml has maven plugin entry like below
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.HelloWorldApplication</mainClass>
</configuration>
</plugin>
Dockerfile looks like below
FROM openjdk:8
VOLUME /tmp
ADD target/helloworld.jar helloworld.jar
EXPOSE 8081
ENTRYPOINT ["java","-jar","helloworld.jar"]
Created image on local machine using command
docker build . -t helloworld:v1
Verified by creating container out of it.
Checked in code to docker-hub account and github account.
Logged into Google cloud platform (GCP), created kubernetes cluster, created pipeline(using container builder) by configuring github url where helloworld microservice code resides. There are two options to run build (use Dockerfile or cloudbuild.yaml). I am using Dockerfile to run build.
When build is picked up to run, it fails for this line in Dockerfile
ADD target/helloworld.jar helloworld.jar
Error seen in GCP logs:
ADD failed: stat /var/lib/docker/tmp/docker-builderxxxxxx/target/helloworld.jar: no such file or directory
I tried to replace it with COPY command and still the issue is same.
Note: I tried to go with cloudbuild.yaml
Here is how my cloudbuild.yaml looks:
steps:
# Build the helloworld container image.
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'gcr.io/${PROJECT_ID}/helloworld:${TAG_NAME}'
- '.'
This didn't make any difference. Issue remains the same.
Any idea if Springboot Java application has some specific configuration for Dockerfile to be built fine in Google Cloud Platform?
UPDATE - 1
Based on comments tried below steps on local machine:
ran command mvn clean . That cleaned target folder
updated Dockerfile
FROM maven:3.5-jdk-8 AS build
COPY src .
COPY pom.xml .
RUN mvn -f pom.xml clean package
FROM openjdk:8
VOLUME /tmp
COPY --from=build target/helloworld.jar helloworld.jar
EXPOSE 8081
ENTRYPOINT ["java","-jar","helloworld.jar"]
Ran docker build . -t helloworld:v1 command and that created image.
Then run command to start container:
docker run -p 8081:8081 -n helloworld-app -d helloworld:v1
container starts and exits with error in log:
Exception in thread "main" java.lang.ClassNotFoundException: com.example.HelloWorldApplication at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
Looks like a problem with file paths.
Try the following updated Dockerfile, which explicitly sets the working directory. It also uses explicit file paths when copying the jar between images.
FROM maven:3.5-jdk-8-slim AS build
WORKDIR /home/app
COPY src /home/app/src
COPY pom.xml /home/app
RUN mvn clean package
FROM openjdk:8-jre-slim
COPY --from=build /home/app/target/helloworld-0.0.1-SNAPSHOT.jar /usr/local/lib/helloworld.jar
EXPOSE 8081
ENTRYPOINT ["java","-jar","/usr/local/lib/helloworld.jar"]
Additional Notes:
See the related answer for a full example building a spring boot app
I've based the second stage on a JRE image. Reduces the size of the output image.
I am trying to copy files from other location (in windows from D drive that is shared drive also) to my image.
But it is giving me error.
Step 5/8 : ADD ${APP_PATH}/${ARTIFACT}-${VERSION} /opt/tomcat/webapps/${ARTIFACT}-${VERSION}
ADD failed: stat /var/lib/docker/tmp/docker-builder990684261/d:/Application_Build/spring-tournament-portal-0.0.1-SNAPSHOT: no such file or directory
Scenario:
I am trying to make test,build,release phase cycle with the help of docker.
So My Multistage docker file's first version looked like this
FROM maven as build
WORKDIR /usr/local
RUN mkdir app
COPY . /usr/local/app/spring-tournament-portal/
WORKDIR /usr/local/app/spring-tournament-portal
RUN mvn -e package
FROM tomcat
ENV PORT 8080
ENV VERSION 0.0.1-SNAPSHOT
ENV ARTIFACT spring-tournament-portal
ENV JPDA_ADDRESS 8000
ENV JPDA_TRANSPORT dt_socket
COPY --from=build /usr/local/app/${ARTIFACT}/target/${ARTIFACT}-${VERSION} /usr/local/tomcat/webapps/${ARTIFACT}-${VERSION}
WORKDIR /usr/local/tomcat/bin
CMD ["catalina.sh jpda run"]
EXPOSE ${PORT}
But on every build maven fetches its dependency. So it was taking too much time.
So i made another approach. I created two docker files(One for build and other for release).
Over here the role of build docker file does is copy all source code into an image only. So that when i will create container, I could easily create volume for maven dependency to avoid redownloading:-
FROM indiver/tournament-base
RUN apt-get update && \
apt-get install -y \
-o APT::Install-Recommend=false -o APT::Install-Suggests=false \
maven
WORKDIR /usr/local
COPY . /spring-tournament-portal/
WORKDIR /spring-tournament-portal
COPY ./docker/dev/entrypoint.sh /usr/local/bin/entrypoint.sh
ENTRYPOINT ["sh", "/usr/local/bin/entrypoint.sh"]
RUN ["chmod", "+x", "/usr/local/bin/entrypoint.sh"]
Here is entrypoint.sh file
#!/bin/bash
echo "$#" Phase is executing.....
mvn clean "$#"
When i run the image after building docker file with the help of docker-compose.xml. I set volume for dependency folder.
Here is docker compose.xml
version: "2"
services:
test-service:
build:
context: ../../
dockerfile: ./docker/dev/Dockerfile
container_name: "test-service"
command: 'test'
volumes:
- .m2:/root/.m2
build-service:
build:
context: ../../
dockerfile: ./docker/dev/Dockerfile
container_name: "build-service"
command: 'package'
env_file:
- ./EnvironmentConstant.env
volumes:
- .m2:/root/.m2
database-service:
container_name: "database-service"
env_file:
- ./EnvironmentConstant.env
image: mysql
ports:
- "3306:3306"
volumes:
- ./dev-mysql:/var/lib/mysql
networks:
- app-network
networks:
app-network:
driver: bridge
So it does not need to redownload the dependency again that is in .m2 volume.
After that i need to create release image having content of build prepared by maven. But container of build service is already stopped. So i need to use docker cp command to get my prepared build.
docker cp build-service:/spring-tournament-portal/target/spring-tournament-portal-0.0.1-SNAPSHOT D:/Application_Build
Now i want build that is in Application_Build folder should be copied into my release image.
So my release docker file looks like
FROM indiver/tournament-release
ENV APP_PATH=d:/Application_Build
ENV ARTIFACT=spring-tournament-portal
ENV VERSION=0.0.1-SNAPSHOT
ADD ${APP_PATH}/${ARTIFACT}-${VERSION} /opt/tomcat/webapps/${ARTIFACT}-${VERSION}
WORKDIR /opt/tomcat/bin
ENTRYPOINT ["catalina.sh", "jpda", "run"]
EXPOSE ${PORT}
But As i have mentioned above it is giving me error
Step 5/8 : ADD ${APP_PATH}/${ARTIFACT}-${VERSION} /opt/tomcat/webapps/${ARTIFACT}-${VERSION} ADD failed: stat /var/lib/docker/tmp/docker-builder990684261/d:/Application_Build/spring-tournament-portal-0.0.1-SNAPSHOT: no such file or directory.
I tried to copy by COPY and ADD command. But nothing is working. How can i achieve this.
If It can be achieved this with the help of other relatively easy flow. It would be helpful as well.
The Dockerfile reference says:
ADD obeys the following rules:
The path must be inside the context of the build.
...
Overall your approach seems to be too complicated to me and a very non micro-services way of doing things.
I would suggest that you copy your dependencies into the binary that you are creating to create a self contained fat (uber) jar, which you can copy to the docker image, the way spring boot does.
You approach for having separate docker files for different environments is also problematic and could result in unexpected conditions in production.
So I too faced this similar problem .
You can try the below listed command and replace the Square brackets with your path:
"docker cp /[Your Source Directory] [ContainerId]:/[Destination Path]"