.netdockermultiplatform

Building multi-platform containers for dotnet applications error NETSDK1047


I am currently trying to build a multi-platform dotnet docker image for .NET 7 using the improved multi-arch build pattern described in this devblog post. However when I run this build command:

docker buildx build --tag exampleapiproject --platform linux/amd64,linux/arm64/v7,linux/arm64/v8 -f ExampleApiProject\Dockerfile ExampleApiProject

... I get the following error message from the builder:

=> ERROR [linux/amd64 build 6/7] RUN dotnet publish --arch amd64 --no-restore -o /app
------
 > [linux/amd64 build 6/7] RUN dotnet publish --arch amd64 --no-restore -o /app:
#0 2.350 MSBuild version 17.6.1+8ffc3fe3d for .NET
#0 3.610 /usr/share/dotnet/sdk/7.0.302/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(266,5): error NETSDK1047: Assets
file '/src/obj/project.assets.json' doesn't have a target for 'net7.0/linux-x64'. Ensure that restore has run and that you have included 'net7.0' in
the TargetFrameworks for your project. You may also need to include 'linux-x64' in your project's RuntimeIdentifiers. [/src/ExampleApiProject.csproj]
------

I also checked the project.assets.json file and it does include the net7.0/linux-musl-x64 as well as the net7.0 target.


Additional Information:

Build platform

I am working on a Windows x64 host system with Docker version 23.0.5, build bc4487a.

Project File

The example project was just created from the webapi template with minimal api and without https support.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

</Project>

Dockerfile

Also I am using the alpine-non-root Dockerfile from the aspnetapp samples using the aspnet:7.0-alpine image instead of aspnet:8.0-preview-alpine:


# Prepare build environment
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:7.0-alpine AS build
ARG TARGETARCH
WORKDIR /src

# Copy project and restore for target platform
COPY *.csproj .
RUN dotnet restore --arch $TARGETARCH

# Copy everything else and build app
COPY . .
RUN dotnet publish --arch $TARGETARCH --no-restore -o /app

# Prepare runtime environment
# Enable globalization and time zones:
# https://github.com/dotnet/dotnet-docker/blob/main/samples/enable-globalization.md
FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine as final

WORKDIR /app
COPY --from=build /app .

USER $APP_UID
ENTRYPOINT ["./aspnetapp"]

Solution attempts:

Non-alpine Images

I also attempted the same build using the normal versions of the images (the 7.0 instead of the 7.0-alpine) and also attempted the build using the 8.0-preview-alpine tag with the same errors.

Build only single platform

I also attempted to run buildkit only on a singe platform at a time (like --platform linux/amd64) but i get the same error message.

I tried this for all 3 different platforms, but with the same result (except of course the target being net7.0/linux-arm64, net7.0/linux-x64 or with alpine the *-musl-* targets).


Solution

  • I'm stupid and this cost me so much time...

    TL;DR: The .dockerignore file was missing


    By default the .dockerignore file is generated in the project root, but I built my project from the project directory. Main problem for me was, that the dockerignore file behaves a little bit different than the gitignore in that the dockerignore file must be at the build context root, and not the project root as docker does (obviously) not check parent directories for that file.

    The .dockerignore was thus missing in the project dir and the build context. This caused my local bin and obj folders to be exposed to the build context (which also contained a windows x64 dotnet restore). Intuitively I now think, that the restore command in the dockerfile should have overwritten that, but it seems not.

    Solutions

    Move dockerignore

    Move the docker ignore file into the project directory.

    Change build context

    Build the docker image from the project root and refer to files prefixed with the project location as Visual studio does by default.