Using Docker Buildkit --mount=type=cache for caching Nuget packages for .NET 5 dockerfile
Asked Answered
P

1

11

I am creating a docker file for a vue+mvc .NET 5 hybrid application. For this, I need to install Node.js, NuGet packages, as well as install Webpack. Every time when I am trying the build the image, it takes around 30 minutes.

I explored how Ican reduce this build time, and I understand the new Docker Buildkit feature provides a cache mount. But I haven't found many samples or documentation on working with NuGet packages specifically.

Can someone help me in providing any sample dockerfile which has implemented --mount=type=cache for NuGet packages?

Poore answered 6/10, 2021 at 10:38 Comment(0)
P
18

The key is using the same --mount=type=cache argument in all of the dockerfile RUN commands that need access to the same package cache (e.g. docker restore, docker build, docker publish).

Here's a short dockerfile example showing the same --mount=type=cache with the same id spread across separate dotnet restore/build/publish invocations. Separating the calls isn't always necessary as build will restore by default and publish will do both, but this way shows sharing the same cache across multiple commands. The cache mount declarations only appear in the dockerfile itself and don't require arguments in docker build.

The example also shows how you might use the BuildKit --mount=type=secret argument to pass in a NuGet.Config file that may be configured to access e.g. a private nuget feed. By default, secret files passed in this way appear in /run/secrets/<secret-id>, but you can change where they go via the target attribute in the docker build command. They only exist during the RUN invocation and don't remain in the final image.

# syntax=docker/dockerfile:1.2
FROM my-dotnet-sdk-image as builder
WORKDIR "/src"
COPY "path/to/project/src" .

RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
    --mount=type=secret,id=nugetconfig \
    dotnet restore "MyProject.csproj" \
    --configfile /run/secrets/nugetconfig \
    --runtime linux-x64

RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
    dotnet build "MyProject.csproj" \
    --no-restore \
    --configuration Release \
    --framework netcoreapp3.1 \
    --runtime linux-x64

RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
    dotnet publish "MyProject.csproj" \
    --no-restore \
    --no-build \
    -p:PublishReadyToRun=true \
    -p:PublishReadyToRunShowWarnings=true \
    -p:TieredCompilation=false \
    -p:TieredCompilationQuickJit=false \
    --configuration Release \
    --framework netcoreapp3.1 \
    --runtime linux-x64

A sample docker build command to pass in the nugetconfig file for a private feed might be:

docker build --secret id=nugetconfig,src=path/to/nuget.config -t my-dotnet-image .

For that command, the environment variable DOCKER_BUILDKIT=1 needs to be set.

Alternatively, you can use buildx:

docker buildx build --secret id=nugetconfig,src=path/to/nuget.config -t my-dotnet-image .

Pyle answered 6/10, 2021 at 16:55 Comment(11)
Thank you rob3c for the response. I have another question, does this cache limited only for this build run or it can be reuse for every build of this dockerfile? if no, please suggest the approach as I have many nugetpackages and taking lots of build time everytime i build by docker file.Poore
The path in --mount=type=cache,id=nuget,target=/root/.nuget/packages assumes that the host is linux based. What if the host is Windows? Can this feature be used cross platform?Weekend
@Poore The cache is used across any builds that use the same id value. It can make local builds very fast, but CI/CD builds with fresh environments will only benefit within a single dockerfile.Pyle
@MuhammadRehanSaeed I am currently working in a Windows host using linux containers. That target value is where the cache will be mounted within the container. Docker itself manages where it is stored locally on the host, and that isn't accessibly directly to us.Pyle
thank you @Pyle I implemented the same and monitoring with different build runs to verify does this cache might not reflect any new functionality. Also, just want to know, in case I want to purge these cache, for example I have a new packages introduced in my logic. In that case how can I go forward either buildkit and mount will take care of new changes? or do I need to manually purge the cache (in this case, please let me know how can I purge this cache data).Poore
@Poore I'm not sure how to specifically purge that particular cache. You can always run docker build with the --no-cache option to fully rebuild everything. If you're updating the package versions, I'd think they should be updating in the cache anyway. If you're not bumping package versions, nuget won't know it should pull them again regardless of docker caching.Pyle
This seemed to work in .NET 5 but I'm having trouble in .NET 6. Raised a new question: #70182370Weekend
Can I do the same in multi-stage builds? Let's say I restore in one stage, cache and run publish with --no-restore in another stage, will the cache be present?Arreola
@JoanaDelucaKleis yes, I use that feature often!Pyle
How could we configure a mount cache for build artifacts to make dotnet build/publish faster on consecutive runs?Largish
Is id=nuget parameter really necessary here? If it is not specified docker will use target path as id and it is the same in all commands.Canova

© 2022 - 2024 — McMap. All rights reserved.