Введение: зачем контейнеризировать C# приложения?
Современная разработка на C# (.NET) редко обходится без Docker. Контейнеризация позволяет упаковать приложение вместе со всеми зависимостями, средой выполнения и конфигурациями в изолированный образ. Это решает проблему "на моей машине работает" и упрощает деплой на сервер, в облако или на локальную инфраструктуру.
В этой статье мы разберем, как создать Docker-образ для .NET приложения (ASP.NET Core или консольного), оптимизировать его размер, использовать docker-compose для связки с базой данных и настроить CI/CD. Все примеры кода написаны на C# и готовы к использованию.
1. Основы Docker для .NET разработчика
Docker — это платформа для запуска приложений в контейнерах. Контейнер содержит все необходимое: код, среду выполнения (runtime), библиотеки и настройки. Для .NET это особенно удобно, так как вам не нужно устанавливать .NET SDK на сервере — достаточно Docker.
1.1. Установка Docker
Скачайте и установите Docker Desktop с официального сайта. После установки проверьте версию:
docker --version
1.2. Структура проекта .NET
Предположим, у нас есть простое ASP.NET Core Web API приложение. Структура папок:
MyApp/
├── MyApp.csproj
├── Program.cs
├── Controllers/
│ └── WeatherController.cs
└── Dockerfile
2. Создание Dockerfile для .NET приложения
Dockerfile — это инструкция по сборке образа. Для .NET рекомендуется использовать многоступенчатую сборку (multi-stage build), чтобы разделить этапы сборки и выполнения. Это уменьшает итоговый размер образа.
2.1. Базовый Dockerfile
Создайте файл Dockerfile в корне проекта:
# Этап сборки
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyApp.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
# Этап выполнения
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 80
ENTRYPOINT ["dotnet", "MyApp.dll"]
Пояснения:
- FROM ... AS build — используем SDK для компиляции.
- COPY ["MyApp.csproj", "."] — копируем только файл проекта для кэширования restore.
- RUN dotnet restore — восстанавливаем NuGet-пакеты.
- RUN dotnet publish — собираем релизную версию.
- FROM ... AS runtime — используем минимальный aspnet образ.
- EXPOSE 80 — открываем порт 80.
- ENTRYPOINT — команда запуска приложения.
2.2. Сборка и запуск образа
Выполните команды в терминале из папки проекта:
docker build -t myapp:latest .
docker run -d -p 8080:80 --name myapp_container myapp:latest
Теперь приложение доступно по адресу http://localhost:8080.
3. Оптимизация Docker-образов для .NET
Большие образы замедляют деплой и потребляют ресурсы. Вот несколько практик для оптимизации:
3.1. Используйте .NET 8 (или новее)
Новые версии .NET имеют встроенную поддержку AOT (Ahead-of-Time) компиляции, что уменьшает размер runtime. Для ASP.NET Core используйте образ aspnet:8.0.
3.2. Минимизируйте слои
Каждая инструкция RUN, COPY создает слой. Объединяйте команды:
RUN apt-get update && apt-get install -y \
curl \
&& rm -rf /var/lib/apt/lists/*
3.3. Используйте .dockerignore
Создайте файл .dockerignore в корне проекта, чтобы исключить ненужные файлы:
bin/
obj/
.vs/
*.user
.git/
README.md
3.4. Пример оптимизированного Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyApp.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish --no-restore
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS runtime
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 80
ENTRYPOINT ["dotnet", "MyApp.dll"]
Образ alpine значительно меньше (около 100 МБ вместо 200 МБ).
4. Docker Compose: связка C# с базой данных
В реальных проектах приложение часто работает с PostgreSQL, SQL Server или Redis. Docker Compose позволяет запустить все сервисы одной командой.
4.1. Файл docker-compose.yml
Создайте файл docker-compose.yml в корне проекта:
version: '3.8'
services:
app:
build: .
ports:
- "5000:80"
environment:
- ConnectionStrings__DefaultConnection=Host=db;Database=mydb;Username=postgres;Password=secret
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: mydb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
4.2. Настройка строки подключения в C#
В appsettings.json или Program.cs используйте переменные окружения:
builder.Services.AddDbContext(options =>
options.UseNpgsql(
builder.Configuration.GetConnectionString("DefaultConnection")));
При запуске через Docker Compose строка подключения будет подставлена автоматически.
4.3. Запуск всех сервисов
docker-compose up -d
Эта команда соберет образ приложения, запустит PostgreSQL и свяжет их