I'm using a docker container to build and run my java application and I want to see the test results that would usually be available from build/reports/tests/test/index.html.
Here's my Dockerfile:
FROM alpine:latest
RUN apk add gradle openjdk17
WORKDIR /home/proj
COPY . .
RUN gradle build
ENTRYPOINT [ "java", "-jar", "./app/build/libs/app.jar" ]
Here's my docker-compose.yml:
version: "3.8"
services:
app:
build: .
I typically build my container with docker-compose build and run it with docker-compose up and would like this to stay as it is.
EDIT
I've tried changing my docker-compose.yml to:
version: "3.8"
services:
app:
build: .
volumes:
- ./tests:/home/proj/app/build/reports/tests/test
But this just creates an empty directory called tests in my project's root directory. I am 100% sure the right path is /home/proj/app/build/reports/tests/test as you can see here:
I've hit this same issue. Unfortunately volumes are only availible to docker run, they aren't part of the docker build portion of the docker compose process.
I even looked into the new RUN --mount=type=bind,source=.,target=./build/reports,rw gradle build and while in the container I can see (with a RUN ls ./build/reports) the reports being generated, but that mount (even as RW) only puts files in the container as a layer and they never appear on the host machine.
There is a hacky way to recover those test results, in the docker output, just above the failure you'll see this line ---> Running in f98e14dd1ee4. This is the layer ID, with that value you can copy from the failed layer to the local machine using
$ docker cp f98e14dd1ee4:/tmp/build/reports ./
$ ls reports/
checkstyle/ jacoco/ tests/
It shouldn't be to difficult to automate this kind of recover but it feels like it would be fragile automated.
I'm very interested if anyone has a better solution to this, even with an alternative to docker. I know I can build the container with gradle but I'd rather everything happens inside the container build process to keep the build environment defined as code.
Related
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.
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
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.
I have a simple Dockerfile in my spring boot as follow. I am able to build the image successfully locally, and can push using my credentials.
But my build keeps failing on every attempt to build automatically.
FROM openjdk:8-jdk-alpine
LABEL maintainer="xxxxx#xxx.com"
VOLUME /tmp
EXPOSE 8080
ARG JAR_FILE=target/jollof.jar
ADD ${JAR_FILE} jollof.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-
jar","/jollof.jar"]
From docker hub, I got this from the log.
Building in Docker Cloud's infrastructure...
Cloning into '.'...
Warning: Permanently added the RSA host key for IP address 'xxx.xx.xxx.xxx' to
the list of known hosts.
....
....
Step 6/7 : ADD ${JAR_FILE} jollof.jar
ADD failed: stat /var/lib/docker/tmp/docker-
builder674045875/target/jollof.jar:
no such file or directory
Unlike your local environment, Docker Hub fetches then builds your project in a fresh environment, so that the file target/jollof.jar that is intended to be copied is not available in the docker context. Hence the error you observe.
So I'd suggest refactoring your Dockerfile so that mvn package or so is done in the Dockerfile itself (which is a best practice to adopt, for the sake of reproducibility). Note that this configuration will be working for Docker Hub's automated builds as well as the builds in your local environment.
For example, below is an example Dockerfile that inspired by the that of this SO answer How to convert a Spring-Boot web service into a Docker image? as well as the Dockerfile of your post:
FROM maven:3.6-jdk-8 as maven
WORKDIR /app
COPY ./pom.xml ./pom.xml
RUN mvn dependency:go-offline -B
COPY ./src ./src
# TODO: jollof-* should be replaced with the proper prefix
RUN mvn package && cp target/jollof-*.jar app.jar
# Rely on Docker's multi-stage build to get a smaller image based on JRE
FROM openjdk:8-jre-alpine
LABEL maintainer="xxxxx#xxx.com"
WORKDIR /app
COPY --from=maven /app/app.jar ./app.jar
# VOLUME /tmp # optional
EXPOSE 8080 # also optional
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar"]
I have a Dockerfile which looks like this:
FROM alpine:3.9
RUN apk add --update openjdk8
RUN mkdir /var/generator/
COPY generator.jar /var/generator
EXPOSE 8080
ENTRYPOINT [ "/bin/sh" ]
Dockerfile is inside generator/ folder. I am building it using:
docker build -t generator generator/
It builds successfully:
Successfully built 878e81f622cc
Successfully tagged generator:latest
but when I am trying to run this image with
docker run -d -p 8080:8080 generator
it dies immediately. docker logs gives no output.
What is wrong with my Dockerfile? Why is the container dying?
Try to run the JAR. Currently, it just runs sh command and exits. Make it something as below to run the JAR in foreground -
FROM alpine:3.9
RUN apk add --update openjdk8
RUN mkdir /var/generator/
COPY generator.jar /var/generator
EXPOSE 8080
ENTRYPOINT ["java","-jar","/var/generator/generator.jar"]
Beside your entrypoint is wrong (sh exits immediately) I would also recommend to start with an appropriate base image instead of starting with alpine and installing the openjdk package. Since you want to run a java application just use the JRE and not a full JDK and start the application as a foreground process.
Here's a minimal version which is also more efficient in disksize as the image will be smaller.
FROM openjdk:8-jre-alpine
COPY generator.jar /opt/generator.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/opt/generator.jar"]