Как объединить фронтенд с бэкендом и не сломать веб-приложение

от автора

Привет! Меня зовут Артём Шумейко, я 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-ключа.

Окно с созданием 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.

Собираем все образы и добавляем их в контейнеры Docker:

docker compose up --build

Адрес бэкенда и фронтенда скрыты от конечного пользователя и мошенников. Напрямую с ними работать не получится, только через nginx. 

Заключение

Нам удалось соединить фронтенд с бэкендом в одном веб-приложении и развернуть его на облачном сервере. Оставляю код на GitHub и видеоверсию инструкции, чтобы вы легко могли повторить все шаги.


ссылка на оригинал статьи https://habr.com/ru/articles/836228/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *