Docker - misunderstanding about the execution and volume - maven

I have a following Dockerfile in my pet project:
FROM java:8
ADD target/sources-registry-0.0.1-SNAPSHOT.jar sources-registry.jar
RUN bash -c 'touch /sources-registry.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/sources-registry.jar"]
EXPOSE 8761
And everything perfectly works - image is created and can be run. Now a bit of description about the project: it is a maven based project and before actually executing the Dockerfile I have to manually run mvn package.
However, if I change the Dokerfile to (because I do not want manually to run mvn package and want to automate it)
FROM java:8
RUN ls target
RUN ./mvnw package
ADD target/sources-registry-0.0.1-SNAPSHOT.jar sources-registry.jar
RUN bash -c 'touch /sources-registry.jar'
#ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/sources-registry.jar"]
EXPOSE 8761
then while execution I get /bin/sh: 1: ./mvnw: not found. However, mvnw is in my project files near the pom.xml.
Even more if I just do following Dockerfile
FROM java:8
RUN ls target/
then I get ls: cannot access target/: No such file or directory.
Can someone please explain this behaviour?
I mean why I can actually do something with target folder (first
Dockerfile) even if does not exist (third Dockerfile)?
How project files (and what files) get copied into a created
container?
The main question: Why second Dockerfile is not working? And how I can make it work?

The ADD command copies over the sources-registry.jar file into the Docker image, so that the first example is able to execute it. If you want to use any other files inside the container, you need to include them in the image as well (using ADD or COPY). See the reference docs for more information

Related

How to do maven build and run make command inside container

I need to run Maven build inside container and afterwards I need to run make command.
For executing Maven, I did the following inside dockerfile
FROM maven:3.8.1-adoptopenjdk-11 AS build
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package
After maven execution, some jar files are generated, which is needed to run make command (used in make file)
Now my question is how to get docker image for make, and how do I use it in same dockerfile? I tried to find docker image for make but didn't get it directly in dockerhub.
I'm familiar with building java code but not with building C/C++ code with make. Any help would be appreciated.

Need assistance with Dockerfile and Kubernetes for .AspNetCore service

