I am learning docker to work with my spring boot application. I am not able to load Snapshot versions of dependent project.
I have two projects, Project A and Project B.
this is my docker-compose file
version: '2.1'
services:
projectA:
build:
context: ./projectA
dockerfile: Dockerfile
restart: always
working_dir: /app
command: mvn clean install
projectB:
build:
context: ./projectB
dockerfile: Dockerfile
restart: always
working_dir: /app
command: mvn clean spring-boot:run
This generates the Snapshot Jar projectA-1.1.0-SNAPSHOT.jar
I want to use this jar in projectB ( Spring Boot Application)
How can I point yo This local jar in POM.xml
My POM Should have
<dependency>
<groupId>com.project.test</groupId>
<artifactId>projectA</artifactId>
<version>1.1.0-SNAPSHOT</version>
</dependency>
I am getting errors while loading projectB due to changes in SNAPSHOT version.
Thanks,
this is the output when I do docker-compose up --build
[ERROR] COMPILATION ERROR :
[INFO] ----------------------------
[ERROR].../com/project/test/api/assembler/UserMapper.java:
[57,54] cannot find symbol
symbol: method getLastSessionTimestamp()
location: variable user of type com.project.test.domain.User
lastSessionTimestamp is added in local SNAPSHOT Jar.
The reason why your example can't work is that you have a misconception of what docker (compose) is and how it works. It is not a package manager for your java libraries but a tool to wrap entire applications together.
So in detail what you configured is the following: projectA builds a docker container using your Dockerfile builds projectA java libraries and finally installs the packaged jarfile into the docker container local filesystems maven folders. Additionally in parallel you are trying to start projectB. That means you have two problems:
the running containers don't know about each other as they are not sharing anything, but even if you would solve this problem, e.g. by sharing a volume amongst them you still have problem
compose doesn't imply an order and executes multiple containers in parallel. So you might run into situations where it might work and on the next run will not work again as B is executed before A is done.
To solve this you have a couple of options of which I would suggest to do the following:
- Build A and B outside of containers on your machine using a multi module pom file that orchestrates the build and only add the final jar to a docker image that you can ship. If that works you can also execute the build in a container.
But to simply try out that both your builds work you can create a volume and mount it in both containers into the maven folder which is /root/.m2 assuming you didn't changed the default user.
But I strongly suggest you also have a read on how docker treats multistage builds and how it handles volumes here:
Docker volumes
Multi-Stage Builds
Related
I have several Spring Boot microservices in one parent and I can run spring-boot:build-image to build docker images for all modules. I'm using my Windows WSL2 Ubuntu x86_64 and Docker Engine to build the images through the configuration in IntelliJ.
I'ts all fine and dandy on my Windows machine and I can start the containers successfull, but I want my images to run in containers on my Raspberry Pi Ubuntu Server 21.04 for architecture ARM64 and pull them through my Windows Docker Registry so I can easily transfer images locally. My registry works as well, but then I'm stuck with the error that the image cannot be started due to architecture problems.
How can I change the architecture of the docker image build in the IntelliJ Maven configuration run?
I've found the spring-boot configuration through Maven very convenient, it does all sorts of configuration for building the image. I don't know how to use docker-compose.yml or a Dockerfile to successfull build an image. If this is the answer I will focus my research on this, but up until now I'm quite stuck what to do.
My feeling goes towards the pom.xml and define any configuration there. My pom.xml looks like this right now:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Question edit:
I have seen you can use the parameter --platform=linux/arm64. Can I put this somewhere?
I have found the answer to be one of the things I could not get running yet, until now - using a Dockerfile.
In IntelliJ I connect to my Docker remote Raspberry Pi instance on my local network through Services
I create a simple Dockerfile
FROM openjdk:11
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
I choose Deploy on the Docker instance in IntelliJ and select the Dockerfile
It now builds and deploys my application on my Raspberry Pi without any local Windows services coming inbetween
Successfully build and deployed a Docker image and container through the Dockerfile running Deploy with IntelliJ! I'm so happy
The solution to your problem isn't at the Maven build step but rather the Docker build step (which happens after you do a Maven build).
I was able to use Maven spring-boot:build-image followed by this Docker command to build an image for ARM arch:
docker buildx build --platform linux/arm/v7 --tag <username>/<image name>:<tag> .
Adding a --push flag will automatically push the image to your registry when it's built.
I will try to keep the description brief. We have a couple of projects. Some of them are full blown Spring Boot apps, some of them are Maven Dependency projects (used in those Spring Boot apps).
I have set up a Jenkins server for automating pipelines. Jenkins calls Google Cloud Build to build projects/docker images and cache dependencies. It also calls SonarQube in a step. This all works fine for the Spring Boot apps, but the SonarQube step fails for the dependency projects. The error is Failed to execute goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar (default-cli) on project projectname: Not inside a Git work tree: / -> [Help 1].
The Dockerfile for the project:
FROM maven:3.5-jdk-8-alpine
# Copy local code to the container image.
COPY pom.xml settings.xml ./
RUN mvn -s settings.xml dependency:go-offline
COPY src ./src
# Build a release artifact.
RUN mvn verify -DskipTests -s settings.xml
The cloudbuild.yaml:
substitutions:
_IMAGE_NAME: "projectname"
steps:
- name: "docker"
entrypoint: "sh"
args:
- "-c"
- |-
docker pull gcr.io/gcp-project/${_IMAGE_NAME}:$_TAG
docker pull gcr.io/gcp-project/${_IMAGE_NAME}:latest || true
- name: "docker"
args:
- "build"
- "-t"
- "gcr.io/gcp-project/${_IMAGE_NAME}"
- "-t"
- "gcr.io/gcp-project/${_IMAGE_NAME}:$_TAG"
- "--cache-from"
- "gcr.io/gcp-project/${_IMAGE_NAME}:latest"
- "--cache-from"
- "gcr.io/gcp-project/${_IMAGE_NAME}:$_TAG"
- "."
- name: "gcr.io/gcp-project/${_IMAGE_NAME}"
entrypoint: "bash"
args:
- "-ce"
- |-
mvn -f /pom.xml -s ./settings.xml sonar:sonar -Dsonar.host.url=https://sonar.server.com -Dsonar.login=${_SONAR_KEY}
- name: "gcr.io/gcp-project/${_IMAGE_NAME}"
args:
- "mvn"
- "deploy"
- "-s"
- "/settings.xml"
images: ["gcr.io/gcp-project/${_IMAGE_NAME}"]
There are two very confusing things. If i run the maven command locally, the analysis completes successfully. Also, if i run the local Google Cloud Build tool (cloud-build-local) it also passes.
I have verified that the .git folder is not uploaded. It is neither with the Spring Boot apps.
I copied the settings.xml from the Jenkins server locally and used that one. Neither the Spring Boot apps or the dependencies define a sonar-project.properties.
Is there anyone who can shed some light on this?
Thanks in advance!
EDIT
I created 2 repositories that are able to replicate this problem:
Non-working: https://github.com/claystation/mvnsonarapp
Working: https://github.com/claystation/mvnsonarappworking
I think the main difference is the dependency project not having #SpringBootApplication?
Ok, so i finally figured it out how to solve this, by doing the MCVE.. Unfortunately not WHY the problem exists.
The main difference between the projects was the #SpringBootApplication annotation. I thought this might have something to do with having the spring-boot-starter-parent parent defined.
I removed the parent part and now my project is passing in Sonar. If there is ever someone who can explain WHY Sonar gives this error with the parent defined but no #SpringBootApplication annotation, that would be very helpful.
Thanks!
I have two maven spring boot applications and I was set up two docker file for that.
Inside each container, I am performing the maven install.
The two containers are performing a lot of download for the dependencies and finally packing the application.
Since these two containers are built sequentially, Can I share the maven's local repository of the first container to the second container, so that the second container's maven install will skip the locally available dependency and only fetch extra libraries mentioned in its pom?
Yes, you can.
We do something similar so that our builds are always clean. But to save time on the maven download, we use a docker volume mounted to the m2 directory so that the downloads can be used between builds & docker containers.
docker run -v m2Repository:/root/.m2 some-image
docker run -v m2Repository:/root/.m2 some-other-image
First run takes a while, but the following builds are much faster.
You did not mention, which environment you are running builds on, so I would like to share my solution for Bitbucket Pipelines CI.
We build our ~20 containers in Bitbucket Pipelines CI and every container is Java application with almost same set of dependencies. Bitbucket Pipelines CI uses Docker images for running builds (yes, they are using Docker images to build Docker images). There is an option to specify which Docker image to use for builds.
To avoid downloading all dependencies over and over again and reduce build time, I built custom Docker image which contains all external dependencies of all our modules. All dependencies were gathered using Maven's command in each module:
mvn -Dmaven.repo.local=c:/projects/bitbucket-pipelines-baseimage/local-maven-repo clean install
After that I removed project's artifacts from temp repository "c:/projects/bitbucket-pipelines-baseimage/local-maven-repo" and built Docker image, which includes that temp repository. That image was deployed to Docker Hub and now all our build in Bitbucket Pipelines are using it. Build times were reduced drastically!
I need to understand how to deal with common libraries that i have created which my Application depends upon. When i create jar for this app using maven it creates a package. But how do we maintain or configure other common libraries which are listed in pom.xml of this application?
should we have maven also as an image in the docker file?
Please explain in detail.
My current progress is explained below: I have an Application A which has other dependencies like B and C libraries which i have specified in pom.xml. When i run application A in my local system it uses local repository that i have configured in user settings for maven. SO it works fine.
So how do we maintain this in kubenetes.
The images that you use to build the containers that run on Kubernetes should contain everything that's needed to run the application.
When you create the JAR file for your application, this JAR should contain the dependencies. There are different ways to achieve this, using both Maven or Gradle. This is an example using Maven and its Apache Maven Assembly Plugin. This is another good user guide on how to achieve it.
Then, you need to create a container image that can run that JAR file, something like
FROM openjdk:8-jdk-alpine
EXPOSE 8080
WORKDIR /opt/app
CMD ["java", "-jar", "app.jar"]
COPY build/libs/app.jar /opt/app
Once this container image is published on a registry, whenever Kubernetes needs to schedule and create a container, it will just use that image: there is no need to re-compile the application and its dependencies.
Making an image for maven project should be straightforward, as maven know how to build (and can know how to run)
How to build docker image and run it with maven?
Let's say the app also needs MongoDB, that I can run as docker run -p 27017:27017 mongo. Is it possible also to specify with some maven plugin?
The maven plugin created by fabric8 allows you to do this:
the plugin and its documentation is available on github: https://github.com/fabric8io/docker-maven-plugin
The samples include for example https://github.com/fabric8io/docker-maven-plugin/blob/master/samples/data-jolokia-demo/pom.xml (which seems to be similar to what you plan).
An alternative could be using Docker-compose and some scripts outside maven, once the images are created.