Среда разработки Entity Framework в Docker

С помощью команды git clone можно с легкостью загрузить рабочий код на компьютер. Однако создание и запуск локальной базы данных может оказаться серьезной проблемой. Часто нужно устанавливать одну из версий определенной платформы базы данных, а затем либо найти файлы snapshot и запустить сценарий, либо найти программиста, который ими ранее занимался. Все это достаточно сложно.

Контейнеры разработчика (dev containers) и Visual Studio Code позволяют упростить весь этот процесс и получить локальный доступ к базе данных, в том числе с помощью git clone.

Docker для настройки и хранения dev environments представляется чрезвычайно мощной концепцией. Это следующая эволюция «инфраструктуры как кода». По сути, Docker представляет собой «среду разработки как код» (dev environment as code). Определяющий среду код перемещается вместе с репозиторием, обновляется и меняется по мере роста проекта. Это означает, что среды разработки всегда синхронизируются и никогда не устаревают.

Рассмотрим, как можно настроить и инициализировать серверную базу данных в контейнере Docker так, чтобы новый разработчик в команде, выполнив git clone репозитория, сразу приступил к работе. Это избавляет от необходимости настраивать локальную базу данных.

Здесь можно найти код приведенного в статье примера.

Необходимые компоненты:

· Docker;

· Visual Studio Code;

· расширение Remote Containers для VSCode;

· терминал с запущенной оболочкой Bash;

· WSL (рекомендуется при работе в Windows, но не обязателен).

Первоначальная настройка

Начнем с пустого каталога. Открываем терминал.

mkdir database-docker-dev-env; \
cd database-docker-dev-env; \
code .

В пустом каталоге откроется VS Code. В нижнем левом углу будет указана рабочая среда. Эта функция позволит контролировать, где вы находитесь в данный момент. Сейчас мы остаемся на хосте, но не в среде Docker, а в WSL.

Мы получили пустую папку  —  полностью чистый лист. Dev-контейнеры можно настраивать и автоматически, нажав F1 для доступа в меню. Но сейчас мы будем использовать индивидуальную ручную настройку.

Это решение потребует два контейнера Docker.

  • Среда разработчика будет выполняться в одном контейнере со всеми обычными dev-зависимостями, такими как dotnet, vim и др.
  • В другом будет сервер базы данных. В этом примере запустим Postgres.

Для настройки взаимодействия используем Docker Compose. Чтобы определить папки и необходимые файлы, скопируйте и вставьте в терминал приведенный ниже код.

mkdir docker; \
cd docker; \
mkdir database; \
mkdir dev-env; \
touch docker-compose.yaml; \
cd dev-env; \
touch Dockerfile; \
cd ..; \
cd database; \
touch database.env;

Папки должны выглядеть подобным образом:

Настройка Docker

Сначала выполним все настройки Docker.

Контейнер среды разработки

Начнем с создания контейнера dev environment. Он будет основан на предоставляемом Microsoft стандартном контейнере C# с некоторыми дополнениями, которые позволят использовать Entity Framework Core в контейнере.

# [Choice] .NET version: 6.0, 5.0, 3.1, 6.0-bullseye, 5.0-bullseye, 3.1-bullseye, 6.0-focal, 5.0-focal, 3.1-focal

ARG VARIANT="6.0-focal"FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT}

# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
ARG NODE_VERSION="none"

RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi

# [Optional] Uncomment this section to install additional OS packages.
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends vim

RUN dotnet tool install -g dotnet-ef
ENV PATH $PATH:/root/.dotnet/tools

Представленный Dockerfile:

  • наследует .NET Core 6 из базового образа;
  • устанавливает Vim (не обязательно);
  • устанавливает инструменты командной строки Entity Framework Core;
  • добавляет инструменты CLI в переменную path.

В данном случае этого достаточно для создания проекта Entity Framework и взаимодействия с сервером базы данных с помощью инструментов командной строки.

Контейнер базы данных

Используем образ Postgres Docker как есть, поэтому не нужно писать отдельный Dockerfile для контейнера базы данных. Потребуется некоторая настройка, поэтому перейдите в database.env и добавьте следующую конфигурацию:

POSTGRES_USER=docker_user
POSTGRES_PASSWORD=password
POSTGRES_DB=blog_database

Docker Compose

Настройка Docker завершается увязыванием всех этих компонентов с файлом Compose. Выглядеть это должно подобным образом:

version: '3'
services:
database:
container_name: postgres
image: "postgres"
env_file:
- database/database.env
volumes:
- blog-database-data:/var/lib/postgresql/data/
dev-env:
container_name: dev-env
build:
context: ./dev-env
volumes:
- "..:/workspace"
stdin_open: true # docker run -i
tty: true # docker run -t

volumes:
blog-database-data: null

На самом деле это просто развертывание контейнера Postgres и передача переменных env. Сохраняем данные базы в томе под названием blog-database-data.

