Install maven/java packages inside docker image without starting springboot - java

I have the following Dockerfile:
FROM maven:3.3.9
COPY . /code
WORKDIR /code
RUN ["mvn", "install"]
CMD mvn spring-boot:run
Which crashes on line 4 (mvn install), because all packages are installed, but at the end Spring starts and attempts to connect to the database container (it is not running, because for now I'm only building the images).
Is there a way I can just install maven packages, without getting spring up and running? I want to avoid downloading a lot of things every time I start my backend service.

Do mvn install -DskipTests. It will skip everything and just download packages

CMD mvn spring-boot:run will cause application to start. Just replace it with a CMD sh -c or something that fits your need.
The main purpose of a CMD is to provide defaults for an executing
container. These defaults can include an executable, or they can omit
the executable, in which case you must specify an ENTRYPOINT
instruction as well.
https://docs.docker.com/engine/reference/builder/

Related

How to build spring boot app in Intellij IDEA in a docker image within the IDE?

I need to replicate the build in our CI/CD tool in the dev workstations of the developers by making Intellij IDEA build within a docker container instead of the current system. Is this doable? I find similar threads with launching the app inside (that i don't need), i need it only as a build environment. I already have the Docker plugin installed but i fail to see how to make it as a build environment.
I have installed the docker plugin, prepared the image. I have docker installed on the workstation.
You are expecting something like this?
FROM eclipse-temurin:17-jdk-alpine as build
WORKDIR /workspace/app
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src
RUN ./mvnw package -DskipTests
FROM eclipse-temurin:17-jdk-alpine
ARG JAR_FILE=target/*.jar
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build /workspace/app/${JAR_FILE} /app/
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar ${0} ${#}"]
You can use the maven container as a build container to save maven installation time in case it takes.

Docker image does not rebuild after code change

I am playing around with a docker project that builds and starts with
docker run -p 8888:8888 -v /$(pwd)/example/proto:/proto <image-name>
Inside it is a gradle based java application, about which I would like to get to know somewhat more, so I started to modify its source, adding some logs etc.
I tried to rebuild and rerun the docker image the above way but the results of my modifications don't seem to visible, the logs aren't printed etc.
I removed the image with docker rmi, but after every rebuild it seems to be the same image is being created. docker images always shows it is created 3 weeks ago and the image id is always the same
Checking on the application level the build directory contains the newly compiled java classes, so apparently on that level my changes are in effect, but it seems docker still uses the old code
Any help would be appreciated
Updated: Dockerfile
FROM gradle:7.0.0-jdk11 as cache
RUN mkdir -p /home/gradle/cache_home
RUN mkdir -p /proto
RUN touch /proto/any.proto
ENV GRADLE_USER_HOME /home/gradle/cache_home
COPY build.gradle /home/gradle/java-code/
COPY gradle.properties /home/gradle/java-code/
WORKDIR /home/gradle/java-code
RUN gradle build -i --no-daemon || return 0
FROM gradle:7.0.0-jdk11 as runner
COPY --from=cache /home/gradle/cache_home /home/gradle/.gradle
COPY . /usr/src/java-code/
WORKDIR /usr/src/java-code
EXPOSE 8888
ENTRYPOINT ["gradle", "bootRun", "-i"]
A docker build will send your local changes to your local docker deamon to be built into an image.
cd projectWithDockerfile
docker build -f ./Dockerfile -t me/gradlethingy .
docker run -p 8888:8888 -v /$(pwd)/example/proto:/proto me/gradlethingy
Without the build I'm guessing you are pulling in their <image-name> from the net each time.

The most correct way to run MyBatis migration from a Docker container

I'm trying to figure out how and when to run the mybatis schema migrations from a Docker container deployed inside a Docker Swarm. I mean: I need the most correct way to do that.
At the moment We build a Docker container from a Dockerfile
FROM ubuntu:18.04
RUN apt-get update && apt-get install -y \
openjdk-11-jre \
openjdk-11-jdk \
maven
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
COPY start.sh start.sh
RUN chmod +x start.sh
ENTRYPOINT ["/bin/sh","start.sh"]
then the start.sh script contains
mvn resources:resources migration:up -Dmigration.path="target/classes/migrations" -Dmigration.env=development -Papply_migrations
java -jar /app.jar
But in this way we have to build an image from Ubuntu, install Maven and lunch the migrations with the environment "hardcoded" into the start.sh file, so We need different files from different envs.
What do you think is the most correct method to run these scheme migrations during the build/deployment process?
Thanks in advance.
EDIT:
I've found useful the solution to use the mybatis migration docker image found on DockerHub and posted by #h3adache but still to have an Issue trying to execute it on a DockerSwarm: the issue is related to the volume mounted between the host folder with mybatis migrations files and the container folder "/migration"
-v $PWD:/migration
My docker-compose.yml is
mybatis-migration:
image: mybatis/migrations
volumes:
- ./mybatis-migrations:/migration
command:
- up
It works fine locally against a dockerized MySQL but fails during the deploy with a GitLab pipeline.
The ./mybatis-migrations folder is, obviously, on my localhost when I checkout the code and It is in the build path of the GitLab repository when the GitLab runner builds everything but is not on the DockerSwarm host so it's unable to find that directory.
This is the error message:
invalid mount config for type "bind": bind source path does not exist
How can I fix this?
Let's look to the problem with maven first. I understand that you (quite rightfully) don't want to install maven (and probably JDK).
There are two ways to achieve what you need.
Runtime Schema Upgrade
You can run migration right from your application when it starts. It may be run from the main method or from the custom javax.servlet.ServletContextListener if you deploy a web application.
Here's how it may look like:
new UpOperation().operate(
new DataSourceConnectionProvider(dataSource),
new JavaMigrationLoader("mycompany.migration.script"), null, null);
Check the documentation with details how to configure this.
This would require to only include mybatis migration to the dependencies of your project (which you might already have).
Using mybatis migrations library directly
The other way is to run mybaits migration directly that is without maven. This can be done by installing the library inside docker as described in the documentation. Note that you only need the libraryr itself and JRE, so no JDK and maven is required.
Then you can run migration using migrate script that is part of the distribution archive.
Environment
In order to fix this you can pass that as a parameter to the docker container that runs start.sh. One option is to use environment variable via --env option for docker service create or docker run. The variable passed this way can be accessed as a regular environment variable in linux in your start.sh.
I suggest you follow the guide I posted on medium which uses the official Mybatis Migrations docker hub image
It gives you an 'out of the box' docker experience and allows you to target different environments (as mentioned in my post).
tl;dr
Use https://hub.docker.com/r/mybatis/migrations for your base image.
This gives you migration commands out of the box
Instead of using the .gitlab-ci.yml from the post, you can add the action (eg. migrate up) as your docker image entrypoint or command.
You can control env or directly affect parameters used by using docker --env
eg.
docker run \
--rm \
--env "MIGRATIONS_URL=jdbc:mysql://$(hostname):3306/mb_migration" \
-v $PWD:/migration \
-it mybatis/migrations status

Docker files and build command

I tried to create a container using dockerfile, but I'm not successful.
For loading the application on the docker what files do I need? And what is the build command?
Docker is a relative new technology and it's quite hard to find suitable documentation for your problem, first of all you will need docker-compose.yaml and Dockerfile, wich are the configuration files. Next you need to access the folder where's your project, and run "docker-compose up --build", for building the project, then "docker-compose down" to stop and "docker-compose up" to start again.
Tanta.
So, basically you'd need the docker installed in your machine, and a Dockerfile in your project.
I would indicate this step-by-step for your first example of a docker container:
Enter a folder that you can start a new project
Execute these command (You will ned git (click here to download it) installed):
git clone -b v1 https://github.com/docker-training/node-bulletin-board
cd node-bulletin-board/bulletin-board-app
Create a Dockerfile in the current folder
Paste this following piece of code in your new Dockerfile:
FROM node:6.11.5
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . .
CMD [ "npm", "start" ]
Now you can build and run your all-new container:
docker image build -t bulletinboard:1.0 .
docker container run --publish 8000:8080 --detach --name bb bulletinboard:1.0
So, with these steps, I think you can start to understand how Docker works and how you can introduce this stack in your currently running application.
Please, also check docker-compose docs for reference, it will help you.
Thank you.

UnsupportedOperationException: No format processor for org.jboss...MavenResolvedArtifact was found

I'm creating an application to automatically generate resources for a launcher, this requires automatically resolving maven dependencies, but I'm getting an UnsupportedOperationException while running JBoss Shrinkwrap Resolver
I'm running this inside a docker container, to avoid the local repository caching, it works outside of the container on the host, but I'm unsure what is missing inside the container.
My resolver config is a simple example, converting to a MavenResolvedArtifact
MavenResolvedArtifact[] artifacts = Maven.configureResolver()
.withMavenCentralRepo(true)
.withRemoteRepo("internal-nexus", MAVEN_URL, "default")
.resolve("com.company:application:" + PROJECT_VERSION)
.withTransitivity()
.asResolvedArtifact();
My Dockerfile is also relatively simple, using openjdk9, including the bootstrapper program, a shell script and some environment variables.
FROM openjdk:9
COPY bootstrapper-shaded.jar /bootstrapper.jar
COPY docker-run.sh /run.sh
ENV CLONE_URL https://github.com/company/repository.git
ENV NEXUS_BASE https://nexus.company.com/
ENV NEXUS_REPO repository
RUN chmod +x /run.sh
RUN apt-get update && apt-get install -y git software-properties-common maven
ENTRYPOINT ["/run.sh"]
And the run.sh script copies some files (removed for brevity), runs the build, then the bootstrapper
#!/bin/sh
rm -rf /boostrap/*
cd /bootstrap/
git clone $CLONE_URL work
cd work
chmod +x ./gradlew
./gradlew clean build
NEXUS_URL=`printf $NEXUS_BASE; printf "/repository/"; printf $NEXUS_REPO` ./gradlew upload
java -jar /bootstrapper.jar 0
I expect the output to be the same as on the host machine, an array of MavenResolvedArtifacts, however the following exception is thrown on the final line of the code snippet, .asResolvedArtifact()
Exception in thread "main" java.lang.UnsupportedOperationException: No format processor for org.jboss.shrinkwrap.resolver.api.maven.MavenResolvedArtifact was found. Supported processors are: class org.jboss.shrinkwrap.resolver.impl.maven.archive.ArchiveFormatProcessor
at org.jboss.shrinkwrap.resolver.spi.format.FormatProcessors.find(FormatProcessors.java:53)
at org.jboss.shrinkwrap.resolver.impl.maven.MavenFormatStageImpl.as(MavenFormatStageImpl.java:84)
at org.jboss.shrinkwrap.resolver.impl.maven.MavenFormatStageImpl.asResolvedArtifact(MavenFormatStageImpl.java:71)
at org.jboss.shrinkwrap.resolver.impl.maven.MavenFormatStageImpl.asResolvedArtifact(MavenFormatStageImpl.java:40)
at com.company.ResolveTask.run(ResolveTask.java:39)
at com.company.Bootstrapper.main(Bootstrapper.java:102)
Apologies for any typos in the stacktrace, VM wouldn't let me copy-paste out of it so I had to type it out myself.
Update: Haven't found anything else on google yet, have tried clean builds to no avail.
You need to change the type of artifacts to
org.jboss.shrinkwrap.resolver.impl.maven.archive.ArchiveFormatProcessor
or at least cast it to that when you declare.

Categories