
Привет! Меня зовут Артём Шумейко, я Python-разработчик и создатель одноименного канала на YouTube. Представьте: у вас есть проект с фронтенд- и бэкенд-частью. Первый работает на одном порту и отображает данные, после — передает бэкенду. Второй работает на другом порту, принимает и обрабатывает эти данные, после чего возвращает ответ. Обычно сайты находятся на едином домене с фронтендом и бэкендом, а здесь — на двух отдельных.
Будучи новичком я не понимал, как объединить фронтенд и бэкенд. Думал, нужно подключать два домена и неведомым образом их «подружить». Но все оказалось намного проще. В тексте поделюсь подробной инструкцией и покажу, как задеплоить проект на облачный сервер.
О проекте
В инструкции не будем писать веб-приложение с нуля — возьмем готовый проект, который состоит из 30-40 строк кода. Фронтенд будет отображать данные с бэкенда: картинки и текст.
from fastapi import FastAPI import random @app.get("/items") def get_items(): items = [ { "id": 1, "name": "Docker", "img": "https://static-00.iconduck.com/assets.00/docker-icon-2048x2048-5mc7mvtn.png", }, { "id": 2, "name": "Nginx", "img": "https://www.svgrepo.com/show/373924/nginx.svg", }, { "id": 3, "name": "GitHub", "img": "https://cdn-icons-png.flaticon.com/512/25/25231.png", }, ] random.shuffle(items) return items
Весь проект локально запущен в двух терминалах. В первом — бэкенд с портом 8000, во втором — фронтенд с портом 5173. По сути, это два разных сервера, которые нужно соединить.
Чтобы объединить фронтенд и бэкенд, есть две стратегии. Первый способ — это реверс-прокси(обратный прокси), при котором мы не создаем домен. В нем разворачиваем фронтенд на основной сайт, а бэкенд — на адрес/API. Второй — это использование обратного прокси через создание поддомена. В нем создаем еще один домен к основному, например api.mysite.ru, чтобы разделить сайты. В тексте будем использовать обратный прокси без поддомена.
Настройка Docker-файла
Бэкенд
Нужно написать два простых Docker-файла, чтобы перенести данные в контейнеры. В образ Python добавляем slim, чтобы не занимать много места:
FROM python:3.11.9-slim
Перемещаем все файлы в локальную директорию и добавляем зависимости в requirements.txt. После копируем файлы в Docker-образ:
COPY requirements.txt requirements.txt RUN pip install -r requirements.txt COPY . .
Сначала устанавливаем файлы с зависимостями, которые редко меняются, и только потом остальные. Запускаем код:
CMD [ "python", "main.py" ]
Фронтенд
Копируем весь Docker-файл и добавляем его в папку frontend. В нем будем использовать не Python, а JavaScript и Node.js.
Указываем последнюю версию ноды типа alpine и называем ее build:
FROM node:alpine as build
Здесь зависимости находятся не в папке requirements.txt, а в package.json. Копируем их и добавляем в файл:
COPY package.json package.json RUN npm install
После — копируем оставшиеся файлы:
COPY . . RUN npm run build
Фронтенд поддерживает только статические файлы: JavaScript, HTML и CSS. Чтобы забрать их из контейнера, запускаем nginx прямо в коде:
FROM nginx: stable-alpine
После команды npm build внутри Docker-образа появилась папка /dist. В ней хранятся созданные билды, а именно — статические файлы. Отправляем их в nginx:
COPY --from=build /dist /usr/share/nginx/html
Далее копируем nginx.conf в классическую директору nginx:
COPY --from=build nginx.conf /etc/nginx/conf.d/default.conf
Указываем порт, на котором будет работать nginx, через EXPOSE 3000, но можно выбрать другой:
EXPOSE 3000 CMD [ "nginx", "-g", "daemon off;" ]
Чтобы отдавать файлы index html, создаем nginx.conf:
server { listen 3000; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html =404; } include /etc/nginx/extra-conf.d/*.conf; }
Общая сборка приложения
Создаем файл docker-compose, чтобы управлять сразу несколькими контейнерами. Здесь используем контейнер бэкенда и фронтенда в YAML-формате.
services: backend: build: context: ./backend frontend: build: context: ./frontend
Перед контейнерами запускаем nginx из готового образа DockerHub:
services: nginx: image: nginx:stable-alpine ports: - "80:80" backend: build: context: ./backend frontend: build: context: ./frontend
Указываем стандартный порт HTTP — 80.
Далее нужно выполнить две задачи:
-
настроить приложение так, чтобы nginx запускался только после бэкенда и фронтенда;
-
добавить volumes, чтобы nginx видел файлы с локального сервера.
services: nginx: image: nginx:stable-alpine ports: - "80:80" volumes: - './nginx.conf:/etc/nginx/nginx.conf' depends_on: - backend - frontend
Соединяем все контейнеры в единую сеть и указываем зависимости:
networks: dev: services: nginx: image: nginx:stable-alpine ports: - "80:80" - "443:443" volumes: - './nginx.conf:/etc/nginx/nginx.conf' depends_on: - backend - frontend networks: - dev backend: build: context: ./backend networks: - dev frontend: build: context: ./frontend networks: - dev
Настройка конфигурации nginx
Используем готовый файл nginx.conf. Называем пользователя root, добавляем необходимое количество worker-нод и порт 80.
user root; worker_processes 1; events { } http { server { listen 80; } }
Указываем Location, чтобы при запуске выводить фронтенд на главную страницу. После — добавляем proxy_pass, чтобы проксировать запросы через nginx, и порт 3000, как на нашем сервере.
location / { proxy_pass http://frontend:3000/; }
Далее подключаем бэкенд и добавляем в Location /api/. Порт — 8000, поскольку контейнер с бэкендом использует именно его.
location /api/ { proxy_pass http://backend:8000/; }
Конфигурация nginx готова:
user root; worker_processes 1; events { } http { server { listen 80; location / { proxy_pass http://frontend:3000/; } location /api/ { proxy_pass http://backend:8000/; } } }
Создание облачного сервера
Переходим в панель управления Selectel и создаем новый сервер. Указываем имя, регион и операционную систему — в нашем случае Ubuntu 24.04 LTS 64-bit. Для работы сайта подойдет минимальная конфигурация:
-
1 CPU,
-
1 ГБ RAM,
-
10 ГБ SSD,
-
публичный IP-адрес.
Далее добавляем SSH-ключ. Указываем имя и копируем команду для терминала. После получаем публичный ключ и добавляем его в окно создания.
Теперь можно автоматически подключаться к серверу без использования пароля, с помощью команды ssh root@<IP-адрес сервера>. Нажимаем Создать сервер.
Создание репозитория
Создаем новый репозиторий для хранения кодовой базы. Если проект не конфиденциален и вы хотите клонировать его на сервер без дополнительной авторизации, сделайте репозиторий публичным. Далее — переходим в терминал (предварительно не забудьте подключиться к серверу) и клонируем репозиторий с помощью команды git clone <адрес репозитория>.
Поскольку у нас около 20 файлов, создаем файл .gitignore. Туда добавляем файлы с зависимостями — venv и node-modules. Пишем initial commit, чтобы отправить их в Git.
venv/ node_modules/
Переходим в терПереходим в терминал и обновляем пакеты, чтобы установить Git. Создаем клон и скачиваем код по HTTPS с GitHub. На выходе получаем папку test-deploy-site, в которой находятся все файлы.
Деплой веб-приложения на сервер
Теперь нужно установить Docker. Используем готовый код — копируем и добавляем его в терминал.
Собираем все образы и добавляем их в контейнеры Docker:
docker compose up --build
Адрес бэкенда и фронтенда скрыты от конечного пользователя и мошенников. Напрямую с ними работать не получится, только через nginx.
Заключение
Нам удалось соединить фронтенд с бэкендом в одном веб-приложении и развернуть его на облачном сервере. Оставляю код на GitHub и видеоверсию инструкции, чтобы вы легко могли повторить все шаги.
ссылка на оригинал статьи https://habr.com/ru/articles/836228/
Добавить комментарий