Для контейнера dev-env это означает развертывание на основе настроенного ранее образа.

Проверка

На этом этапе проверим работоспособность. Вводим с клавиатуры:

cd .. \
docker compose up

Для начала убедимся, что в контейнерах Docker не возникло никаких проблем. Загляните в контейнер dev-env.

docker exec -it dev-env /bin/bash

Находясь в контейнере можно убедиться, что dotnet и dotnet-ef установлены правильно:

Выйдите с помощью exit из контейнера developer environment и загляните в Postgres.

docker exec -it postgres /bin/bash

Также убедитесь, что Postgres установлен и доступен.

Теперь можно выполнить exit для контейнеров Postgres и удалить их с помощью:

docker compose down

Контейнеры Dev в VSCode

Далее настроим VS Code. Возвращаемся в терминал и вставляем (в корневую папку проекта) код:

mkdir .devcontainer; \
cd .devcontainer; \
touch devcontainer.json;

В .devcontainer.json вставим:

{
"name": "C# (.NET)",
"dockerComposeFile": [
"../docker/docker-compose.yaml"
],
"service": "dev-env",
"workspaceFolder": "/workspace",
"settings": {},
"extensions": [
"ms-dotnettools.csharp",
"shardulm94.trailing-spaces",
"mikestead.dotenv",
],
}

Это все, что нужно для настройки Docker. Теперь нажмите F1 в VSCode и выберите “rebuild and reopen in container”.

В первый раз это займет некоторое время, но в последующие все происходит намного быстрее. После завершения загрузки в нижней части окна VSCode будет показано, что мы находимся в среде Docker.

Теперь при запуске терминала в VSCode видно, что он открылся в ранее настроенном контейнере среды.

Все, что касается Docker, готово. Осталось рассмотреть пример использования Entity Framework Core.

Пример Entity Framework

Создадим небольшой пример с Entity Framework и рассмотрим его взаимодействие с экземпляром Postgres. Используем терминал в VSCode, чтобы добавить новый проект .NET и установить пакеты, необходимые для entity framework.

dotnet new classlib --name Blog.Database; \
cd Blog.Database; \
dotnet add package Microsoft.EntityFrameworkCore; \
dotnet add package Microsoft.EntityFrameworkCore.Design; \
dotnet add package Microsoft.EntityFrameworkCore.Analyzers; \
dotnet add package Microsoft.EntityFrameworkCore.Relational; \
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL; \
touch BlogDbContext.cs; \
touch BlogPost.cs; \
rm Class1.cs;

Создадим очень простой пример базы данных Code First, вставив следующий код в BlogDbContext.cs.

using Blog.Database.Entities;
using Microsoft.EntityFrameworkCore;

namespace Blog.Database;

public class AppDbContext : DbContext
{
public DbSet<BlogPost> Posts { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseNpgsql("Host=postgres;Database=blog_database;Username=docker_user;Password=password");

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogPost>().HasData(
new BlogPost() { Id = 1, Title = "Doing Docker" },
new BlogPost() { Id = 2, Title = "Angular with Docker" },
new BlogPost() { Id = 3, Title = "Addicted to Docker - send help" }
);
}
}

И в BlogPost.cs:

namespace Blog.Database.Entities;
public class BlogPost
{
public int Id { get; set; }
public string Title { get; set; } = default!;
}

Теперь введите следующее в терминале VS Code:

dotnet-ef migrations add initial; \
dotnet-ef database update;

Тестовые данные будут отправлены в базу данных Postgres, которая работает в другом контейнере Docker. Это можно проверить.

Обратите внимание, в среде Docker существует ограничение  —  получить доступ к другим контейнерам Docker не получится. Это возможно только на хосте, поэтому нужно использовать другой, неиспользуемый в VSCode терминал. В терминале VSCode вы увидите, что Docker недоступен.

Вернитесь в свой терминал (не тот, что в VSCode!).

docker exec -it postgres /bin/bash

Вы попадете в контейнер Docker, где работает Postgres. Введите следующее:

psql --host=database --username=docker_user --dbname=blog_database

При появлении запроса введите пароль (подсказка  —  это будет password).

Обратите внимание, что информация совпадает с установленными ранее данными в database.env. Далее проверяем и убеждаемся, что таблицы созданы:

\d

Также можно показать перемещение тестовых данных:

select * from "Posts";

Подведем итоги.

Любой желающий может просто извлечь этот репозиторий, развернуть его и начать использовать приложение, не задумываясь о настройке базы данных.

В примере использован Postgres, но те же принципы применимы в большей или меньшей степени и к любой другой платформе баз данных, которую можно запускать в контейнере Docker.

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Andy Watt: Entity Framework Dev Environment in Docker

Предыдущая статья5 инструментов Chrome DevTools, упрощающих разработку
Следующая статьяАвтоматический мониторинг скорости API с помощью динамического тестирования