使用 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"]
我需要使用 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"]