Как создать Dockerfile для приложения на ASP.NET, имеющего данную архитектуру?

В вашем описании архитектуры проекта присутствует структура, состоящая из двух основных компонентов: server_app (на ASP.NET) и client_app (на React). Внутри server_app имеется несколько проектов: Presentation, Application, Domain и Infrastructure, где каждый проект зависит от предыдущего. Вы упоминаете, что возникают проблемы с зависимостями, особенно когда Infrastructure обращается к NuGet пакетам из Application. 

Проблема заключается в том, что все работает корректно вне Docker, но при попытке сборки в Docker вы получаете ошибку: `ERROR [server_app build 9/9] RUN dotnet publish server_app.Presentation/server_app.Presentation.csproj -c Development -o /publish`. 

Вы также предоставили ссылку на репозиторий GitHub для более детального изучения проблемы. Правильно ли я понимаю, что ваша проблема связана не только с Docker, но и с особенностями архитектуры вашего проекта? Буду признателен за любой конструктивный ответ.
  • 28 января 2025 г. 19:04
Ответы на вопрос 2
Для создания Dockerfile для приложения на ASP.NET, состоящего из нескольких проектов, включая `Presentation`, `Application`, `Domain` и `Infrastructure`, важно учитывать, что все проекты должны быть собраны и правильно упакованы в одном образе. Ваша проблема может возникнуть из-за того, что Docker не может найти некоторые зависимости во время сборки, так как они могут быть неправильно настроены в Docker окружении.

Вот пример Dockerfile, который может помочь вам:

```Dockerfile
# Указываем базовый образ для сборки
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env
WORKDIR /app

# Копируем csproj файлы и восстанавливаем зависимости
COPY server_app/*.sln ./
COPY server_app/Presentation/*.csproj ./server_app/Presentation/
COPY server_app/Application/*.csproj ./server_app/Application/
COPY server_app/Domain/*.csproj ./server_app/Domain/
COPY server_app/Infrastructure/*.csproj ./server_app/Infrastructure/
RUN dotnet restore

# Копируем остальные файлы проекта и собираем
COPY server_app/ ./
RUN dotnet publish server_app.Presentation/server_app.Presentation.csproj -c Release -o out

# Создаем образ для запуска приложения
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app
COPY --from=build-env /app/out ./

# Указываем команду для запуска приложения
ENTRYPOINT ["dotnet", "server_app.Presentation.dll"]
```

### Объяснение Dockerfile

1. **Базовые образы**: Мы используем два образа: `sdk` для сборки и `aspnet` для выполнения приложения.

2. **Рабочая директория**: Установка рабочей директории в `/app`.

3. **Копирование файлов**: Сначала копируем файлы проекта (слой `*.csproj`), чтобы восстановить зависимости. Это позволяет Docker кэшировать этот шаг, если сами файлы проекта не менялись, и не выполнять восстановление зависимостей каждый раз при изменении кода.

4. **Восстановление зависимостей**: Выполняется команда `dotnet restore`, чтобы загрузить NuGet пакеты.

5. **Копирование кода**: Копируем весь код приложения в контейнер.

6. **Сборка и публикация**: Используем `dotnet publish` для компиляции и создания предварительно собранного приложения.

7. **Финальный образ**: Создаётся финальный образ, который содержит только необходимые для выполнения файлы.

8. **Исполнение приложения**: Через `ENTRYPOINT` указываем, что запускать при старте контейнера.

### Дополнительные советы

1. **Проверка зависимостей**: Убедитесь, что все NuGet пакеты указаны и доступны в `*.csproj` файлах.

2. **Модули и dll**: Если у вас есть специфические зависимости между проектами, убедитесь, что это правильно указано в ваших `csproj`, чтобы все необходимые dll были скомпилированы и скопированы.

3. **Запуск**: Для запуска вашего контейнера используйте команду:

   ```bash
   docker build -t your-image-name .
   docker run -d -p 8080:80 your-image-name
   ```

### Проект React

Если вам нужно собрать и запустить клиентское приложение на React в Docker, можете создать отдельный Dockerfile для клиентской части или добавить шаги для сборки React приложения в этот же Dockerfile.

