I want to containerize an ASP.NET app. the whole solution paths look like this
I have tried to write the Dockerfile like this
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env
WORKDIR /app
# Copy the project files
COPY . ./MyApp
# Copy the Infrastructure project file
COPY ../Infrastructure/ ./Infrastructure/
# Restore NuGet packages
RUN dotnet restore
# Build the solution
RUN dotnet build
# Publish the ASP.NET app to a directory called "app"
RUN dotnet publish -c Release -o /app
# Build the final image
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app
COPY --from=build-env /app .
# Expose the port and start the app
EXPOSE 80
ENTRYPOINT ["dotnet", "MyApp.dll"]
but I get an error
What am I doing wrong and how can I fix my Dockerfile? Do I have to move it to the ParentDirectory or something? Can I keep my current solution structure and still containerize this app?
It is possible to greatly reduce the size of an ASP.Net Docker image by using assembly trimming and by using runtime-deps image as apposed to the aspnet image:
FROM mcr.microsoft.com/dotnet/sdk:7.0-alpine AS build
WORKDIR /source
# copy csproj and restore as distinct layers
COPY aspnetapp/*.csproj .
RUN dotnet restore -r linux-musl-x64 /p:PublishReadyToRun=true
# copy everything else and build app
COPY aspnetapp/. .
RUN dotnet publish -c Release -o /app -r linux-musl-x64 --self-contained true --no-restore /p:PublishTrimmed=true /p:PublishReadyToRun=true /p:PublishSingleFile=true
# final stage/image
FROM mcr.microsoft.com/dotnet/runtime-deps:7.0-alpine-amd64
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["./aspnetapp"]
In this example, the sample app image is reduced from 220MB to 82.8 MB.
My question is why isn't this the default? What is the benefit of including all those unused assemblies?
I want to make a docker image that contains an Asp.net core app and some other components. I have decided to pull the debian image, install the necessary components (in this case is the asterisk system), then commit and push it as my own image, let's call it A.
In the Asp.net core app, I use A as a parent component in dockefile and build a image, let's call it B.
But when I run B as a container, I can not find the components I already installed in the image A.
This is my dockerfile:
FROM vocaoson7/asterisk:king
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /app
# copy csproj and restore as distinct layers
COPY *.sln .
COPY aspnetapp/*.csproj ./aspnetapp/
RUN dotnet restore
# copy everything else and build app
COPY aspnetapp/. ./aspnetapp/
WORKDIR /app/aspnetapp
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS runtime
WORKDIR /app
COPY --from=build /app/aspnetapp/out ./
ENTRYPOINT ["dotnet", "aspnetapp.dll"]
You are trying to use a multi-stage build and the way it works is that your final image is defined by your last FROM command in your Dockerfile and whatever follows that.
So for your case, all you will find in your final image is the aspnet:3.1 installation (from the base image used for the runtime stage) and an /app folder containing with what your build step generated in the out directory.
Your very first FROM has no influence whatsoever on the final image.
I'm building an ASP .NET Core 2.1 MVC application and I need to know where the NuGet libraries get stored, because one of them depends on a file I need to copy in the NuGet library folder. From the Dockerfile made by Visual Studio I see that it's making several images for each step of the building process, but Im so confused as to where the NuGet files are on the container's file system. I can't find it using find -iname "nuget" either.
per request my Dockerfile:
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 53204
EXPOSE 44391
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY ["Versandformulartool/Versandformulartool.csproj", "Versandformulartool/"]
RUN dotnet restore "Versandformulartool/Versandformulartool.csproj"
COPY . .
WORKDIR "/src/Versandformulartool"
RUN dotnet build "Versandformulartool.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "Versandformulartool.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Versandformulartool.dll"]
The Visual Studio tooling for Docker creates a Dockerfile for ASP.NET projects containing a COPY . . command as below:
WORKDIR /src
COPY *.sln ./
...
COPY . .
From what I've read, the <src> parameter is relative to the context, so isn't affected by the WORKDIR /src command. The <dest> however is relative to the WORKDIR so will be pointing at /src.
Is this command just bringing over the remaining files from the root for packaging (docker-compose.yml, .dockerignore, etc.)? If so, then why is this done ahead of the RUN dotnet build... command?
Full Dockerfile below:
FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0 AS build
WORKDIR /src
COPY *.sln ./
COPY MyProject/MyProject.csproj MyProject/
RUN dotnet restore
COPY . . # The line mentioned above
WORKDIR /src/MyProject
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", "MyProject.dll"]
The COPY . . copies the entire project, recursively into the container for the build.
The reason for the separation of the first 2 COPY commands with dotnet restore and then the complete COPY . . with dotnet build is a Docker caching trick to speed up container image builds. It is done this way so the project dependencies don't need to be reinstalled every time a code change is made.
Docker images are built in layers. Docker compares the contents and instructions that would make up the each new layer to previous builds. If they match the SHA256 checksum for the existing layer, the build step for that layer can be skipped.
Code changes a lot more than dependencies, and dependencies are usually fetched from a slow(ish) network now. If you copy the code after the dependency installs are completed then you don't bust the cached dependency layer for every other change.
This is a common theme across many languages with a dependency manager. Go, Python, Node.js etc. The Node.js equivalent does the package.json and package-lock.json before the rest of the application contents:
WORKDIR /app
COPY package.json package-lock.json /app/
RUN npm install
COPY . /app/
CMD ["node", "app/index.js"]
Some more pointers on the above from Scott Hanselman: https://www.hanselman.com/blog/OptimizingASPNETCoreDockerImageSizes.aspx
PRO TIP: Docker is smart about making intermediate images and doing the least work, but it's useful if we (the authors) do the right thing as well to help it out.
For example, see where we COPY the .csproj over and then do a "dotnet restore"? Often you'll see folks do a "COPY . ." and then do a restore. That doesn't allow Docker to detect what's changed and you'll end up paying for the restore on EVERY BUILD.
By making this two steps - copy the project, restore, copy the code, this means your "dotnet restore" intermediate step will be cached by Docker and things will be WAY faster.
The first dot is “where i am now”
So it will copy everything from the same place as the dockerfile, to “where i am now” in the container.
The “where i am now” in the image/container is defined by https://docs.docker.com/engine/reference/builder/#workdir 433
So if you set:
WORKDIR /tmp
and do
COPY . .
It will copy everything from the current folder, to /tmp