Знакомство с .devcontainer
Вступление
Знаете ли вы, что существует спецификация «Development Container» которая позволяет использовать контейнеры как полноценную среду разработки.
Такие IDE как Visual Studio Code (VSCode) или IDE от JetBrains поддерживают эту спецификацию.
Я работаю в Visual Studio Code (VSCode), поэтому хотел бы продемонстрировать вам как легко настроить такую среду для работы с вашим проектом.
Запускать среду разработки в контейнере полезно хотя бы для того, чтобы защитить вашу хост систему от запуска потенциально вредоносных сценариев, например, из установленных пакетов. Development Container сильно упрощает настройку и запуск контейнеров за счет интеграции с IDE.
И хоть IDE имеют мастер настройки, с которым вы можете ознакомиться самостоятельно (загляните в Command Palette и введите там >Dev Containers), я всё же рассмотрю в этой короткой статье конкретный кейс.
Дано приложение Next.js, которое в свою очередь использует базу данных Redis.
Необходимо чтобы VSCode запускал для нас среду "под ключ" и устанавливал всё необходимое для разработки. Опционально мы еще желаем, чтобы наше приложение автоматически запускалось в режиме разработки, который будет собирать его каждый раз, когда меняется код.
Настройка
Вам понадобится наличие Docker на вашем хосте и установленный плагин Dev Containers в VSCode. Возможно он у уже предустановлен.
1️⃣ Создадим папку .devcontainer в корне проекта
2️⃣ Создадим файл .devcontainer/devcontainer.json
Здесь мы опишем нашу среду, а также укажем имя основного сервиса который чуть ниже мы опишем в docker-compose.yml. Полная спецификация devcontainer.json доступна здесь.
{ "name": "NextJS + Redis", "dockerComposeFile": "docker-compose.yml", "service": "next", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", "forwardPorts": [ 3000 ], "onCreateCommand": "[ ! -f .env ] && cp .env.example .env || true",, "postStartCommand": "npm install --include=dev && npm run dev", "customizations": { "vscode": { "extensions": [ "unifiedjs.vscode-mdx", "esbenp.prettier-vscode", "ms-azuretools.vscode-docker", "cweijan.vscode-redis-client", "bradlc.vscode-tailwindcss", "Gruntfuggly.todo-tree" ] } } }
- onCreateCommand – позволяет нам выполнить операцию при создании контейнера. Мы создаем файл .env копируя .env.example если .env еще не создан. Это действие создаст файл именно на хосте в папке проекта, и сэкономит время тех, кто впервые склонирует наш проект.
- postStartCommand – после того как всё запустится, мы можем установить зависимости. Для демонстрации я также запускаю приложение в dev режиме. Это совсем не обязательно делать, вы можете выполнять команды типа npm run dev в терминале в ручную.
- customizations.vscode.extensions – это набор расширений которые будут добавлены в среду VSCode. От проекта к проекту необходимые расширения могут отличаться и благодаря контейнеризации в VSCode не будет запущено лишних плагинов. Например в этом проекте я использую cweijan.vscode-redis-client чтобы просматривать базу Redis.
3️⃣ Создадим файл .devcontainer/docker-compose.yml
version: "3.8" services: next: build: context: .. dockerfile: .devcontainer/Dockerfile volumes: - ../..:/workspaces:cached network_mode: service:redis redis: image: redis:latest
Оба контейнера будут работать в одной сети, что позволит обращаться к хосту redis из контейнера next.
4️⃣ Создадим файл .devcontainer/Dockerfile
FROM mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm RUN apt-get update && apt-get install -y iputils-ping
В Dockerfile мы подготавливаем образ среды приложения.
Не стоит выполнять тут установку зависимостей или создание, например, .env файла. Мы выполняем эти операции в .devcontainer/devcontainer.json не случайно. Потому что если мы это сделаем в Dockerfile, то при монтировании папки все наши инсталяции, по идее, канут в Лету.
В итоге у нас есть папка .devcontainer в корне проекта и три файла в ней: devcontainer.json, docker-compose.yml, Dockerfile. Проверьте.
5️⃣ Запустим нашу среду разработки.
VSCode по умолчанию сам будет предлагать вам запустить среду из .devcontainer
Если этого не произошло, можно запустить Comman Pallete (На Mac: ⌘ + SHIFT + P) и ввести, например ">Dev Containers: Rebuild and Reopen in Container"
При первом запуске понадобится время чтобы образы и контейнеры собрались.
После чего вы увидите, что приложение запустилось. В моём случае это выглядит так:
Убедившись, что приложение открывается по адресу http://localhost:3000, вы можете остановить эту задачу в терминале с помощью CTRL + C.
Запустить ваше приложение повторно будет легко, используйте терминал VSCode. Все сеансы терминала будут запускаться внутри контейнера next и изолировано от хост-системы.
Выйти из этого режима тоже просто. Вам нужно снова открыть папку "локально". Введите в Command Palette: >Dev Containers: Reopen Folder Locally
Еще скриншоты
Возможные проблемы
Я несколько раз сталкивался с ситуацией когда из-за незавершенного Docker контейнера среда могла не запуститься. Решается эта проблема ручной остановкой контейнеров. Благо, контейнеры имеют достаточно ясный нейминг.