I do a multistage build right now. The first stage compiles with credentials for my internal repos and I just keep the binaries as per this example: https://github.com/dotnet/dotnet-docker/blob/master/documentation/scenarios/nuget-credentials.md
But I want to run in CI server and need to provider the CI server with test and coverage reports. It would be most elegant to do this in the build layer but how do I get files out of a docker image during build?
For example:
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj .
COPY ./nuget.config .
RUN dotnet restore
# Copy and publish app and libraries
COPY . .
############ Get this files out #####################
# Generate test report. copy this to external directory
RUN dotnet test --logger trx
# Generate coverage report. copy this to external directory
RUN dotCover.sh dotnet --output=myRep.html --reportType=HTML -- test
#######################################################
RUN dotnet publish -c Release -o out --no-restore
FROM mcr.microsoft.com/dotnet/core/runtime:3.1 AS runtime
WORKDIR /app/
COPY --from=build /app/out ./
ENTRYPOINT ["dotnet", "dotnetapp.dll"]
So I want to be able to run docker build and have it dump a test and coverage report to the current directory where docker build command was run. Is this possible? It would make this seamless for CI because all server must do is run docker build and it get reports
docker build supports an --output flag. I think it requires BuildKit (DOCKER_BUILDKIT=1). Here's one example usage.
https://docs.docker.com/engine/reference/commandline/build/ - then find --output on the page
https://docs.docker.com/engine/reference/commandline/build/#output
Related
I have a .net solution which has 2 projects, and each project is a microservice (a server). I have a dockerfile which first installs all the dependencies which are used by both projects. Then I publish the solution:
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.sln .
COPY Server/*.csproj ./Server/
COPY JobRunner/*.csproj ./JobRunner/
RUN dotnet restore ./MySolution.sln
# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["dotnet", "Server.dll"]
When the solution is published, 2 executables are available: Server.dll and JobRunner.dll. However, I can only start only one of them in Dockerfile.
This seems to be wasteful because restoring the solution is a common step for both Server and JobRunner project. In addition this line RUN dotnet publish -c Release -o out produces both an executable for Server and JobRunner. I could write a separate Dockerfile for each project but this seems redundant as 99% of the build steps for each project is identical.
Is there a way to somehow start 2 executables from a single file without using a script (I don't want that both services will be started in a single container)? The closest I've found is the --target option in docker build but it probably won't work because I'd need multiple entrypoints.
In your Dockerfile, change ENTRYPOINT to CMD in the very last line.
Once you do this, you can override the command by just providing an alternate command after the image name in the docker run command:
docker run ... my-image \
dotnet JobRunner.dll
(In principle you can do this without changing the Dockerfile, but the docker run construction is awkward, and there's no particular benefit to using ENTRYPOINT here. If you're using Docker Compose, you can override either entrypoint: or command: on a container-by-container basis.)
I have a large .NET solution and want to efficiently build multiple docker images from it for a few app projects.
The Dockerfile for the first project looks like this:
# Solution common build steps
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-env
WORKDIR /app
COPY . .
RUN setup-build-env.sh # Sets up additional NuGet feeds
RUN dotnet restore Linux.slnf
# Project specific build steps
RUN cd src/Category1/src/Project1 && dotnet publish -c Release -o publish
FROM mcr.microsoft.com/dotnet/runtime:3.1 AS base
WORKDIR /app
COPY --from=build-env /app/src/Category1/src/Project1/publish .
ENTRYPOINT dotnet Project1.dll
The parts up until including RUN dotnet restore Linux.slnf will be identical for every project image.
What I'm worried about most is the large (~400MB) COPY . . operation that seems to need to be repeated everytime this Dockerfile is built.
Each app project to be turned into a container references multiple projects in the solution, so just COPYing the single project in question won't work.
How do I efficiently build multiple app project images from my large solution?
Build a custom image with the common part
Common image
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-env
WORKDIR /app
COPY . .
RUN setup-build-env.sh # Sets up additional NuGet feeds
RUN dotnet restore Linux.slnf
docker build -t common.image:1.0 .
Project image
FROM common.image:1.0
RUN cd src/Category1/src/Project1 && dotnet publish -c Release -o publish
FROM mcr.microsoft.com/dotnet/runtime:3.1 AS base
WORKDIR /app
COPY --from=build-env /app/src/Category1/src/Project1/publish .
ENTRYPOINT dotnet Project1.dll
Obviously if the solution changes you must rebuild the common image
If ALL project has the SAME Dockerfile (change only the name) you can use the ARG
I am trying to dockerize an an angular aspnet core 2.2 webapi using the following dockerfile:
FROM mcr.microsoft.com/dotnet/core/sdk:2.2.105 AS build
WORKDIR /src
# Copy csproj and restore as distinct layers
COPY ["Fightplan_v1/Fightplan_v1.csproj", "Fightplan_v1/"]
COPY ["Fightplan_v1.Autogenerate/Fightplan_v1.Autogenerate.csproj", "Fightplan_v1.Autogenerate/"]
COPY ["Fightplan_v1.Autogenerate.Test/Fightplan_v1.Autogenerate.Test.csproj", "Fightplan_v1.Autogenerate.Test/"]
COPY ["Fightplan_v1.Database/Fightplan_v1.Database.csproj", "Fightplan_v1.Database/"]
COPY ["Fightplan_v1.Helpers/Fightplan_v1.Helpers.csproj", "Fightplan_v1.Helpers/"]
COPY ["Fightplan_v1.Jobs/ConvertImagestoBlob/Fightplan_v1.ConvertImagestoBlob.csproj", "Fightplan_v1.Jobs/ConvertImagestoBlob/"]
COPY ["Fightplan_v1.Models/Fightplan_v1.Models.csproj", "Fightplan_v1.Models/"]
COPY ["Fightplan_v1.Shared/Fightplan_v1.Shared.csproj", "Fightplan_v1.Shared/"]
RUN dotnet restore "Fightplan_v1/Fightplan_v1.csproj"
# Copy everything else and build
COPY . .
WORKDIR "/src/Fightplan_v1"
RUN dotnet build "Fightplan_v1.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "Fightplan_v1.csproj" -c Release -o /app
# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime
WORKDIR /app
COPY --from=build /app .
EXPOSE 80
ENTRYPOINT ["dotnet", "Fightplan_v1.dll"]
The build command used is:
docker build -f .\fp.dockerfile -t test .
The build goes through fine but when I try to run it using:
docker run -p 5100:80 -it test
I get the following error:
I have tried:
Adding -r linux-x64 to the end of publish to define the runtime: RUN dotnet publish "Fightplan_v1.csproj" -c Release -o /app -r linux-x64
Adding <PublishWithAspNetCoreTargetManifest>false</PublishWithAspNetCoreTargetManifest> to my .csproj file
None of the above fixes work unfortunately.
Since this is combined poject of an angular application and a webapi I might be missing some installations/dependencies?
You are copying the runtime files from wrong layer
COPY --from=build /app .
Try to change it to
COPY --from=publish /app .
Also, you probably need to separate out path in build and publish steps:
RUN dotnet build "Fightplan_v1.csproj" -c Release -o /app/build
RUN dotnet publish "Fightplan_v1.csproj" -c Release -o /app/publish
and then copy runtime files from the publish folder
COPY --from=publish /app/publish .
Edit. Basically, you need to copy publish artifacts into runtime, not build. Build will produce deps.json, which will lists all external dependencies, and during runtime this libraries are resolving using NuGet cache, if it is empty you will see an error. To copy dependencies along with project files you need to run publish.
So I assume, that theoretically dotnet build can be omitted, and is using only to discover compilation errors on early stage of docker build.
I am starting to investigate Azure Devops and its pipelines feature for setting up a continuous integration workflow. I have a pipeline that builds a Docker image of my application using the following dockerfile:
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build-env
WORKDIR /cicd
# restore (put more volatile, changing projects later in process)
COPY src/WebApp/WebApp.csproj ./src/WebApp/
RUN dotnet restore src/WebApp/WebApp.csproj -s http://mycontainerrepo.acme.com/repository/nuget/
COPY tests/WebApp.Test/WebApp.Test.csproj ./tests/WebApp.Test/
RUN dotnet restore tests/WebApp.Test/WebApp.Test.csproj -s http://mycontainerrepo.acme.com/repository/nuget/
# copy source
COPY . .
# test (if tests fail, no final image, yay)
RUN dotnet test tests/WebApp.Test/WebApp.Test.csproj
# publish
RUN dotnet publish src/WebApp/WebApp.csproj -o /publish
# runtime stage
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS release
COPY --from=build-env /publish /publish
WORKDIR /publish
ENTRYPOINT ["dotnet", "WebApp.dll"]
The call to run dotnet test executes just fine and outputs results to the console, but I don't know of any way to make use of this result in the pipeline. In TeamCity, you could set an environment variable to sort of trick it into outputting the test results (xUnit only, I think...). But not sure if there's a similar trick here...
I saw this post on Github about making a separate test image just for testing but was hoping to avoid that route unless its my only option.
Any other CI/CD Azure Devops gurus out there?
I am making a Dockerfile for a dotnet core project with some xUnit tests. I want to run the unit tests when the images are being built. However when I docker build I get the following message at the test step:
No test is available in /ciad/tests/bin/Debug/netcoreapp2.1/Tests.dll. Make sure that test discoverer & executors are registered and platform & framework version settings are appropriate and try again.
Here is the Dockerfile:
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /ciad
# restore
COPY API/API.csproj ./api/
RUN dotnet restore api/API.csproj
COPY Tests/Tests.csproj ./tests/
RUN dotnet restore tests/Tests.csproj
# copy src
COPY . .
# test
RUN dotnet test tests/Tests.csproj
I'm aware that this is an incomplete dockerfile. I'm just stuck with the tests at the moment. Could anyone see what I'm missing?
Good to mention that tests run fine in VS and "dotnet test" command works too. I can also see that the Tests projects' files are copied to the container.
I run:
docker build -t testing .
I don't know what was wrong but eventually thanks to tips from omajid I changed the tests project's name and folder to tests with small t and all other capital T in Dockerfile to small t and it worked!
I hope this might help someone.
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /ciad
# restore
COPY API/API.csproj ./api/
RUN dotnet restore api/API.csproj
COPY tests/tests.csproj ./tests/
RUN dotnet restore tests/tests.csproj
# copy src
COPY . .
# test
RUN dotnet test tests/Tests.csproj