Если у вас возникнут дополнительные проблемы с зависимостями в Docker, не забудьте проверить логи для более точной информации о произошедшей ошибке.
У вас проблема в зависимостях 
Даже по логу вам говорится:
/app/server_app.Domain/Model/Queries/ProductCategoryCreateQuery.cs(3,17): error CS0234: The type or namespace name 'AspNetCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?) [/app/server_app.Domain/server_app.Domain.csproj]


А конкретно проблема в этом
server_app/server_app.Domain/server_app.Domain.csproj
<ItemGroup>
        <Reference Include="FluentValidation">
            <HintPath>..\..\..\..\.nuget\packages\fluentvalidation\11.11.0\lib\net8.0\FluentValidation.dll</HintPath>
        </Reference>
        <Reference Include="Microsoft.AspNetCore.Http.Abstractions">
            <HintPath>..\..\..\..\.nuget\packages\microsoft.aspnetcore.app.ref\8.0.8\ref\net8.0\Microsoft.AspNetCore.Http.Abstractions.dll</HintPath>
        </Reference>
        <Reference Include="Microsoft.AspNetCore.Http.Features">
            <HintPath>..\..\..\..\.nuget\packages\microsoft.aspnetcore.app.ref\8.0.8\ref\net8.0\Microsoft.AspNetCore.Http.Features.dll</HintPath>
        </Reference>
        <Reference Include="Microsoft.AspNetCore.Mvc.Abstractions">
            <HintPath>..\..\..\..\.nuget\packages\microsoft.aspnetcore.app.ref\8.0.8\ref\net8.0\Microsoft.AspNetCore.Mvc.Abstractions.dll</HintPath>
        </Reference>
        <Reference Include="Microsoft.AspNetCore.Mvc.Core">
            <HintPath>..\..\..\..\.nuget\packages\microsoft.aspnetcore.app.ref\8.0.8\ref\net8.0\Microsoft.AspNetCore.Mvc.Core.dll</HintPath>
        </Reference>
        <Reference Include="Microsoft.IdentityModel.Tokens">
            <HintPath>..\..\..\..\.nuget\packages\microsoft.identitymodel.tokens\7.1.2\lib\net8.0\Microsoft.IdentityModel.Tokens.dll</HintPath>
        </Reference>
        <Reference Include="Npgsql.EntityFrameworkCore.PostgreSQL">
          <HintPath>..\..\..\..\.nuget\packages\npgsql.entityframeworkcore.postgresql\9.0.2\lib\net8.0\Npgsql.EntityFrameworkCore.PostgreSQL.dll</HintPath>
        </Reference>
    </ItemGroup>


Вы буквально указали путь к конкретным dll на вашем компьютере, и из-за этого в докер они не попадают, а dotnet restore их просто игнорирует. Эти зависимости должны быть в общем списке, как в блоке ItemGroup ниже этого, но проблема на самом деле куда глобальнее.

Как я понимаю, вы только изучаете DDD, и сделали самую фатальную ошибку в дизайне, Domain не должен отвечать за БД, JWT, модели, DTO и тд. Domain должен концентрировать именно бизнес-сущности и бизнес-логику (Entities & Buisness Services). Application слой уже отвечает за сценарии использования приложения (CQRS или Use Cases, которые оперируют сущностями/сервисами из Domain, а для инфраструктурных моментов использует интерфейсы - dependency inversion). Инфраструктурный слой реализует интерфейсы из Application слоя, например, репозитории бд, http-клиенты и тд, соответственно в нём концентрируется вся работа с БД и другими внешними сервисами. Presentation слой отвечает за представления, это может быть ASP.NET Core API. В таком случае, здесь уже используются модели, JWT, вызов Use Cases из слоя Application, в общем всё, что касается предоставления API.

Это если очень коротко, тема довольно обширная и сложная.
Советую вам почитать:
Мартин Роберт - Чистая архитектура. Искусство разработки программного обеспечения
Эрик Эванс - Предметно-ориентированное проектирование (DDD). Структуризация сложных программных систем

Также именно для C# есть прекрасный пример проекта с использованием подходов CA и DDD, изучите его, необязательно делать всё под копирку, но полезным точно будет.

Удачи Вам!
Похожие вопросы