Yesterday was one of those days when I got around to upgrading some docker files after the web projects were migrated to DotNet 7. The thing was, I wanted to reduce the size of the docker image as much as possible and take advantage of some improvements since Net 5.0 was released. Although everything seemed great and easy at the beginning, in the end, when it came to production it was not so much fun.! Here you can see my own adventurers on this:
1. Update the images to use Net 7. We can use the standard images (the «Skd:7.0») or another’s more lightweight like the alpine one, for the first layer (BUILD):
FROM mcr.microsoft.com/dotnet/sdk:7.0-alpine AS build
2. Then, for PUBLISH, we could have the more common sentences:
FROM build AS publish RUN dotnet publish "MyCoctailDev.csproj" -c Release -o /app/publish
But, to get a small image we have to do some changes:
- Choose the most adequate RID (Runtime Identifier). Because for this particular case is Linux, my election was «linux-musl-x64» which is a lightweight distributions using musl like Alpine. I used the argument «-r» for that.
- Then, include «–self-contained true» (or just «–self-contained», because true is its default value). This means, the final docker image:
- Contains DotNet runtime embedded on it.
- So, it doesn’t need the DotNet runtime installed.
- If we include «–self-contained false» instead, the final docker image base has to include a dotnet runtime installed, so we will have to choose «aspnet:7.0-alpine» but not «runtime-deps:7.0».
Therefore, we have two options regarding the previous steps:
... dotnet publish "MyCocktailDev.csproj" -c Release -o /app/publish -r linux-musl-x64 --self-contained ... FROM mcr.microsoft.com/dotnet/runtime-deps:7.0-alpine AS final ... ENTRYPOINT ["./MyCocktailDev"]
and, Option 2:
... dotnet publish "MyCocktailDev.csproj" -c Release -o /app/publish -r linux-musl-x64 --self-contained false ... FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine AS final ... ENTRYPOINT ["dotnet", "MyCocktailDev.dll"]
So far so good, but what about «/p:PublishTrimmed=true» as argument for «dotnet publish» ? Ok, so after apply that, the image size was reduced by almost half.
Note: To use Trimmed, could be possible to include below sentence in all .csproj files, to avoid some warnings.
At this point, I said, «Wwwwooooou» I get it !
But…., after some time doing some tests something started to seem a bit strange to me. The time to generate the docker image was more than double. But it got worst when I launch the Azure DevOps Pipeline due to the image docker must be generated more than once. Here, I miss some kind of cache for that when the Azure DevOps Build Agent is Linux. One more thing that I’ve to improve 🙂 !!!
I got the minimum docker image size but a high cost (in time) to generate it. That was not the result that I was expecting, maybe for others use cases it could be the bet !
Finally, my docker file was something like this:
FROM mcr.microsoft.com/dotnet/sdk:7.0-alpine AS build WORKDIR /src COPY ["MyCocktailDev/MyCocktailDev.csproj", "MyCocktailDev/"] RUN dotnet restore "MyCocktailDev/MyCocktailDev.csproj" COPY . . WORKDIR "/src/MyCocktailDev" RUN dotnet build "MyCocktailDev.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "MyCocktailDev.csproj" -c Release -o /app/publish -r linux-musl-x64 --self-contained true /p:PublishTrimmed=false FROM mcr.microsoft.com/dotnet/runtime-deps:7.0-alpine AS final WORKDIR /app COPY --from=publish /app/publish . EXPOSE 80 EXPOSE 443 ENTRYPOINT ["./MyCocktailDev"]
Note: «bullseye-slim-amd64» image size is twice bigger than the Alpine one, so if it doesn’t matter the Linux distribution my recommendation is to use Alpine!
Also remember that:
- Review .dockerignorefiles to include only necessary files
- Use as few layer as possible. There are many layers, one for each command in a Docker file (EXPOSE, RUN, COPY, ENTRYPOINT, …)
Happy building docker images… !
PS: This is my first post in English, so, sorry if there are some typos and/or mistakes. However, I hope to keep improving it as well as my technical knowledge 😉