How would I create docker container of Gradle application? - docker

I have a gradle spark application that needs to be used with docker to create a container. I am new to docker and I am having a hard time setting up Dockerfile.
In Dockerfile I tried executing build.gradle and running Main.java.
# Start with a base image containing Java runtime
FROM gradle:jdk10 as builder
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build
FROM openjdk:10-jre-slim
COPY ./ /tmp/
CMD ["cd tmp/src/main/java/Empowering/"]
CMD ["javac Main.java"]
EXPOSE 8080

For your runtime container, you shouldn't be using javac. Gradle is doing the build for you. So, you'll only need to worry about running what Gradle is producing. Additionally, you want to make sure that you're properly copying the stuff being built by your builder.
I don't know what type of application you are running and what you're Gradle configuration looks like so I'm going to have to make some assumptions here.
I would highly suggest that you utilize the application plugin if you're generating a web application. If that's the case the installDist will put everything you need into the build/install folder. Once that's in place, you can simply use the generated shell script for your CMD/ENTRYPOINT
For Example:
# Start with a base image containing Java runtime
FROM gradle:jdk10 as builder
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle installDist
FROM openjdk:10-jre-slim
EXPOSE 8080
COPY --from=builder /home/gradle/src/build/install/<app name>/ /app/
WORKDIR /app
CMD ["bin/<app name>"]
If you're packaging as a jar, you can just simply copy the jar generated by the build/ fat jar task in the builder then run that
# Start with a base image containing Java runtime
FROM gradle:jdk10 as builder
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build
FROM openjdk:10-jre-slim
EXPOSE 8080
COPY --from=builder /home/gradle/src/build/<jar output path>/<app name>.jar /app/
WORKDIR /app
CMD ["java -jar <app name>.jar"]

Related

Unable to load shared library 'kernel32.dll'