My docker build is failing due to the following error:
COPY failed: CreateFile \?\C:\ProgramData\Docker\tmp\docker-builder117584470\Aeros.Services.Kubernetes\Aeros.Services.Kubernetes.csproj: The system cannot find the path specified.
I am fairly new to docker and have went with the basic project template that is set up when you create a Kubernetes container project template, so I'd figure it would work out of the box, but I'm mistaken.
I'm having problems trying to figure out what it's attempting to due in the temp directory structure and the reason it is failing. Can anyone offer some assistance? I've done some searching and others have said the default docker template was incorrect in Visual Studio, but I'm not seeing any of the files being copied over to the temp directory to begin with, so figuring out what is going on is being rather problematic at the time.
Here is the docker file, the only thing I've added is a publishingProfile arg so I can tell it which profile to use in the Build and Publish steps :
ARG publishingProfile
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY ["Aeros.Services.Kubernetes/Aeros.Services.Kubernetes.csproj", "Aeros.Services.Kubernetes/"]
RUN dotnet restore "Aeros.Services.Kubernetes/Aeros.Services.Kubernetes.csproj"
COPY . ./
WORKDIR "/src/Aeros.Services.Kubernetes"
RUN dotnet build "Aeros.Services.Kubernetes.csproj" -c $publishingProfile -o /app
FROM build AS publish
RUN dotnet publish "Aeros.Services.Kubernetes.csproj" -c $publishingProfile -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Aeros.Services.Kubernetes.dll"]
I haven't touched the yaml file, but if you need that I can provide it as well. Again, all I've done with this is add a few NuGet packages to the project reference. Build in VisualStudio runs fine, but the docker command:
docker build . --build-arg publishingProfile=Release
is failing with the error mentioned above.
Can someone be so kind as to offer some enlightenment? Thanks!
Edit 1:
I am executing this from the project's folder via a PowerShell command line.
Leandro's comments helped come across the solution.
So first a rundown of that COPY command, it takes two parameters, source and destination.
Within the template for the Dockerfile for Visual Studio, it includes the folder location of the .csproj file it is attempting to copy. In my case, the command read as follows:
COPY ["Aeros.Services.Kubernetes/Aeros.Services.Kubernetes.csproj", "Aeros.Services.Kubernetes/"]
So it is looking for my Aeros.Services.Kubernetes.csproj file in the Aeros.Services.Kubernetes project folder and copying it to the Aeros.Services.Kubernetes folder in the src folder of Docker.
The problem with this is that if you use the default setup, your dockerfile is included inside the project folder. If you are executing the docker build from within the project folder, the syntax for the COPY command is actually looking in the wrong file location. For instance, if your project is TestApp.csproj located in the TestApp project folder, and you are executing the Docker build command for the dockerfile within the same folder, the syntax for that COPY command:
COPY ["TestApp/TestApp.csproj", "TestApp/"]
is actually looking for: TestApp/TestApp/TestApp.csproj.
The correct syntax for the COPY command in this situation should be:
COPY ["TestApp.csproj", "TestApp/"]
since you are already within the TestApp project folder.
Another problem with the default template that may trouble some is that it doesn't copy the web files for the project either, so once you get past the COPY and dotnet restore steps, you will fail during the BUILD with a:
CSC : error CS5001: Program does not contain a static 'Main' method
suitable for an entry point
This is resolved by adding:
COPY . ./
following your RUN dotnet restore command to copy your files.
Once these pieces have been addressed in the default template provided, everything should be functioning as expected.
Thanks for the help!
In which line the problem happens? I do not remember if docker build shows it.
Where are you executing this build? The problem is that it is not finding the file you are trying to copy. It should be local to where the command is executed.
I saw now, the problem is on the first COPY.

Using Maven artifact in Google Cloud Docker build

I have a google cloud container build with the following steps
gcr.io/cloud-builders/mvn to run a mvn clean package cmd
gcr.io/cloud-builders/docker to create a docker image
My docker image includes and will run tomcat.
Both these steps work fine independently.
How can I copy the artifacts built by step 1 into the correct folder of my docker container? I need to move either the built wars or specific lib files from step 1 to the tomcat dir in my docker container.
Echoing out the /workspace and /root dir in my Dockerfile doesn't show the artifacts. I think I'm misunderstanding this relationship.
Thanks!
Edit:
I ended up changing the Dockerfile to set the WORKDIR to /workspace
and
COPY /{files built by maven} {target}
The working directory is a persistent volume mounted in the builder containers, by default under /workdir. You can find more details in the documentation here https://cloud.google.com/container-builder/docs/build-config#dir
I am not sure what is happening in your case. But there is an example with a Maven step and a Docker build step in the documentation of the gcr.io/cloud-builders/mvn builder. https://github.com/GoogleCloudPlatform/cloud-builders/tree/master/mvn/examples/spring_boot. I suggest you compare with your files.
If it does not help, could you share your Dockerfile and cloudbuild.yaml. Please make sure you remove any sensitive information.
Also, you can inspect the working directory by running the build locally https://cloud.google.com/container-builder/docs/build-debug-locally#preserve_intermediary_artifacts

I am trying to perform mvn install from Dockerfile but it is not working says mvn not found

