Search code examples
dockerasp.net-core.net-coredockerfile

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


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?


Solution

  • 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 .