Настройка взаимодействия приложения на виртуальных машинах с сервисом Managed PostgreSQL
В этой лабораторной работе вы развернете сервис сокращенных ссылок и настроите защищенную схему взаимодействия FastAPI-приложения с сервисом Managed PostgreSQL.
Вы выполните развертывание виртуальной машины Ubuntu 22.04, настройку сетей и групп безопасности, создание кластера PostgreSQL, установку и конфигурирование приложения и публикацию API за Nginx с поддержкой Let’s Encrypt.
В результате вы получите надежную архитектуру: база данных доступна только по закрытому адресу, а доступ к приложению осуществляется по HTTPS.
Вы будете использовать следующие сервисы:
Виртуальная машина — виртуальная машина в облаке для размещения приложения.
Публичный IP-адрес — для доступа к сервису через интернет.
Managed PostgreSQL — управляемая база данных PostgreSQL.
VPC сеть — изолированная виртуальная сеть для создания безопасной инфраструктуры.
Бесплатный сервис nip.io для получения публичного доменного имени и сертификата. Вы также можете использовать собственное зарегистрированное доменное имя и SSL-сертификат для организации доступа.
Nginx — для проксирования запросов и организации защищённого HTTPS-доступа к приложению.
Let’s Encrypt — для автоматического получения бесплатного SSL-сертификата.
Шаги:
Перед началом работы
-
Если вы уже зарегистрированы, войдите под своей учетной записью.
1. Разверните ресурсы в облаке
Создайте виртуальную сеть со следующими параметрами:
В поле Название укажите название сети, например short-links-service-VPC.
Создайте подсеть:
В поле Название укажите short-link-service-subnet.
В поле Адрес укажите 10.10.1.0/24.
В поле VPC выберите short-links-service-VPC.
Создайте группу безопасности со следующими параметрами:
Укажите ту же зону доступности, что и для сети.
В поле Название укажите short-links-service.
Добавьте правила входящего трафика:
Протокол: TCP
Порт: 443
Тип источника: IP-адрес
Источник: 0.0.0.0/0
Протокол: TCP
Порт: 80
Тип источника: IP-адрес
Источник: 0.0.0.0/0
Добавьте правила исходящего трафика:
Протокол: Любой
Тип адресата: IP-адрес
Адресат: 0.0.0.0/0
Создайте бесплатную виртуальную машину со следующими параметрами:
В поле Название укажите название виртуальной машины, например short-links-service.
На вкладке Публичные выберите образ Ubuntu 22.04.
Назначьте публичный IP-адрес виртуальной машине — оставьте включенной опцию Подключить публичный IP. Для виртуальной машины будет арендован и назначен прямой публичный IP.
В поле Логин укажите имя пользователя виртуальной машины, например user1.
Выберите метод аутентификации — пароль.
В поле Имя хоста укажите уникальное имя устройства, по которому можно идентифицировать виртуальную машину в сети, например short-links-service.
Создайте кластер Managed PostgreSQL со следующими параметрами:
В поле Имя кластера укажите short-links-service.
В поле Название базы данных укажите default.
В поле Версия PostgreSQL выберите 16.
В поле Режим выберите Стандарт.
В поле Тип выберите Single.
В поле Подсеть выберите short-link-service-subnet.
Создайте пользователя:
В поле Имя пользователя укажите short_links.
Укажите пароль.
Создайте базу данных:
В поле Владелец выберите short_links.
Название базы данных: shortener_db.
Убедитесь, что в личном кабинете:
На странице сервиса «VPC»:
отображается сеть short-links-service-VPC;
в списке подсетей отображается short-link-service-subnet.
На странице сервиса «Группы безопасности»:
отображается группа безопасности short-links-service;
статус группы безопасности — «Создана».
На странице сервиса «Виртуальные машины»:
отображается виртуальная машина short-links-service;
статус виртуальной машины — «Запущена».
На странице сервиса «Managed PostgreSQL»:
отображается кластер short-links-service;
статус кластера — «Доступен».
2. Настройте окружение на виртуальной машине
На этом шаге вы настроите систему и основные сетевые параметры виртуальной машины, установите необходимые пакеты и подготовите ее к запуску FastAPI-приложения.
В личном кабинете перейдите к сервису «Виртуальные машины» и выберите машину short-links-service.
Активируйте сетевой интерфейс по инструкции:
sudo cloud-init cleansudo cloud-init initОбновите систему:
sudo apt update && sudo apt upgrade -yУстановите Python и базовые пакеты:
sudo apt install -y python3-venv build-essential nginx snapd ufw postgresql-clientsudo snap install core; sudo snap refresh coresudo snap install --classic certbotsudo ln -s /snap/bin/certbot /usr/bin/certbotНастройте файрвол:
sudo ufw allow OpenSSHsudo ufw allow 'Nginx Full'sudo ufw enableПроверьте установку Python, Nginx, postgresql-client, ufw:
python3 --versionnginx -vsudo ufw status
3. Разверните приложение
На этом шаге вы развернете FastAPI-приложение, подготовите файлы и подключите приложение к кластеру Managed PostgreSQL.
Создайте директорию для приложения:
cd /home/user1mkdir short-links-servicecd short-links-serviceСоздайте файл сервера:
nano server.pyВставьте следующий код:
from fastapi import FastAPI, HTTPException, Dependsfrom fastapi.responses import RedirectResponsefrom sqlalchemy import create_engine, Column, String, DateTime, Integerfrom sqlalchemy.orm import declarative_basefrom sqlalchemy.orm import sessionmaker, Sessionfrom pydantic import BaseModel, HttpUrlfrom datetime import datetimeimport osimport secretsimport stringfrom typing import Optionalfrom dotenv import load_dotenvload_dotenv()# Конфигурация базы данныхDATABASE_URL = os.getenv("DATABASE_URL", "postgresql://user:password@localhost:5432/shortener_db")engine = create_engine(DATABASE_URL)SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)Base = declarative_base()# Модель базы данныхclass URLModel(Base):__tablename__ = "urls"id = Column(Integer, primary_key=True, index=True)original_url = Column(String, nullable=False)short_code = Column(String, unique=True, index=True, nullable=False)created_at = Column(DateTime, default=datetime.utcnow)clicks = Column(Integer, default=0)# Создание таблицBase.metadata.create_all(bind=engine)# Pydantic моделиclass URLCreate(BaseModel):original_url: HttpUrlclass URLResponse(BaseModel):original_url: strshort_code: strshort_url: strcreated_at: datetimeclicks: intclass Config:from_attributes = True# FastAPI приложениеapp = FastAPI(title="URL Shortener API",description="API для создания коротких ссылок",version="1.0.0")# Dependency для получения сессии БДdef get_db():db = SessionLocal()try:yield dbfinally:db.close()# Функция для генерации короткого кодаdef generate_short_code(length: int = 6) -> str:"""Генерирует случайный короткий код из букв и цифр"""characters = string.ascii_letters + string.digitsreturn ''.join(secrets.choice(characters) for _ in range(length))# Эндпоинты@app.get("/health")async def health_check():"""Проверка здоровья приложения"""return {"status": "healthy", "timestamp": datetime.utcnow()}@app.get("/")async def root():return {"message": "URL Shortener API","version": "1.0.0","endpoints": {"create": "POST /shorten","redirect": "GET /{short_code}","stats": "GET /stats/{short_code}"}}@app.post("/shorten", response_model=URLResponse)async def create_short_url(url_data: URLCreate, db: Session = Depends(get_db)):"""Создание короткой ссылки"""# Проверяем, не существует ли уже такой URLexisting_url = db.query(URLModel).filter(URLModel.original_url == str(url_data.original_url)).first()if existing_url:base_url = os.getenv("BASE_URL", "https://yourdomain.com")return URLResponse(original_url=existing_url.original_url,short_code=existing_url.short_code,short_url=f"{base_url}/{existing_url.short_code}",created_at=existing_url.created_at,clicks=existing_url.clicks)# Генерируем уникальный короткий кодwhile True:short_code = generate_short_code()if not db.query(URLModel).filter(URLModel.short_code == short_code).first():break# Создаем запись в БДdb_url = URLModel(original_url=str(url_data.original_url),short_code=short_code)db.add(db_url)db.commit()db.refresh(db_url)base_url = os.getenv("BASE_URL", "https://yourdomain.com")return URLResponse(original_url=db_url.original_url,short_code=db_url.short_code,short_url=f"{base_url}/{db_url.short_code}",created_at=db_url.created_at,clicks=db_url.clicks)@app.get("/{short_code}")async def redirect_to_url(short_code: str, db: Session = Depends(get_db)):"""Перенаправление на оригинальный URL"""url_record = db.query(URLModel).filter(URLModel.short_code == short_code).first()if not url_record:raise HTTPException(status_code=404, detail="Ссылка не найдена")# Увеличиваем счетчик кликовurl_record.clicks += 1db.commit()return RedirectResponse(url=url_record.original_url, status_code=302)@app.get("/stats/{short_code}", response_model=URLResponse)async def get_url_stats(short_code: str, db: Session = Depends(get_db)):"""Получение статистики по короткой ссылке"""url_record = db.query(URLModel).filter(URLModel.short_code == short_code).first()if not url_record:raise HTTPException(status_code=404, detail="Ссылка не найдена")base_url = os.getenv("BASE_URL", "https://yourdomain.com")return URLResponse(original_url=url_record.original_url,short_code=url_record.short_code,short_url=f"{base_url}/{url_record.short_code}",created_at=url_record.created_at,clicks=url_record.clicks)if __name__ == "__main__":import uvicornuvicorn.run(app, host="0.0.0.0", port=8000)Создайте файл зависимостей:
nano requirements.txtСодержимое файла:
fastapi==0.104.1uvicorn[standard]==0.24.0sqlalchemy==2.0.23psycopg2-binary==2.9.9python-dotenv==1.0.0pydantic==2.5.0Создайте и активируйте виртуальное окружение:
python3 -m venv venvsource venv/bin/activateУстановите зависимости:
pip install -r requirements.txtДобавьте переменные среды:
nano .envВставьте содержимое в файл .env:
DATABASE_URL=postgresql://short_links:<PASSWORD>@<DB_PRIVATE_IP>:5432/short_linksBASE_URL=<IP-адрес>.nip.ioГде:
<PASSWORD> — пароль, который вы задали при создании пользователя базы данных.
<DB_PRIVATE_IP> — IP-адрес сервиса Managed PostgreSQL.
<IP-адрес> — публичный IP-адрес виртуальной машишы.
Запустите сервис:
python3 server.py
4. Настройте сервис, Nginx и HTTPS
В этом шаге вы автоматически опубликуете API-приложение через системный сервис, настроите обратный прокси через Nginx и выпустите бесплатный SSL-сертификат с помощью Let’s Encrypt.
Настройте сервис
Создайте спецификацию сервиса:
sudo nano /etc/systemd/system/short-links.serviceВставьте в спецификацию следующее содержимое:
[Unit]Description=Short Links ServiceAfter=network.target[Service]User=user1Group=user1WorkingDirectory=/home/user1/short-links-serviceEnvironment="PATH=/home/user1/short-links-service/venv/bin"EnvironmentFile=/home/user1/short-links-service/.envExecStart=/home/user1/short-links-service/venv/bin/uvicorn server:app --host 127.0.0.1 --port 8000Restart=always[Install]WantedBy=multi-user.targetПри необходимости замените user1 на имя своего пользователя.
Запустите сервис:
sudo systemctl daemon-reloadsudo systemctl enable short-linkssudo systemctl start short-linksПроверьте статус сервиса:
sudo systemctl status short-linksУбедитесь, что сервис находится в статусе «active (running)».
Зарегистрируйте бесплатный домен
В сервисе виртуальных машин скопируйте публичный IP-адрес вашей виртуальной машины.
Сформируйте доменное имя по шаблону <IP-адрес>.nip.io (например, 1.2.3.4.nip.io).
Проверьте, что в браузере по адресу http://<IP-адрес>.nip.io загружается страница Welcome to nginx.
Настройте Nginx
Создайте конфигурационный файл:
sudo nano /etc/nginx/sites-available/short-links-service.confВставьте конфигурацию, заменив <IP-адрес> на IP-адрес вашей виртуальной машины.
server {listen 80;server_name <IP-адрес>.nip.io www.<IP-адрес>.nip.io;# Проксирование запросов к FastAPIlocation / {proxy_pass http://127.0.0.1:8000;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_redirect off;}# Логиaccess_log /var/log/nginx/short_links.log;error_log /var/log/nginx/short_links_error.log;}Примените конфигурацию и перезапустите nginx:
sudo ln -sf /etc/nginx/sites-available/short-links-service.conf /etc/nginx/sites-enabled/short-links-service.confsudo rm -f /etc/nginx/sites-enabled/defaultsudo nginx -tsudo systemctl reload nginxПроверьте, что nginx работает:
sudo systemctl status nginxCервис nginx должен быть в статусе «active (running)».
Перейдите по адресу http://\DOMAIN\.nip.io/docs.
Откроется документация API FastAPI по незащищенному протоколу HTTP.
Выпустите SSL сертификат и настройте HTTPS
Запустите команду для выпуска SSL-сертификата.
sudo certbot --nginx -d <DOMAIN> --redirect --agree-tos -m <EMAIL>Где:
<DOMAIN> — ваш домен из nip.io.
<EMAIL> — ваш email.
После успешного выпуска сертификата, перейдите по адресу https://DOMAIN.nip.io/docs.
Откроется документация API FastAPI. В свойствах сайта браузер отметит соединение как безопасное.
Проверьте работу API:
В документации вызовите POST-запрос:
{"original_url": "https://console.cloud.ru/"}Вернется короткая ссылка.
Перейдите по ссылке — должен открыться сайт https://console.cloud.ru/.
Что дальше
В этой лабораторной работе вы полностью реализовали инфраструктуру и приложение для сервиса сокращения ссылок в облаке Cloud.ru с управляемой базой данных, надежной сетевой изоляцией и публикацией API по HTTPS.
Полученные навыки помогут создавать сервисы с использованием управляемых баз данных и создавать безопасные облачные среды для приложений разного типа.
Узнавайте больше о работе с сервисами и получайте практические навыки управления облаком, выполняя лабораторные работы.
- Перед началом работы
- 1. Разверните ресурсы в облаке
- 2. Настройте окружение на виртуальной машине
- 3. Разверните приложение
- 4. Настройте сервис, Nginx и HTTPS
- Что дальше