Need assistance with Dockerfile and Kubernetes for .AspNetCore service - visual-studio

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.

Related

ASPNET Core 3.1 - Dockerfile changes don´t work when run in Visual Studio

I run a web api (ASPNETCore 3.1 - API) in Visual Studio 2019 (F5 in Debug mode), I use Docker (for Linux), when I change Dockerfile and run application, the changes don´t work.
Example:
I put the RUN touch test.txt and ENV my_variable value in Dockerfile, but the file and variable are not created.
Does anyone know why?
Nothing like reading the official documentation...
https://learn.microsoft.com/en-us/visualstudio/containers/container-build?view=vs-2019#debugging
Debugging
When building in Debug configuration, there are several optimizations that Visual Studio does that help with the performance of the build process for containerized projects. The build process for containerized apps is not as straightforward as simply following the steps outlined in the Dockerfile. Building in a container is much slower than building on the local machine. So, when you build in the Debug configuration, Visual Studio actually builds your projects on the local machine, and then shares the output folder to the container using volume mounting. A build with this optimization enabled is called a Fast mode build.
In Fast mode, Visual Studio calls docker build with an argument that tells Docker to build only the base stage. Visual Studio handles the rest of the process without regard to the contents of the Dockerfile. So, when you modify your Dockerfile, such as to customize the container environment or install additional dependencies, you should put your modifications in the first stage. Any custom steps placed in the Dockerfile's build, publish, or final stages will not be executed.
This performance optimization only occurs when you build in the Debug configuration. In the Release configuration, the build occurs in the container as specified in the Dockerfile.
I put RUN touch test.txt and ENV my_variable value in the first lines (where Dockerfile build base stage) and it works.
A tip refers to RUN touch test.txt, this needs to be executed (WORKDIR) in another folder different from the folder mapped with the source code in the hostlocal (/app).
Example:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /tmp
RUN touch teste.txt
WORKDIR /app
ENV my_variable value
EXPOSE 80
EXPOSE 443
My final Dockerfile is:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /tmp
RUN touch teste.txt
RUN echo "teste1" > teste1.txt
WORKDIR /app
ENV my_variable value
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["MyTestProject/TestProject.csproj", "MyTestProject/"]
RUN dotnet restore "MyTestProject/TestProject.csproj"
COPY . .
WORKDIR "/src/MyTestProject"
RUN dotnet build "TestProject.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "TestProject.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENV my_variable value
RUN touch teste.txt
ENTRYPOINT ["dotnet", "TestProject.dll"]
You can choose to include additional environment files to be passed to the docker run command by adding the following tag DockerfileRunEnvironmentFiles inside the propertygroup in your .csproj file:
<PropertyGroup>
<DockerfileRunEnvironmentFiles>your_env_file.env</DockerfileRunEnvironmentFiles>
...
...
<PropertyGroup>
your_env_file.env:
PAT=[Personal Access Token]
PROJECT=[Azure DevOps Project URL]
VARIABLE=[Filename of the variable file including extension]
WORKSPACE=[Name of the default workspace]
For the problem about the arguments not being passed you can add this to your csproj:
<PropertyGroup>
<DockerDebuggeeArguments>touch test.txt</DockerDebuggeeArguments>
...
...
</PropertyGroup>
Found here: https://learn.microsoft.com/en-us/visualstudio/containers/container-msbuild-properties?view=vs-2019

Visual Studio docker support doesn't work with CI/CD

I have a solution that has the following projects:
ServiceStackDockerTest
ServiceStackDockerTest.ServiceModel
ServiceStackDockerTest.ServiceInterface
When I add docker support inside visual studio this is the docker file that is added.
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY ServiceStackDockerTest/ServiceStackDockerTest.csproj ServiceStackDockerTest/
COPY ServiceStackDockerTest.ServiceModel/ServiceStackDockerTest.ServiceModel.csproj ServiceStackDockerTest.ServiceModel/
COPY ServiceStackDockerTest.ServiceInterface/ServiceStackDockerTest.ServiceInterface.csproj ServiceStackDockerTest.ServiceInterface/
RUN dotnet restore ServiceStackDockerTest/ServiceStackDockerTest.csproj
COPY . .
WORKDIR /src/ServiceStackDockerTest
RUN dotnet build ServiceStackDockerTest.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish ServiceStackDockerTest.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "ServiceStackDockerTest.dll"]
It adds the docker file inside the startup project (/ServiceStackDockerTest).
This works perfectly fine inside visual studio. The image builds and runs when I debug and my breakpoints are hit.
However when I try to build this image normally using docker it doesn't work as it cannot find the path of the .csproj files.
I think this happens because Visual Studio is using volume sharing so it has access to the parent folders or it is changing the scope the Dockerfile is run in somehow.
However, in my CI pipeline it runs docker build on ServiceStackDockerTest/Dockerfile which copies this folder to docker and does not have access to it's parent folders. The paths in VS dockerfile are all from the parent directory to where the docker file is located.
Why has Microsoft built in their support like this? Surely building the dockerfile inside a CI pipeline is a common task.
What is the best way to fix this so I still can debug inside the container with live reload inside Visual Studio but also build the image in my CI pipeline?
So the answer to this is actually very simple. In CI pipeline just change the build context to the parent folder.
To build locally run this from parent folder docker build -f SSDockerTest2\Dockerfile . and then it runs it in context of parent direcory.

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

Docker - misunderstanding about the execution and volume

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

Recommended Project Structure for Docker

I'm working on a Go project that has the following structure (schematic):
./lib1
./prog1
./...
./prog2
./...
Where:
lib1 is a library
prog1 and prog2 are executables (both depend on lib1)
In a nutshell: How do I create Dockerfiles for prog1 and prog2?
I tried several approaches, all to no avail:
Creating a Dockerfile in prog1/
Failed because docker cannot ADD ../lib1 to the container since it is out of the context (see http://docs.docker.com/reference/builder/#add).
Creating a Dockerfile in the root directory
Ignoring the fact that I actually need two Dockerfiles (for prog1, and for prog2), I tried placing the Dockerfile in the root directory of the project.
However, the docker image I need to use (golang:1.4.1-onbuild) fails to find any Go files (since they are in ./prog1, and not in the root):
+ exec go install -v
can't load package: package app: no buildable Go source files in /go/src/app
What is the recommended project structure for the golang:1.4.1-onbuild image?
Edit: Better asked here: https://stackoverflow.com/questions/29209202/dockerizing-gos-hello-world
Most pull the files in via their VCS or just go get instead of using ADD. You add the the source tree in the same way regardless of what tool your building, since you need the structure of $GOPATH to be the same for each.
Note, you can also name your docker file via docker build -f, so if you want to use ADD, you can have multiple DOCKERFILEs in your root directory.

Resources