Installing and using Gradle in a docker image/container - java

I am getting this strange error at the end of the process of creating a docker image from a Dockerfile:
/bin/sh: 1: gradle: not found
INFO[0003] The command [/bin/sh -c gradle test jar] returned a non-zero code: 127
The relevant part of the Dockerfile:
FROM debian:jessie
[...]
RUN curl -L https://services.gradle.org/distributions/gradle-2.4-bin.zip -o gradle-2.4-bin.zip
RUN apt-get install -y unzip
RUN unzip gradle-2.4-bin.zip
RUN echo 'export GRADLE_HOME=/app/gradle-2.4' >> $HOME/.bashrc
RUN echo 'export PATH=$PATH:$GRADLE_HOME/bin' >> $HOME/.bashrc
RUN /bin/bash -c "source $HOME/.bashrc"
RUN gradle test jar
[...]
The command I am using is: docker build -t java_i .
The strange thing is that if:
I run a container from the previous image commenting out RUN gradle test jar (command: docker run -d -p 9093:8080 -p 9094:8081 --name java_c -i -t java_i),
then I log into that container (command: docker exec -it java_c bash),
then I manually check the gradle environment variables finding them,
then I manually run that commented out command from within the running container (gradle test jar):
I eventually get the expected output (the compiled java code in the build folder).
I am using Docker version 1.6.2

I solved the problem using the ENV docker instructions (link to the documentation).
ENV GRADLE_HOME=/app/gradle-2.4
ENV PATH=$PATH:$GRADLE_HOME/bin

This command /bin/bash -c "source $HOME/.bashrc" means that you create a new non-interactive process and run a command in it to set environment variables there. Which does not affect the parent process. As soon as variables are set, process exits. You can check this by running something like this:
RUN /bin/bash -c "source $HOME/.bashrc; env"
RUN env
What should be working is this option:
RUN source ~/.bashrc
And the reason why it works when you log in, is because the new process reads already updated ~/.bashrc.

I was trying to install same version with JDK 11.0.7 but gradle-2.4 does not work. and got below error
FAILURE: Build failed with an exception.
* What went wrong:
Could not determine java version from '11.0.7'.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
I install later version to fix the above issue after installation.
Posting as an answer might help someone else.
FROM openjdk:11.0.7-jdk
RUN apt-get update && apt-get install -y unzip
WORKDIR /gradle
RUN curl -L https://services.gradle.org/distributions/gradle-6.5.1-bin.zip -o gradle-6.5.1-bin.zip
RUN unzip gradle-6.5.1-bin.zip
ENV GRADLE_HOME=/gradle/gradle-6.5.1
ENV PATH=$PATH:$GRADLE_HOME/bin
RUN gradle --version

You can use multi-stage builds and the Gradle Docker image (no need to install Gradle...) to build the application then use the result in the runtime container:
# Build
FROM gradle AS build
WORKDIR /appbuild
COPY . /appbuild
RUN gradle --version
# here goes your build code
Once the Gradle build is done, switch to the runtime container:
# Runtime
FROM openjdk:8-jre-alpine
# more stuff here...
COPY --from=0 appbuild/<somepath>/some.jar application.jar
# more stuff here...
The COPY command copies the build artifacts from the build phase to the runtime container (in this case a jar file).

Related

Install rust on openjdk docker image

I'm trying to write a dockerfile to run a rust test suite that requires a jar to be running on a separate port. I've downloaded the jar into the project and would like to start with the openjdk docker image and download rust as well. That way I can use the java command to run the jar then cargo to run the tests.
# Start with java
FROM openjdk:latest
# Add rust
RUN <one line command to download rust>
# Install production dependencies and build a release artifact.
RUN cargo build --release
# Start chromedriver, geckodriver, and selenium standalone binary
RUN ./thirtyfour/tests/binaries_and_jars/chromedriver
RUN ./thirtyfour/tests/binaries_and_jars/geckodriver
RUN java -jar ./thirtyfour/tests/binaries_and_jars/selenium.jar standalone --port 1234
# Run the tests
RUN cargo test
I was hoping to download rust using the curl command provided on the website, passing all the options as cli arguments, but I still get the prompt. Running
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable --default-host x86_64-unknown-linux-gnu --profile default
still produces the confirmation prompt.
I'm open to any solution here, including
A one-line command to install rust
Starting from the rust image + a one-line command to install java.
You can skip the confirmation prompt by adding the -y argument. This can be found in the help page of installer script.
The installer for rustup
USAGE:
rustup-init [FLAGS] [OPTIONS]
FLAGS:
-v, --verbose Enable verbose output
-q, --quiet Disable progress output
-y Disable confirmation prompt.
--no-modify-path Don't configure the PATH environment variable
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
--default-host <default-host> Choose a default host triple
--default-toolchain <default-toolchain> Choose a default toolchain to install
--default-toolchain none Do not install any toolchains
--profile [minimal|default|complete] Choose a profile
-c, --component <components>... Component name to also install
-t, --target <targets>... Target name to also install

How to set environment variables so they work in non-interactive bash shells?