I'm running a dotnet webapp in my local (windows machine) and it works just fine. When I deploy the same application to an AKS container and try running it, it fails with
System.TypeInitializationException: The type initializer for 'System.Runtime.Caching.MemoryMonitor' threw an exception.
---> System.DllNotFoundException: Unable to load shared library 'kernel32.dll' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: libkernel32.dll: cannot open shared object file: No such file or directory
at Interop.Kernel32.GlobalMemoryStatusEx(MEMORYSTATUSEX& lpBuffer)
at System.Runtime.Caching.MemoryMonitor..cctor()
--- End of inner exception stack trace ---
Below is my Docker
FROM mcr.microsoft.com/dotnet/aspnet:5.0-bullseye-slim
RUN apt-get update && apt-get install -y \
curl
WORKDIR /app
EXPOSE 80
EXPOSE 443
COPY . .
ENTRYPOINT ["dotnet", "MyApp.dll"]
Let me know if anyone has solved or seen this before
It looks like you're copying in your binaries directly into the container. The tag you are using is 5.0-bullseye-slim is Linux-based. So if the binaries you're copying in were built for the Windows platform, which I'm guessing they are since it's looking for kernel32.dll, then that's not going to run in a Linux environment.
You'll either need to build your binaries so that they are targeting Linux, which can be done with dotnet build -r linux-x64 ..., or a better option would be to build your project as part of the Dockerfile.
Here's an example Dockerfile that demonstrates this:
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /source
# copy csproj and restore as distinct layers
COPY *.csproj .
RUN dotnet restore
# copy and publish app and libraries
COPY . .
RUN dotnet publish -c release -o /app --no-restore
# final stage/image
FROM mcr.microsoft.com/dotnet/runtime:6.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "dotnetapp.dll"]
(Taken from
https://github.com/dotnet/dotnet-docker/blob/0fc0e2c6af6303cfd4676f1ac8c21090d82b0072/samples/dotnetapp/Dockerfile)

Error while executing gradle command in docker file

FROM gradle:4.2.1-jdk8-alpine
WORKDIR /app
ADD --chown=gradle:gradle /app/producer /app
RUN ./gradlew build --stacktrace
Project Structure is as follows . It is a muti module project:
<code>
--springbootdocker (Root folder of project) <br>
--producer (Sub module Producer) <br>
-- Dockerfile (for Producer)<br>
--consumer (Sub module Consumer) <br>
-- Dockerfile (for Consumer)<br
</code>
This is the docker file.
While doing docker build: getting this error
failed to build: ADD failed: stat
/var/lib/docker/tmp/docker-builder561553413/app/producer: no such
file or directory
Here you have to fix a couple of things in your Dockerfile.
ADD command
ADD command requires two parameters <src> and <dest>. So, you should provide producer path from the host as src container path as dest. But in such cases recommended to use COPY command.
COPY --chown=gradle:gradle producer /app/producer
RUN ./gradlew
It should be just gradle and it's WORKDIR should be /app/producer. If not it'll fail and you'll get,
Failed to create parent directory '/app/.gradle' when creating directory
'/app/.gradle/4.2.1/fileHashes' error when running gradle command.
Because the WORKDIR /app owns by user root.
Recommend to divide RUN gradle build --stacktrace as ENTRYPOINT and CMD.
Complete Dockerfile
FROM gradle:4.2.1-jdk8-alpine
WORKDIR /app
COPY --chown=gradle:gradle producer /app/producer
WORKDIR /app/producer
ENTRYPOINT ["gradle"]
CMD ["build", "--stacktrace"]
The partial output of docker build
Starting a Gradle Daemon (subsequent builds will be faster)
:buildEnvironment
------------------------------------------------------------
Root project
------------------------------------------------------------
classpath
No dependencies
BUILD SUCCESSFUL in 5s
1 actionable task: 1 executed
This is the dockerfile which is currently working without any error.
FROM gradle:4.10.0-jdk8-alpine AS build
COPY --chown=gradle:gradle . /home/gradle/src/producer
WORKDIR /home/gradle/src/producer
RUN gradle bootJar --no-daemon --stacktrace
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=build/libs/*.jar
COPY --from=build /home/gradle/src/producer/build/libs/*.jar producer.jar
ENTRYPOINT ["java","-jar","/producer.jar"]
ADDed files need to be under the directory where the docker build is being run from, so depending on your structure you probably want something like:
ADD myProject /app
Assuming you have a structure like:
Dockerfile
myProject/

Is it possible to copy files to the host during a multistage docker build?

I have written the following Dockerfile to containerize a maven build:
FROM maven AS builder
WORKDIR /build
COPY . /build
RUN mvn -Dmaven.repo.local=.m2/repository clean test clover:instrument clover:clover clover:check findbugs:check package site
FROM amazoncorretto:8
COPY --from=builder /build/target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
The second stage copies the jar file built by the first stage so that it can be used by its ENTRYPOINT but I'd also like the docker host to get a copy of the entire target directory from the container because it holds other build artefacts like code coverage and analysis reports.
Specifically, I'd like the copy to happen as part of the docker build -t fakefirehose . Is this possible?

Gradle dependency caching during docker multi stage build?

I have the following Dockerfile
FROM gradle:jdk13 AS appbuild
WORKDIR "/home/gradle/"
COPY --chown=gradle:gradle "./build.gradle" "/home/gradle/"
RUN gradle dependencies
COPY --chown=gradle:gradle "./src/" "/home/gradle/src/"
RUN gradle build --info
FROM openjdk:13
ENV LANG en_US.UTF-8
COPY --from=appbuild "/home/gradle/build/libs/frontend.jar" "/frontend.jar"
CMD ["java", "-jar", "-Dspring.profiles.active=default", "/frontend.jar"]
My aim is to prevent gradle from downloading the dependencies every time I build a docker image.
The command gradle dependencies downloads all the required java libraries in case they are missing.
Before the first gradle dependencies command I only copied the build.gradle in order to only download the dependencies and cache them.
When I run the gradle build command, why does it want to download all the files again? They are already present in one of the layers.
I have tried with RUN gradle clean build --info || return 0 instead of gradle dependencies, all the same.
The GRADLE_USER_HOME environment variable isn't set by default. You'll need to explicitly set it, and then copy over the downloaded dependencies in the next stage.
FROM gradle:jdk13 AS cache
WORKDIR /app
ENV GRADLE_USER_HOME /cache
COPY build.gradle gradle.properties settings.gradle ./
RUN gradle --no-daemon build --stacktrace
FROM gradle:jdk13 AS builder
WORKDIR /app
COPY --from=cache /cache /home/gradle/.gradle
COPY src/ src/
RUN gradle --no-daemon build --stacktrace
FROM openjdk:jre-alpine
WORKDIR /app
RUN apk --no-cache add curl
COPY --from=builder /app/build/libs/frontend.jar /frontend.jar
ENV PORT 80
EXPOSE 80
HEALTHCHECK --timeout=5s --start-period=5s --retries=1 \
CMD curl -f http://localhost:$PORT/health_check
CMD ["java", "-jar", "-Dspring.profiles.active=default", "/frontend.jar"]
Here's my original Dockerfile. I've modified it for yours, but haven't tested it, so you can refer to the original if you're in doubt.

Run dotnet test inside docker container

I want to run the dotnet test command inside a docker container but I just cannot figure out where to put the command. The project is a .NET Core 2.1 test project. The reason for this is that I want to run end-to-end integration tests which require all my containers to be running.
DockerFile:
FROM microsoft/dotnet:2.1-runtime AS base
WORKDIR /app
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY *.sln ./
COPY Sombra.IntegrationTests/Sombra.IntegrationTests.csproj Sombra.IntegrationTests/
COPY . .
WORKDIR /src/Sombra.IntegrationTests
RUN dotnet build -c Release -o /app
FROM build AS publish
RUN dotnet publish -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "test", "Sombra.IntegrationTests.csproj"]
docker-compose.yml
version: '3'
services:
sombra.integrationtests:
image: sombra.integrationtests
build:
context: .
dockerfile: Sombra.IntegrationTests/Dockerfile
depends_on:
- rabbitmq
You're using a runtime image to invoke the sdk command test. Your final is from base and base is from runtime.
I've successfully used unit tests as intermediate step while building the container but never integration tests with docker-compose. The key difference is I used a RUN command instead of the entrypoint/cmd so the tests are already executing while building the container. The main advantage is that there is no final image when the tests fail. But then again, this were pure unit tests and no integration tests. Although I can imagine that this will also work.
Here is my full example:
FROM microsoft/dotnet:2.0-sdk AS build-env
WORKDIR /app
# copy csproj and restore as distinct layers
COPY test.sln ./test.sln
COPY program/program.csproj ./program/program.csproj
COPY program.tests/program.tests.csproj ./program.tests/program.tests.csproj
RUN dotnet restore
# copy everything else and build
COPY . ./
RUN dotnet test program.tests -c Release
RUN dotnet publish program -c Release -o /app/out
# build runtime image
FROM microsoft/dotnet:2.0-runtime
WORKDIR /app
COPY --from=build-env /app/out ./
ENTRYPOINT ["dotnet", "program.dll"]
There is a good blog about this. A guide to setting up a .NET Core project using Docker, with integrated unit and component tests
In this blog look for component tests which is equivalent to what you are trying to do.
Below dockerfile is working for me. This can be build as docker image and then can be used for running integration tests.
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY *.sln .
COPY ["Somthing.Business/Somthing.Business.csproj", "Somthing.Business/"]
COPY ["tests/Somthing.Business.IntegrationTests/Somthing.Business.IntegrationTests.csproj", "tests/Somthing.Business.IntegrationTests/"]
COPY "Directory.*.props" . # this is centralized package manager for a project
RUN dotnet restore "tests/Somthing.Business.IntegrationTests/Somthing.Business.IntegrationTests.csproj"
COPY . .
RUN dotnet build "tests/Somthing.Business.IntegrationTests/Somthing.Business.IntegrationTests.csproj"
FROM build AS testrunner
WORKDIR /src/tests/Somthing.Business.IntegrationTests
CMD ["dotnet", "test", "--no-restore"]
You don't provide us with an error log or something, but my guess is that you're trying to run dotnet test Sombra.IntegrationTests.csproj on an image that doesn't have the dotnet sdk installed (only the dotnet runtime).
The dotnet runtime is a version of dotnet core that cannot execute commands (like test and build). It can only execute dll's (hence the name "runtime").

Resources