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

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

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

Начать курс

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

В современной разработке программного обеспечения контейнеризация стала стандартом де-факто для создания, тестирования и развертывания приложений. Docker позволяет упаковать ваше C# приложение вместе со всеми его зависимостями в изолированную среду — контейнер. Это гарантирует, что приложение будет работать одинаково на любой машине: от ноутбука разработчика до production-сервера в облаке.

В этой статье мы подробно разберем, как контейнеризировать .NET приложения с помощью Docker. Вы узнаете, как создавать эффективные Dockerfile, использовать многоступенчатую сборку, работать с docker-compose для многоконтейнерных приложений и следовать лучшим практикам.

Что такое Docker и зачем он нужен C# разработчику?

Docker — это платформа для разработки, доставки и запуска приложений в контейнерах. Контейнер — это легковесный, автономный, исполняемый пакет, который содержит все необходимое для работы приложения: код, среду выполнения (runtime), системные инструменты, библиотеки и настройки.

Для C# разработчика Docker дает следующие преимущества:

  • Изоляция окружения — больше не нужно настраивать окружение на каждой машине. Все зависимости фиксируются в образе.
  • Унификация — приложение работает одинаково на Windows, Linux и macOS.
  • Масштабируемость — легко запускать несколько экземпляров приложения для обработки нагрузки.
  • CI/CD интеграция — контейнеры идеально подходят для автоматических пайплайнов сборки и развертывания.
  • Микросервисная архитектура — каждый сервис можно упаковать в отдельный контейнер.

Важно отметить, что .NET Core (и более новые .NET 5/6/7/8) являются кроссплатформенными и отлично работают в Linux-контейнерах, которые являются стандартом для Docker. .NET Framework приложения требуют Windows-контейнеров, что накладывает определенные ограничения.

Создание Dockerfile для .NET приложения

Основной артефакт для контейнеризации — это файл Dockerfile. Он содержит инструкции для сборки образа вашего приложения. Рассмотрим пример для типичного ASP.NET Core Web API.

Создайте файл Dockerfile в корне вашего проекта:

# Этап 1: Сборка приложения
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src

# Копируем файл проекта и восстанавливаем зависимости
COPY ["MyApp/MyApp.csproj", "MyApp/"]
RUN dotnet restore "MyApp/MyApp.csproj"

# Копируем весь исходный код и собираем приложение
COPY . .
WORKDIR "/src/MyApp"
RUN dotnet build "MyApp.csproj" -c Release -o /app/build

# Этап 2: Публикация приложения
FROM build AS publish
RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish /p:UseAppHost=false

# Этап 3: Финальный образ для запуска
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
EXPOSE 80
EXPOSE 443

# Копируем опубликованные файлы из этапа publish
COPY --from=publish /app/publish .

# Устанавливаем пользователя без прав root для безопасности
USER app

ENTRYPOINT ["dotnet", "MyApp.dll"]

Разбор инструкций:

  • FROM ... AS build — используем SDK-образ для сборки. Это "строительный" этап.
  • WORKDIR — задает рабочую директорию.
  • COPY — копирует файлы из хост-системы в образ.
  • RUN dotnet restore — восстанавливает NuGet-пакеты.
  • RUN dotnet build — компилирует проект.
  • FROM ... AS publish — второй этап для публикации (часто объединяют с build).
  • FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final — финальный образ, содержащий только ASP.NET Core runtime. Он намного легче SDK-образа.
  • COPY --from=publish — копирует результат сборки из предыдущего этапа.
  • USER app — запускает приложение от непривилегированного пользователя (безопасность).
  • ENTRYPOINT — команда, которая выполняется при старте контейнера.

Многоступенчатая сборка (multi-stage build) — ключевая практика. Она позволяет держать финальный образ минимальным по размеру, так как в него не попадают SDK, компиляторы и временные файлы.

Сборка и запуск контейнера

После создания Dockerfile, соберите образ и запустите контейнер:

# Сборка образа с тегом myapp:latest
docker build -t myapp:latest .

# Запуск контейнера в фоновом режиме
docker run -d -p 5000:80 --name myapp-container myapp:latest

# Проверка, что приложение работает
curl http://localhost:5000

Флаг -p 5000:80 пробрасывает порт 5000 на хост-машине на порт 80 внутри контейнера. Если ваше приложение использует порт 443 (HTTPS), добавьте соответствующий маппинг.

Docker Compose: управление многоконтейнерными приложениями

В реальных проектах редко бывает только один сервис. Часто требуется база данных, кэш (Redis), очередь сообщений и т.д. Docker Compose позволяет описать всю инфраструктуру в одном YAML-файле.

Создайте файл docker-compose.yml:

version: '3.8'

services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "5000:80"
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ConnectionStrings__DefaultConnection=Server=db;Database=MyAppDb;User=sa;Password=Your_password123;
    depends_on:
      - db

  db:
    image: mcr.microsoft.com/mssql/server:2022-latest
    environment:
      - ACCEPT_EULA=Y
      - SA_PASSWORD=Your_password123
    ports:
      - "1433:1433"
    volumes:
      - sql_data:/var/opt/mssql

volumes:
  sql_data:

Объяснение: