使用 src-test 目录布局容器化 ASP.NET 核心 API

Containerize ASP.NET Core API with src-test directory layout

我需要使用 Docker 将 ASP.NET Core 6.0 Web API 容器化。项目可以在我的这个GitHub Repo

中找到

项目结构如下:

───PlaygroundApiDockerized
    │
    ├───src
    │   ├───Playground.API
    |   |   ├───Dockerfile
    |   |   └───Playground.API.csproj
    |   |   
    │   └───Playground.Core
    |       └───Playground.Core.csproj
    │   
    ├───test
    │   ├───Playground.Tests
    │       └───Playground.Tests.csproj
    │
    ├───Playground.sln
    └───docker-compose.yml

API 项目依赖于一个名为 Playground.Core 的简单 C# class 库,并且有一个 Dockerfile.

Docker文件的内容:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["src/Playground.API/Playground.API.csproj", "Playground.API/"]
COPY ["src/Playground.Core/Playground.Core.csproj", "Playground.Core/"]
RUN dotnet restore "src/Playground.API/Playground.API.csproj"
COPY . .
WORKDIR "/src/Playground.API"
RUN dotnet build "Playground.API.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "Playground.API.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Playground.API.dll"]

docker-compose 文件如下所示:

version: '3.7'

services:
  playground-api:
    build:
      context: ./
      dockerfile: src/Playground.API/Dockerfile
    restart: always
    ports:
      - "7987:80"

我的预期是,当在解决方案根目录中执行docker-compose up命令时,API启动。

但是该命令导致以下错误。

我了解到执行命令的当前工作目录是docker-compose.yml中指定的上下文目录。在我的示例中,上下文是解决方案根。我根本不知道如何在 Dockerfile 中指定路径。有人知道吗?

Creating network "playgroundapidockerized_default" with the default driver
Building playground-api
[+] Building 2.2s (11/18)
 => [internal] load build definition from Dockerfile                                                               0.0s
 => => transferring dockerfile: 720B                                                                               0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [internal] load metadata for mcr.microsoft.com/dotnet/sdk:6.0                                                  0.8s
 => [internal] load metadata for mcr.microsoft.com/dotnet/aspnet:6.0                                               0.0s
 => [internal] load build context                                                                                  0.3s
 => => transferring context: 13.35MB                                                                               0.2s
 => [base 1/2] FROM mcr.microsoft.com/dotnet/aspnet:6.0                                                            0.0s
 => [build 1/8] FROM mcr.microsoft.com/dotnet/sdk:6.0@sha256:fde93347d1cc74a03f1804f113ce85add00c6f0af15881181165  0.0s
 => CACHED [build 2/8] WORKDIR /src                                                                                0.0s
 => [build 3/8] COPY [src/Playground.API/Playground.API.csproj, Playground.API/]                                   0.1s
 => [build 4/8] COPY [src/Playground.Core/Playground.Core.csproj, Playground.Core/]                                0.0s
 => ERROR [build 5/8] RUN dotnet restore "src/Playground.API/Playground.API.csproj"                                0.9s
------
 > [build 5/8] RUN dotnet restore "src/Playground.API/Playground.API.csproj":
#13 0.814 MSBUILD : error MSB1009: Project file does not exist.
#13 0.814 Switch: src/Playground.API/Playground.API.csproj
------
executor failed running [/bin/sh -c dotnet restore "src/Playground.API/Playground.API.csproj"]: exit code: 1
ERROR: Service 'playground-api' failed to build : Build failed

当您复制项目文件时,图像中的当前目录是 /src,您将其复制到 Playground.API/,因此项目文件最终具有绝对路径 /src/Playground.API/Playground.API.csproj

然后 运行 dotnet restore 时,您使用相对路径 src/Playground.API/Playground.API.csproj。所以它会寻找不存在的 /src/src/Playground.API/Playground.API.csproj

稍后当您使用 COPY . . 复制所有文件时,您会从主机获得目录结构,所以现在您的文件变为 /src/src/Playground.API/Playground.API.csproj 等。此时您有 2 个项目文件副本.一个在 /src/Playground.API 一个在 /src/src/Playground.API.

我认为最好的办法是将主机目录结构保留在工作目录下,即 /src/src/...。我会将工作目录重命名为 /src 以外的名称以避免混淆。像这样

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /app
COPY ["src/Playground.API/Playground.API.csproj", "src/Playground.API/"]
COPY ["src/Playground.Core/Playground.Core.csproj", "src/Playground.Core/"]
RUN dotnet restore "src/Playground.API/Playground.API.csproj"
COPY . .
WORKDIR "/app/src/Playground.API"
RUN dotnet build "Playground.API.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "Playground.API.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Playground.API.dll"]