I am trying to perform "mvn install" to create war file from Dockerfile. Bellow is the Dockerfile
FROM scratch
FROM ubuntu:16.04
RUN mkdir /opt/java8
RUN mkdir /opt/tomcat8
RUN mkdir /opt/maven3
ENV JAVA_HOME /opt/java8
ENV CATALINA_HOME /opt/tomcat8
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin:$M2_HOME/bin
ADD jdk1.8.0_112 /opt/java8
ADD apache-tomcat-8.0.38 /opt/tomcat8
WORKDIR /home/veni/git/M_UserTP
RUN mvn install
WORKDIR /home/veni/git/M_UserTP/target
RUN mv M_UserTP.war
/home/veni/Documents/dhaval_bhoot/docker_images/tomcat1
ADD M_UserTP.war /opt/tomcat8/webapps
EXPOSE 8080
CMD ["catalina.sh", "run"]
I also added the path of bin directory of maven in PATH environment variable.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/veni/Documents/apache-maven-3.3.9/bin/
This path I set from root user in my machine, I also added same path in PATH variable as normal user already.
So now I exit from root user and come back by sudo su to be root user and check PATH variable, it has not path of maven
So when I make docker build of image I get the bellow error
/bin/sh: 1: mvn: not found
The command '/bin/sh -c mvn install' returned a non-zero code: 127
Given that you want to run your application in a Tomcat 8 Docker container:
Your maven project should be laid out like:
M_UserTP
+ Dockerfile
+ pom.xml
+ src
+ target
This is a standard maven layout plus your Dockerfile.
Ensure that your pom.xml contains the following finalName defined in it:
<build>
<finalName>${project.artifactId}</finalName>
...
</build>
Your Dockerfile can be really simple:
FROM tomcat:8.0
COPY target/M_UserTP.war $CATALINA_HOME/webapps/
(Note how the finalName is used by the Dockerfile)
To build it, execute:
mvn clean install && docker build . -t Bhoot/M_UserTP
You can use what ever -t tag that you want.
It will take some time the first time that you do this while the standard Tomcat 8 image is downloaded.
Now you can run it:
docker run --detach --publish 8080:8080 Bhoot/M_UserTP
You don't really want to build your WAR file in the docker image. This will suck all the maven repository components used by maven to build your application into the image. This space is not recoverable as images will only ever grow - they never shrink again.
Have you considered using a maven:onbuild image in conjunction with a multi-stage build for this?
An example of such a usage (with a Spring Boot application) is available here: https://github.com/anokun7/docker-springframework/blob/master/Dockerfile
Your container have its own filesystem.
So the mvn binary available on your system, is not available on a base ubuntu image.
You should install it first in your container (with a RUN apt-get install..)
You will then be able to use it in the next RUN
Try getting inside your container (after commenting out maven layer and everything below) and type which mvn. This will display the absolute path of the maven binary. Then use that absolute path inside your Dockerfile instead of just mvn.
Example:
mvn -> /opt/maven/bin/mvn

Do not download all Maven dependencies on a Docker build

I'm trying to create a Dockerfile to then build a Maven project.
I wonder how to fix the Dockerfile and what command to then execute.
I would like to know how to run the build so that it does NOT download all the Maven dependencies every time it builds when the source code, sitting in the src/ directory, has NOT changed.
Here is my Dockerfile file:
FROM maven:3.3.9-jdk-8
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN cd /usr/src/app
ADD pom.xml /usr/src/app
RUN mvn dependency:resolve
ADD src /usr/src/app
RUN mvn package
ENTRYPOINT ["mvn"]
CMD ["package"]
Should I run the docker run --rm -it toolbox command or the docker build -t toolbox . command ?
Both of these above commands run fine, except that they both download all the Maven dependencies even if the source code has not been touched.
That's how Docker works. Every time you do docker run, it creates a new container which does not have any access to the files in the old container. So, it download all dependencies it requires. You can circumvent this by declaring an external volume. Looking at the Dockerfile of Maven, it declares a volume /root/.m2. So, you can use a directory in your host machine and attach it to this volume by -v option. Your Docker command would be,
`docker run -v <directory-in-your-host>:/root/.m2 <other-options-and-commands>
Every time you run a new docker run, Maven will look into your local directory before downloading the dependency.
However, my question is why don't you build your app first and use the resulting jar to create the docker images unless you have any specific reasons. You can create your own Dockerfile using java base image or simply use one of the docker-maven-plugin like spotify available out there. That makes your life a lot easier.

Resources