Openshift Docker Strategy - not able to pull maven artifacts from private repo - docker

In OpenShift i am using s2i( docker strategy) .
I have configured two repo's public and private in pom.xml .
maven is able to pull the artifacts from the public repo , But it could not pull the application specific artifact from the private repo.
Is there a way to update the maven setting.xml inside the openshift by providing maven repo credentials. how to provide credentials to pull the artifacts from private maven repo configured.
Error Below
Downloading from central: https://artifactory.mycomp.com/artifactory/java-snapshot-local/com/test/common-security/1.0.0/common-security-1.0.0.pom
Failed to execute goal on project demo-app: Could not resolve dependencies for project com.example:demo-app:jar:0.0.1-SNAPSHOT: Failed to collect dependencies at com.mycomp:common-security:jar:1.0.0: Failed to read artifact descriptor for
com.mycomp:common-security:jar:1.0.0: Could not transfer artifact com.mycomp:common-security:pom:1.0.0 from/to central (https://artifactory.mycomp.com/artifactory/java-snapshot-local): authentication failed for https://artifactory.mycomp.com/artifactory/java-snapshot-local/com/test/common-security/1.0.0/common-security-1.0.0.pom,
status: 401 Unauthorized -> [Help 1]
[ERROR]

The below one worked for me but not sure this one is ideal. Add the settings.xml to the root of the source:
<settings>
<servers>
<server>
<id>${repo.id}</id>
<username>${repo.login}</username>
<password>${repo.pwd}</password>
</server>
</servers>
</settings>
Inside the docker, use can use the settings.xml as an argument during build and supply the credentials.
# Build the application first using Maven
FROM maven:3.8-openjdk-11 as build
WORKDIR /app
COPY . .
COPY settings.xml /usr/share/
RUN mvn --version
RUN mvn --settings /usr/share/settings.xml -Drepo.id=central -Drepo.login=Myname -Drepo.pwd=MyPass clean install -Dmaven.test.skip=true
# Inject the JAR file into a new container to keep the file small
FROM openjdk:8-jre-alpine
WORKDIR /app
COPY --from=build /app/target/demo-app*.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["sh", "-c"]
CMD ["java -jar app.jar"]

Related

How to organize multi-stage Dockerfiles for multi-module microservices with common modules

I have a gRPC microservices project with following structure:
- common (common protobuf definitions)
- microservices
- ms1
..
- msN
Now I want to add multi stage Dockerfiles for each microservice.
The problem is that I have this common module which I need to build the rest of the projects. I can't reference the sources outside the microservice project in Dockerfile.
So the only posibility I see is to have one Dockerfile in the root folder that builds all the images:
FROM maven:3.8.6-eclipse-temurin-17 AS builder
COPY ./ /usr/app
RUN mvn -f /usr/app/pom.xml clean package
FROM eclipse-temurin:17-jre-alpine
COPY --from=builder /usr/app/microservices/ms1/target/ms1-1.0-SNAPSHOT.jar /usr/app/ms1-1.0-SNAPSHOT.jar
ENTRYPOINT ["java", "-jar", "/usr/app/ms1-1.0-SNAPSHOT.jar"]
But still I have to build all the project in builder image.
One other option I see is to create separate Docker images for builder and then referencing it inside of the microservice Dockerfile by tag. But how can I trigger rebuild for builder image when building microservice image.
Are there any other options? Which one should I use?
We can use a multistage dockerfile with arguments (docs.docker.com) and maven's --also-make command line option (maven.apache.org):
FROM maven:3.8.6-eclipse-temurin-17 AS builder
ARG RELATIVE_PATH_TO_ADAPTER_MODULE # e.g. service/ms1
COPY ./ /usr/app
# specify the specific project to build via "-pl", we could also use "-f /usr/app/${PATH_TO_ADAPTER_MODULE}/pom.xml"
# we specify --also-make to also build the dependencies
RUN mvn -pl /usr/app/${PATH_TO_ADAPTER_MODULE} --also-make clean package
FROM eclipse-temurin:17-jre-alpine
ARG RELATIVE_PATH_TO_ADAPTER_MODULE # e.g. service/ms1
COPY --from=builder /usr/app/${RELATIVE_PATH_TO_ADAPTER_MODULE}/target/*.jar /usr/app/service.jar
ENTRYPOINT ["java", "-jar", "/usr/app/service.jar"]
Should the target-directory contains more than one .jar-file, we can exclude all unwanted .jar-files through a .dockerignore-file (docs.docker.com), e.g. in the module's root directory.
We can then build a particular microservice by calling docker build with --build-arg (docs.docker.com)
docker build --build-arg RELATIVE_PATH_TO_ADAPTER_MODULE=services/ms1 --tag services/ms1 .
docker build --build-arg RELATIVE_PATH_TO_ADAPTER_MODULE=services/ms2 --tag services/m22 .
...
Notice, however, that each build has still to re-build the dependency modules; they are not shared across builds. Also, each build has to re-download all maven dependencies. This article at baeldung.com shows how to use a host directory as maven cache.

.csproj file not found when building docker image using Azure Pipeline

My goal
I want to publish a docker image to Dockerhub from the Azure DevOps Pipeline.
The pipeline runs after a commit on the master branch in Gitlab.
The application I want to build an image for is a .Net Core Web API project.
I'm using the automatically created Dockerfile by dotnet.
Error
This is the error I get:
Information
The folder structure of my application looks like this:
- APIGateway [Folder]
- APIGateway [Folder]
- Controller/Models/Services etc... [Folders]
- APIGateway.csproj
- APIGateway.csproj.user
- **Dockerfile**
- Program.cs
- Startup.cs
- Appsettings,json
- Appsettings.Development.json
- APIGateway.UnitTests [Folder]
- .dockerignore
- APIGateway.sln
- Readme.md
My Dockerfile looks like this:
For the Azure Pipeline, I added the .Net Core template task (restore, build, test, publish, publish artifect) to the agent job. The pipeline executes these tasks successfully.
I also added the Docker BuildAndPush task and configured my Dockerhub as a container registry.
The commands for the BuildAndPush task:
I already looked at this similar post: Azure Pipeline to build docker images fails using same docker file in Visual Studio. People mainly suggested to add 'Build.Repository.LocalPath' to the build context. But I still get the same error.
Does anyone know how to solve this issue?
Others have alluded to this in the comments.
Given you have a folder structure containing multiple projects within a solution similar to this:
AND your Dockerfile was created in one of the projects within the solution (e.g., the Server project) similar to this (e.g., generated by VS-right click, Add Docker support):
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["Server/QuizManagerClientHosted.Server.csproj", "Server/"]
COPY ["Client/QuizManagerClientHosted.Client.csproj", "Client/"]
COPY ["Shared/QuizManagerClientHosted.Shared.csproj", "Shared/"]
RUN dotnet restore "Server/QuizManagerClientHosted.Server.csproj"
COPY . .
WORKDIR "/src/Server"
RUN dotnet build "QuizManagerClientHosted.Server.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "QuizManagerClientHosted.Server.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "QuizManagerClientHosted.Server.dll"]
Problem: It works locally but not via ADO (or perhaps GitHub Actions or other CI/CD solutions).
Solution: Move the Dockerfile up one level (e.g., from the Server directory to the QuizManagerClientHosted directory).

Specify Source directory for Docker Builder Image

Note: I had problems finding a good title. If you have a better idea for the title feel free to edit the title.
In the past I have used the following builder image to containerize the build process of a Spring Boot app.
FROM maven:3.6.3-jdk-11
COPY pom.xml ./
COPY src ./src
RUN mvn clean package
I don't like this container design, because the resulting container image is useless if the source code changes, because if the source code or pom.xml changes I need to rebuild the docker image. Instead I want a builder image which takes a src directory and a pom.xml and executes mvn clean package when running the container.
FROM maven:3.6.3-jdk-11
COPY pom.xml ./
COPY src ./src
ENTRYPOINT ["mvn", "clean", "package"]
I now use mvn clean package as the entrypoint. This way mvn clean package gets execute every time the container starts and not just on docker build. But the problem remains. The src directory and pom.xml is copied during the docker build process.
So here is my question: Is there a way to specify the src directory and pom.xml when executing docker run ? Can I achieve this by mounting a volume?
FROM maven:3.6.3-jdk-11
WORKDIR /usr/src/myapp
ENTRYPOINT ["/usr/local/bin/mvn-entrypoint.sh"]
CMD ["mvn"]
This solution works. Run it with:
docker container run --name build -v "$(pwd)":/usr/src/myapp -w /usr/src/myapp myapp:build mvn clean install
However, for this you can just use the maven image as #timsmelik has suggested in the comments.

Iot Edge: Building a Docker image from multi projects

I can build and run in Visual Studio successfully, but I got an error when I am trying to build a docker image(TestModule) from a visual studio that references 2 projects (Microsoft.Azure.Devices.Edge.Util + ModuleLib). Any idea what wrong with my dockerfile? To build, I right-click on project> build & push IoT edge Modules (I'm using vs extension tool).
projects:
-TestModule
|--Dockerfile
-Microsoft.Azure.Devices.Edge.Util
-ModuleLib
TestModule.csproj
...
<ItemGroup>
<ProjectReference Include="..\Microsoft.Azure.Devices.Edge.Util\Microsoft.Azure.Devices.Edge.Util.csproj" />
<ProjectReference Include="..\ModuleLib\Microsoft.Azure.Devices.Edge.ModuleUtil.csproj" />
</ItemGroup>
...
Build Errors:
Step 4/12 : COPY Microsoft.Azure.Devices.Edge.Util/*.csproj ./Microsoft.Azure.Devices.Edge.Util/
COPY failed: no source files were specified
[ERROR]: COPY failed: no source files were specified
UPDATE:
*
if you try to build this inside DOCKERFILE, using VS Code, the file will not be able to get access because the context of the docker is set to the module folder access. Hence the correct command should be for setting context at root folder.
Run in Powershell in the root folder (replaced myacr.azurecr.io with you container):
docker build --rm -f .\TestModule\Dockerfile.windows-amd64 -t myacr.azurecr.io/testmodule:0.0.7-windows-amd64 .;if ($?) { docker push myacr.azurecr.io/testmodule:0.0.7-windows-amd64 }
Dockerfile in TestModule (Dockerfile.windows-amd64):
FROM microsoft/dotnet:2.1-sdk AS build-env
WORKDIR /app
COPY . .
RUN dotnet restore ./TestModule/TestModule.csproj
COPY . ./
RUN dotnet publish ./TestModule/TestModule.csproj -c Release -o out
FROM microsoft/dotnet:2.1-runtime-nanoserver-1809
WORKDIR /app
COPY --from=build-env /app/TestModule/out ./
ENTRYPOINT ["dotnet", "TestModule.dll"]
I created a DockerBuild.bat batch script in root project folder(replaced myacr.azurecr.io with you container), just enter as parameter a module name (lowercase) + version:
#echo off
Rem Run docker build image and push to Azure Container
IF "%~1"=="" (
ECHO Missing module name parameter lowercase. Ex: DockerBuild.bat modulename
EXIT
)
IF "%~2"=="" (
ECHO Missing version parameter. Ex: DockerBuild.bat modulename version
EXIT
)
set modulename=%~1
set version=%~2
echo Module name: %modulename%
echo Version: %version%
docker build --rm -f .\%modulename%\Dockerfile.windows-amd64 -t myacr.azurecr.io/%modulename%:%version%-windows-amd64 .
docker push myacr.azurecr.io/%modulename%:%version%-windows-amd64
echo The Docker build has completed

How to build a Docker image for Spring Boot application without the JAR at hand

I have followed these tutorials to build Docker image for my Spring Boot application, which uses Maven as build tool.
I am using boot2docker VM on top of Windows 10 machine, cloning my project to the VM from my Bitbucker repository.
https://spring.io/guides/gs/spring-boot-docker/
https://www.callicoder.com/spring-boot-docker-example/
I understand the instructions told, but, I failed to build a proper Docker image. Here's the things I tried.
Use the Spotify maven plugin for Dockerfile. Try to run ./mvnw to build the JAR as well as the Docker image. But, I don't have Java installed in the boot2docker. So the Maven wrapper ./mvnw cannot be run.
I tried to build the JAR through Dockerfile, which is based on the openjdk:8-jdk-alpine image. I added RUN ./mvnw package instruction in the Dockerfile. Then run docker build -t <my_project> . to build Docker image.
It fails at the RUN instruction, claiming /bin/sh: mvnw: not found
The command '/bin/sh -c mvnw package' returned a non-zero code: 127
My Dockerfile, located in the directory where the mvnw is located:
MAINTAINER myname
VOLUME /tmp
RUN ./mvnw package
ARG JAR_FILE=target/myproject-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
For 1, I need to have Java installed in the OS where the Docker engine resides. But I think it's not a good practice coz this lowers the portability.
For 2, first, I don't know how to run ./mvnw successfully in Dockerfile. Second, I'm not sure if it is a good practice to build the Spring Boot JAR through Dockerfile, coz I don't see any "Docker for Spring Boot" tutorial to tell to do so.
So, what is the best practice to solve my situation? I'm new to Docker. Comments and answers are appreciated!
You can install maven and run the compile directly in the build. Typically this would be a multi-stage build to avoid including the entire jdk in your pushed image:
FROM openjdk:8-jdk-alpine as build
RUN apk add --no-cache maven
WORKDIR /java
COPY . /java
RUN mvn package -Dmaven.test.skip=true
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/java/target/myproject-0.0.1-SNAPSHOT.jar"]
The above is a stripped down version of a rework from the same example that I've done in the past. You may need to adjust filenames in your entrypoint, but the key steps are to install maven and run it inside your build.
From your second example I think you are misunderstanding how Docker builds images. When Docker executes RUN ./mvnw package, the file mvnw must exist in the file system of the image being built, which means you should have an instruction like COPY mvnw . in a previous step - that will copy the file from your local filesystem into the image.
You will likely need to copy the entire project structure inside the image, before calling ./mvnw, as the response from #BMitch suggests.
Also, as #BMitch said, to generate a small-sized image it's normally recommended to use a multi-stage build, where the first stage installs every dependency but the final image has only your JAR.
You could try something like below:
# First stage: build fat JAR
# Select base image.
# (The "AS builder" gives a name to the stage that we will need later)
# (I think it's better to use a slim image with Maven already installed instead
# than ./mvnw. Otherwise you could need to give execution rights to your file
# with instructions like "RUN chmod +x mvnw".)
FROM maven:3.6.3-openjdk-8-slim AS builder
# Set your preferred working directory
# (This tells the image what the "current" directory is for the rest of the build)
WORKDIR /opt/app
# Copy everything from you current local directory into the working directory of the image
COPY . .
# Compile, test and package
# (-e gives more information in case of errors)
# (I prefer to also run unit tests at this point. This may not be possible if your tests
# depend on other technologies that you don't whish to install at this point.)
RUN mvn -e clean verify
###
# Second stage: final image containing only WAR files
# The base image for the final result can be as small as Alpine with a JRE
FROM openjdk:8-jre-alpine
# Once again, the current directory as seen by your image
WORKDIR /opt/app
# Get artifacts from the previous stage and copy them to the new image.
# (If you are confident the only JAR in "target/" is your package, you could NOT
# use the full name of the JAR and instead something like "*.jar", to avoid updating
# the Dockerfile when the version of your project changes.)
COPY --from=builder /opt/app/target/*.jar ./
# Expose whichever port you use in the Spring application
EXPOSE 8080
# Define the application to run when the Docker container is created.
# Either ENTRYPOINT or CMD.
# (Optionally, you could define a file "entrypoint.sh" that can have a more complex
# startup logic.)
# (Setting "java.security.egd" when running Spring applications is good for security
# reasons.)
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -jar /opt/app/*.war

Resources