Dockerfile для .NET-микросервисов: общий core-образ, multi-stage, как у нас
↑ 7.6 DevOps для бэкенд-разработчика · ← Предыдущая · → Следующая
Зачем это на собесе
Написать хороший Dockerfile для .NET — типичное практическое задание.
Объяснение
Multi-stage сборка: тяжёлый SDK-образ для сборки, лёгкий runtime-образ для запуска.
# syntax=docker/dockerfile:1
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
# сначала только файлы проектов — кэш слоя restore
COPY Directory.Build.props Directory.Packages.props ./
COPY src/Orders.Api/Orders.Api.csproj src/Orders.Api/
COPY src/Orders.Domain/Orders.Domain.csproj src/Orders.Domain/
RUN --mount=type=cache,target=/root/.nuget/packages dotnet restore src/Orders.Api/Orders.Api.csproj
COPY src/ src/
RUN dotnet publish src/Orders.Api/Orders.Api.csproj -c Release -o /app --no-restore /p:UseAppHost=false
FROM mcr.microsoft.com/dotnet/aspnet:9.0-noble-chiseled AS final
WORKDIR /app
COPY --from=build /app .
USER $APP_UID # не root
ENV ASPNETCORE_HTTP_PORTS=8080
EXPOSE 8080
ENTRYPOINT ["dotnet", "Orders.Api.dll"]Общий базовый (core) образ: команда собирает свой образ на основе aspnet с часто нужным (корневые сертификаты, шрифты для генерации PDF, часовой пояс, локали, инструменты диагностики) и публикует в приватный registry. Сервисы наследуют его — единые обновления безопасности и меньше дублирования.
Практики:
.dockerignore(bin/,obj/,.git,node_modules).- Порядок слоёв от редко к часто меняющимся.
- Слои кэша NuGet (
--mount=type=cache). - Минимальные образы (chiseled/alpine), запуск не от root, read-only файловая система.
- Метки
org.opencontainers.image.*(версия, коммит). - Сканирование образа (Trivy, Grype).
- Встроенная публикация:
dotnet publish /t:PublishContainerбез Dockerfile.
Нюансы и подводные камни
- Кириллица в PDF без шрифтов в образе — квадраты.
alpine(musl) иногда несовместим с нативными библиотеками.- Секреты в
ARG/ENVостаются в слоях образа. - Большой контекст сборки замедляет
docker build. - Часовой пояс и локаль в контейнере: задавайте явно.
Практика
- Уменьшите образ сервиса с 800 МБ до ~100 МБ через multi-stage и chiseled.
- Проверьте кэширование слоёв: изменение кода не должно вызывать повторный restore.
- Просканируйте образ Trivy и устраните критические уязвимости.
Вопросы с ответами
Зачем multi-stage?
В финальный образ попадает только runtime и результат публикации, без SDK и исходников.
Зачем копировать csproj отдельно?
Чтобы слой
restoreкэшировался и не выполнялся при изменении только кода.