Настройка мультиконтейнерной среды в Visual Studio Code

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

Решением этой проблемы является разработка каждой из этих служб в отдельном контейнере. Visual Studio Code (VS Code) дает нам возможность не только запускать несколько наших сервисов, но также легко подключаться к каждому из них и использовать VS Code как наш инструмент разработки в различных контейнерах.

Давайте посмотрим, как это может быть реализовано. Взяв эту статью за основу, мы можем расширить те же концепции и построить нашу мультиконтейнерную среду.

Предполагая, что наша архитектура состоит из следующих трех сервисов:

  1. Фронтенд на основе PyWebIO
  2. Средний уровень, API на основе fastApi
  3. Бэкэнд, экземпляр Redis

Структура папок в моей папке разработки, названная в данном случае multicontainersetup , будет выглядеть следующим образом:

C:\DEV\MULTICONTAINERSETUP
├───api
├───frontend
└───redis

Чтобы VS Code распознал другую папку как «Remote-Folder», то есть папку, которую следует открыть в контейнере Docker, нам нужно создать папку .devcontainer в каждой подпапке. Взяв за основу файлы, описанные в ранее упомянутой статье, мы можем затем настроить конфигурацию каждой папки по мере необходимости.
Поскольку интерфейс и API будут разрабатываться на Python, мы можем использовать один и тот же Dockerfile для них обоих.

Этот Dockerfile необходимо скопировать в папку .devcontainer папки Frontendи API .

Файл devcontainer.json необходимо изменить, чтобы использовать файл Docker Compose, чтобы VS Code мог одновременно запускать несколько контейнеров Docker. Прежде чем я опишу файлы devcontainer.json, давайте быстро взглянем на файл docker-compose.yml.
Файл docker-compose.yml должен быть помещен в корневую папку нашего проекта, в данном случае multicontainersetup.

Каждая служба, за исключением службы redis , о которой я объясню позже, будет следовать одному и тому же шаблону, для frontend в части службы в файле docker-compose.yml конфигурация будет выглядеть следующим образом:

frontend:
image: frontend
tty: true
build:
context: ./frontend/.devcontainer
dockerfile: ./Dockerfile
volumes:
- .:/workspace:cached
depends_on:
- api
- redisserver
ports:
- "8000:8000"
networks:
- myNetwork

Более пристальный взгляд показывает, что мы описываем службу с именем frontend, первой строкой кода выше, и что она построена на основе Dockerfile в нашей папке frontend/.devcontainer:

context: ./frontend/.devcontainer
dockerfile: ./Dockerfile

Мы также делаем этот контейнер зависимым от нашей службы api и службы redisserver, так что оба контейнера будут запущены, как только мы запустим контейнер frontend. Я также открываю порт «8000», чтобы я мог получить доступ к frontend с моего хост-компьютера, как только я его разработаю.

ports:
- "8000:8000"

Используя тот же формат, api service будет выглядеть так:

api:
image: api
tty: true
build:
context: ./api/.devcontainer
dockerfile: ./Dockerfile
volumes:
- .:/workspace:cached
networks:
- myNetwork

Обратите внимание, что я подключил обе службы к сети с именем myNetwork.

Поскольку я планирую использовать API только в этой сети Docker, я не открываю никаких портов для хост-компьютера.

Часть конфигурации сети в файле docker-compose.yml выглядит так и будет в самом конце конфигурации.

networks:
myNetwork:
driver: bridge

Теперь перейдем к redisserver service, который будет нашим бэкендом. Поскольку мы не планируем вести разработку внутри этого контейнера, мы можем настроить этот контейнер без папки .devcontainer и файлов Dockerfile и devcontainer.json.

Не буду вдаваться в подробности конфигурации для контейнера redis, у меня работает следующая конфигурация :)

redissever:
image: redisserver
tty: true
build:
context: ./redis/
dockerfile: ./Dockerfile
volumes:
- .:/workspace:cached
- ./redis/redis-data:/data
ports:
- "6379:6379"
command:
# Save if 100 keys are added in every 10 seconds
- "--save 10 100"
networks:
- myNetwork

Это полный файл docker-compose.yml, который я использую.

Файлы devcontainer.json для двух служб очень похожи, но относятся к их соответствующему образу в файле docker-compose.yml.
Следующая часть должна быть настроена для каждого контейнера; это конкретная часть для frontend service:

"name": "frontend",
"dockerComposeFile": "../../docker-compose.yml",
"workspaceFolder": "/workspace/frontend",
"service": "frontend",

Нам нужно определить имя, файл docker-compose.yml, который VS Code будет использовать для создания нашей среды, папку, в которой будет храниться наш код workspaceFolder , и имя службы, на которую мы ссылаемся, в файле Docker Compose.

Два полных файла с конфигурациями для линтера Python:

Чтобы завершить настройку, нам нужно создать файлы requirements.txt для каждой службы. Один для внешнего интерфейса имеет следующий контент, так как мой внешний интерфейс будет основан на PyWebIO:

pylint
pycodestyle
black
requests
pywebio

И контент для службы API будет следующим:

pylint
pycodestyle
black
fastapi
uvicorn[standard]
redis

API будет создан с использованием fastapi и uvicorn будет использоваться для размещения API. Я также устанавливаю модуль redis Python для доступа к базе данных Redis.

Полная структура папок, включая файлы, должна быть такой

C:\DEV\MULTICONTAINERSETUP
│   docker-compose.yml
│   
├───api
│   └───.devcontainer
│           devcontainer.json
│           Dockerfile
│           requirements.txt
│           
├───frontend
│   └───.devcontainer
│           devcontainer.json
│           Dockerfile
│           requirements.txt
│           
└───redis

Используя CTRL+SHIFT+P или F1 для доступа к палитре команд VS Code, мы выбираем следующую команду

Remote-containers: Open Folder in Container

В следующем окне мы выбираем либо папку API, либо папку внешнего интерфейса, и vs code запустит три контейнера, если все прошло нормально, нам будет представлен терминал внутри контейнера, и все три контейнера будут запущены.