I am running the amazonlinux:2 docker image directly from dockerhub and installing the corretto-17 JDK with the following command:
yum install -y git java-17-amazon-corretto-devel
Note: I am not using a custom Dockerfile, I do not control it and I can't change it.
When I then try and run my .gradlew task, it fails because there's no JAVA_HOME set.
So I do that by:
echo "export JAVA_HOME='/usr/lib/jvm/java-17-amazon-corretto.x86_64'" >> /root/.bashrc
If I manually connect a terminal to to the container, the .bashrc works fine and gradlew will run.
But when I run commands from outside the container via something like:
docker exec kopibuild /bin/bash -c "cd the-project-code && ./gradlew build"
The .bashrc is not loaded so JAVA_HOME is not set and gradlew fails.
My workaround is to add the interactive flag -i to the bash command and then it all works, but there are warnings in the logs about "cannot set terminal process group (-1): Inappropriate ioctl for device".
docker exec kopibuild /bin/bash -c "cd the-project-code && BASH_ENV=/root/.bashrc ./gradlew build"
But it didn't seem to do anything.
What's the right way to set environment variables for Amazon Linux so they will exist in non-interactive shell invocations?
After digging around on the Googles - I believe there is no standard Linux way to set an environment variable for non-interactive shells.
But there is a Docker way to answer the question. On the original docker create of the container from the amazonlinux:2 image, specify the environment variable via -e JAVA_HOME=/usr/lib/jvm/java-17-amazon-corretto.x86_64. This stores the environment variable in the docker metadata for the container and it will be available in all execution contexts, including non-interactive shells invoked directly via docker exec (without having to specify it explicitly for every exec command).
As far as I know, this is the same as what the ENV command in a Dockerfile does.

JavaFX Docker Unable to open DISPLAY

I am trying to start a Java program in a docker container. After docker-compose build i try to start the program with docker-compose up but get the following error:
Exception in thread "main" java.lang.UnsupportedOperationException: Unable to open DISPLAY
The readme of the progam says:
"If you get the error message that the container cannot connect to Xorg (Unable to open DISPLAY) when starting the container, the supplied script "./startup.sh" needs to be executed".
startup.sh:
#!/bin/sh
xhost +local:
docker-compose up
xhost -local:
dockerfile
FROM ubuntu:16.04
RUN apt-get update && apt-get install --assume-yes --no-install-recommends openjfx openjdk-8-jdk maven git
COPY . /opt/Testfolder
WORKDIR /opt/Testfolder/src
RUN mvn package -DskipTests -Dcheckstyle.skip
CMD java -jar program.jar
At what point would i need to execute the startup.sh script? Do i need to add another RUN startup.sh in the dockerfile? Anyone has an idea?

What does this docker run command do?

I have a docker run command, I am just wondering what the part -v "..":".." -w ".." maven mvn clean... is doing?
docker run --rm --name ${DOCKER_IMAGE_NAME}_build -v "$(pwd)":/usr/src/mymaven -w /usr/src/mymaven maven:3.6.0-jdk-8-alpine mvn clean install package
I think it is mapping the local volume on the OS "$(pwd)" to the docker folder inside the docker volume which is /usr/src/mymaven, then it executes the command with "w" inside the /usr/src/mymaven" folder but because of the mapping it executes inside the local $pwd directory right? so it executes the "maven:3.6.0-jdk-8-alpine mvn clean install package" part, which starts the mvn build process, but what is maven:3.6.0-jdk... I know that it is an image, but how does it know where to pull that image from and how is it possible to directly execute that command for maven thereafter for that image?
The -v part of that command binds a volume to the container you're starting. In this case -v "$(pwd)":/usr/src/mymaven
adds your current directory as /usr/src/mymaven to the container.
the -w part of the command sets your working dir within the container to /usr/src/mymaven
and the part after that actually
maven:3.6.0-jdk-8-alpine -> this is the container you're starting
mvn clean install package -> this is the command you're starting inside the container (so in the /usr/src/mymaven working directory)
basically this run command starts up a container, runs maven and does this with your current directory where you started as source to run in.
for more info about the arguments: docker doc on run arguments

When building a Maven project in Docker, all target files are rooted

I have a Maven project which I want to build in a Docker container, so that I don't have to install Java, Maven, ... on my Jenkins system.
I build the Maven project as following:
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock:ro
-v $(pwd):/opt/maven
-w /opt/maven
maven
mvn clean install
This works great, the build is correctly made. However, when doing this as my regular user, all files in the target/ directory are owned by root and no by jester, which is my current user.
Is there an easy way to fix this?
You chan check out the option -u, as in this gist, which wraps docker run in a script:
#!/bin/sh
set -e
test ":$DEBUG" != :true || set -x
# set image
set -- debian:jessie "$#"
# use current user and its groups at host
for v in /etc/group /etc/passwd; do
[ ! -r "$v" ] || set -- -v $v:$v:ro "$#"
done
set -- --user "`id -u`:`id -g`" "$#"
for g in `id -G`; do
set -- --group-add "$g" "$#"
done
set -- -v "$HOME":"$HOME" "$#"
exec docker run --rm -it "$#"
The goal is to make sure the container mounts the local user definition, and uses the same uid/gid.

Categories