Docker и C#: контейнеризация .NET приложений с нуля

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: зачем контейнеризировать 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 и свяжет их

Блоги

Рекомендаций по книгам