Инструкция пользователя Облака УВА Advanced
Проекты в Облаке УВА Advanced
Страница с описаниями проектов доступна с виртуальных машин всех отделов. Выполните проброс локального порта аналогично тому, как описано здесь:
ssh -L 5555:10.0.4.62:5555 <your-username>@<ECS-external-IP>-L 5555— произвольно выбранный порт, на котором страница будет доступна локально.
10.0.4.62:5555— эти данные должны остаться без изменения.
<your-username>@<ECS-external-IP>замените на свой логин и внешний IP виртуальной машины отдела.
После проброса, в браузере:
http://localhost:5555
Митапы Облака УВА Advanced
| Дата | Название |
|---|---|
| 01.12.2025 | Митап №2: GigaChat |
Правила пользования Облаком УВА Advanced
- Сбор персональных данных с использованием облачных ресурсов УВА запрещен. Перед началом работы, пожалуйста, изучите 152-ФЗ.
- Использование Облака УВА не связано с:
- с тестированием продуктовых гипотез;
- проведением маркетинговых исследований, исследований UX (user experience) и клиентских путей, социологических исследований;
- поддержкой/продажей существующих продуктов или реализацией run-процессов;
- выводом продуктов на внешней рынок;
- договорными отношениями с внешними клиентами (физ. лица, юр. лица) с принятием обязательств перед клиентами по качеству или доступности цифровых сервисов. Не предусмотрена обработка информации выше К4.
- обработкой персональных данных клиентов. В целях обеспечения соблюдения требований Федерального закона от 27.07.2006 г. №152-ФЗ «О персональных данных» в Облаке УВА запрещено осуществлять сбор, хранение, использование, обработку, передачу и распространение персональных данных субъектов персональных данных.
- Не отключайте опцию подключения к виртуальной машине с правами root. Нарушение этого правила может привести к блокировке вашей машины.
- Администраторам придерживаться шаблона при создании учетной записи на виртуальной машине:
{имя}-{табельный номер}. Пример: eimeredelin@sberbank.ru →eimeredelin-2042974.
- Не храните в базах данных и объектном хранилище информацию, не предназначенную для широкой аудитории. Пользование сервером PostgreSQL и бакетами в Облаке УВА организовано по принципу🤝
все видят всех и могут выгружать всё
- Давайте сущностям осмысленные имена. В названиях однотипных придерживайтесь шаблона/структуры. При создании базы данных заполняйте поле Комментарий. Пожалуйста, думайте об удобстве использования материалов вашими коллегами.
- Вопросы по работе сервиса, предложения и обнаруженные ошибки, пожалуйста, направляйте по адресам:
- Евгений Меределин, eimeredelin@sberbank.ru
- копия письма: Радик Махмутов, rgmakhmutov@sberbank.ru
О персональных данных
Персональные данные (ПДн) — это любая информация, относящаяся к прямо или косвенно определенному или определяемому физическому лицу (п.1 ст.3 Федерального закона от 27.07.2006 №152-ФЗ «О персональных данных», далее — Закон о ПДн).
Для того чтобы загрузить и обрабатывать данные, содержащие ПДн, требуется правовое основание. Перечень правовых оснований для обычных и специальных категорий ПДн приведен в ч.1 ст.6, ч.2, 2.1 ст.10 Закона о ПДн. Основным (хотя и не единственным) правовым основанием является согласие на обработку ПДн. Сбор и обработка ПДн без правовых оснований влечет риск.
На что нужно обратить внимание при обработке внешних данных:
- Обезличивание ПДн — действия, в результате которых становится невозможным без использования дополнительной информации определить принадлежность ПДн конкретному лицу.
- Если из датасета будет удалена только часть «наиболее очевидных» ПДн (ФИО, номер телефона и т.п.), либо такие данные будут заменены идентификаторами, но останется иная информация, прямо или косвенно связанная с гражданином, существует вероятность признания таких действий обезличиванием ПДн. В ряде случаев обезличенные ПДн остаются персональными, и при их обработке по-прежнему необходимо соблюдать требования закона.
- Использование изображения гражданина (в т.ч. фотографии, видеозаписи) допускается с согласия этого гражданина. Тот факт, что изображение опубликовано в открытом доступе, еще не означает, что можно свободно загружать и использовать изображение без согласия гражданина.
Не требуется получать согласие в следующих случаях:
- изображение используется в государственных, общественных или иных публичных интересах;
- изображение получено при съемке, которая проводится в местах, открытых для свободного посещения, или на публичных мероприятиях, за исключением случаев, когда такое изображение является основным объектом использования;
- гражданин позировал за плату;
- обстоятельства размещения изображения в Интернете могут говорить о согласии гражданина на использование изображения (например, если это предусмотрено условиями пользования сайтом, на котором размещено изображение).
В иных случаях использование изображения гражданина без его согласия влечет риск.
- Частная жизнь — это область жизнедеятельности человека, которая касается только его и не подлежит контролю со стороны общества и государства, если не носит противоправный характер.
При этом исчерпывающее определение перечня сведений, однозначно относящихся/не относящихся к сведениям, составляющим частную жизнь лица, невозможно.
В частную жизнь включаются, в частности, сведения о происхождении, о месте пребывания или жительства, о личной и семейной жизни, о профессиональной и деловой деятельности.Не допускаются без согласия гражданина сбор, хранение, распространение и использование любой информации о его частной жизни. Согласие не требуется в случаях, когда указанные действия осуществляются в государственных, общественных или иных публичных интересах, а также в случаях, если информация о частной жизни гражданина ранее стала общедоступной, либо была раскрыта самим гражданином или по его воле (п.1 ст.152.2 ГК РФ).
В большинстве случаев сведения о частной жизни одновременно являются ПДн, поэтому сохраняют актуальность выводы, указанные применимо к обработке ПДн.
- Нарушением тайны телефонных переговоров является, в частности, незаконный доступ к информации о входящих и об исходящих сигналах соединения между абонентами или абонентскими устройствами пользователей связи (дате, времени, продолжительности соединений, номерах абонентов, других данных, позволяющих идентифицировать абонентов — п.4 Постановления Пленума Верховного Суда РФ от 25.12.2018 №46).
При возникновении вопросов с определением категории информации для обработки в Облаке УВА можно обратиться к коллегам из SOC (ЮЗБ).
Порядок получения доступов
Порядок получения доступов — учетных данных к сервисам в Облаке УВА.
Есть пользователь (сотрудник отдела), есть администратор отдела — тоже сотрудник отдела, но с функцией "старосты", есть администратор Облака УВА.
- Чтобы получить свои персональные учетные данные, сотрудник/заявитель пишет админу своего отдела.
- Админ отдела пишет админу Облака УВА: создать доступы для табельный номер заявителя. Табельный номер есть в профиле сотрудника в Пульсе. Если заявителю требуется sudo, админ отдела указывает это. По умолчанию sudo не будет.
- Админ Облака УВА создает для заявителя доступы к виртуальной машине отдела, серверу PostgreSQL и объектному хранилищу.
- Админ Облака УВА передает заявителю учетные данные из п.3 с копией письма админу отдела.
- Заявитель подключается к сервисам, пользуясь данной Инструкцией и своими учетными данными.
Администраторы отделов
| Вертикаль/Отдел | ФИО |
|---|---|
| ОАОП | Демков Владимир Валерьевич |
| ОАОП | Горянский Илья Андреевич |
| ОАПСО | Котенев Алексей Алексеевич |
| ОАПСО | Любимцев Игорь Юрьевич |
| ОАРБ | Чечнев Алексей Александрович |
| ОАРБ | Дейнеко Максим Андреевич |
| ОАИТ | Меределин Евгений Игоревич |
| ОАИТ | Махмутов Радик Гумерович |
| ОАОФР | Хертек Ясемин Орлан-ооловна |
| ОАОФР | Ульяненков Тимофей Владимирович |
| CDS | Абрашкина Анна Александровна |
| CDS | Батарчук Егор Игоревич |
Комплект учетных данных
Виртуальная машина
- Внешний IP для подключения по SSH. В примере Подключение к виртуальной машине:
188.72.107.76.
- Внутренний IP в Облаке УВА.
- Имя пользователя и пароль. Пользователь в примере:
user-demo.
Сервер PostgreSQL
- Имя сервера PostgreSQL и его IP-адрес. В примере Подключение к серверу PostgreSQL:
postgres-demo,10.0.14.19.
- Имя пользователя и пароль. Пользователь в примере:
user-demo.
Объектное хранилище
- Имя IAM-пользователя и пароль для доступа к сервису Object Storage Service через консоль платформы Advanced Cloud.ru. Используется в п.5 Подключение к объектному хранилищу. Метод двухфакторной аутентификации (2FA) — Virtual MFA Device, см. раздел Подключить приложение одноразовых паролей.ℹ️
консольный доступ работает с локальной машины и из сигмы
- Access key, secret key, endpoint и region (programmatic access — программный доступ) для управления объектами в бакете с помощью клиентов/интерфейсов объектных хранилищ и библиотек. Используется в пп.1-4 Подключение к объектному хранилищу.ℹ️
программный доступ работает с локальной машины (GUI, CLI) и виртуальной машины (CLI)
- Имя созданного для отдела бакета. В примере:
user-demo-bucket.
Подключение к виртуальной машине
- Сгенерируйте пароль (passphrase) для SSH-ключа и сохраните его в надежном месте. Пожалуйста, не пренебрегайте созданием passphrase — он понадобится для подключения к серверу PostgreSQL. Например, создайте буквенно-цифровую последовательность длиной 50 символов этим генератором.
- Сгенерируйте SSH-ключ на локальной машине:
$ ssh-keygen Generating public/private ed25519 key pair. Enter file in which to save the key (/c/Users/user/.ssh/id_ed25519): Enter passphrase for "/c/Users/user/.ssh/id_ed25519" (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /c/Users/user/.ssh/id_ed25519 Your public key has been saved in /c/Users/user/.ssh/id_ed25519.pub The key fingerprint is: SHA256:apfCa4esUZko7sJjHEwkE2eMpvrRUQlucdrf6RXZ9Y0 user@AsusVivobook The key's randomart image is: +--[ED25519 256]--+ |.+o o... .| |+=.. =o o oo| |=. +.. o E o| |.. ... + . . . | |+ ....+ S o . | |.+...o . o . | |o.o...=.o . | |.*. o++. | |..o .o.. | +----[SHA256]-----+
- Скопируйте публичную часть ключа,
id_ed25519.pub, с локальной машины на виртуальную. Измените путь до ключа на локальной машине на свой.$ scp C:/Users/user/.ssh/id_ed25519.pub user-demo@188.72.107.76:/home/user-demo/.ssh/authorized_keys user-demo@188.72.107.76's password: id_ed25519.pub 100% 99 7.3KB/s 00:00
- Подключитесь к виртуальной машине по SSH:
$ ssh user-demo@188.72.107.76 Enter passphrase for key '/c/Users/user/.ssh/id_ed25519': Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-71-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro System information as of Wed Jul 30 02:20:05 PM MSK 2025 System load: 0.0 Processes: 113 Usage of /: 8.6% of 39.26GB Users logged in: 0 Memory usage: 10% IPv4 address for eth0: 10.0.14.15 Swap usage: 0% Expanded Security Maintenance for Applications is not enabled. 0 updates can be applied immediately. Enable ESM Apps to receive additional future security updates. See https://ubuntu.com/esm or run: sudo pro status Welcome to Elastic Cloud ServiceЕще проще с Termius:
- В платной версии есть синхронизация зашифрованного хранилища (vault) между десктоп- и мобильным приложением:
- Доступ к виртуальной машине из сигмы.
Закрепите Elastic Cloud Server на панели быстрого доступа:
Найдите в списке машину вашего отдела и подключитесь к терминалу:
⚠️Завершите сессию командой
exitперед закрытием вкладки браузера.
Подключение к серверу PostgreSQL
- Установите PostgreSQL на локальную машину, включая предлагаемый во время установки pgAdmin.
- Создайте базу данных и схему (schema) внутри нее. Внутри схемы вы сможете создавать таблицы и другие сущности. Скриншот ниже показывает пример ошибки, которую получит другой пользователь при попытке изменить вашу таблицу.
- Быть владельцем сущности не всегда означает право изменять ее: владелец может делегировать право, хотя сам при этом может им активно и не обладать. Чтобы писать в таблицы, например, с помощью SQLAlchemy, выполните небольшую донастройку по примеру на скришотах ниже. Откройте свойства принадлежащих вам, т.е. созданных вами, сущностей (БД, схема, таблица и т.д.) и дайте самому себе или коллегам необходимые права. Во вкладке Security задаются права на уже созданные сущности, в Default Privileges — на те, которые будут созданы внутри редактируемой сущности.
- Если вы используете SQLAlchemy ORM, не забудьте указать имя схемы. Таблица в примере, reviews, живет на схеме bankiru. Если не указать это явно, SQLAlchemy будет искать/писать таблицу на дефолтной для постгреса схеме public, к которой сейчас у пользователей доступа нет, и это приведет к
InsufficientPermissionException. Для установки схемы воспользуйтесь одним из двух способов:- определите схему в метаданных базового класса
Base, если схему нужно распространить на все дочерние модели;
- переопределите схему в дандер-атрибуте
__table_args__конкретной модели, если схема задается для той или иной таблицы индивидуально.
from sqlalchemy import MetaData from sqlalchemy.orm import declarative_base Base = declarative_base(metadata=MetaData(schema="bankiru")) class Review(Base): __tablename__ = "reviews" # __table_args__ = {"schema": "bankiru"} # ... - определите схему в метаданных базового класса
Подключение к объектному хранилищу
пп.1-4 — с локальной машины, п.5 — с локальной машины и из сигмы
- Установите OBS Browser Plus на локальную машину.
- Выполните вход, следуя подсказкам на скриншоте. Используйте данные из п.2 Доступ к объектному хранилищу.
- Подключение через консоль платформы Advanced Cloud.ru. Используйте имя пользователя и пароль из п.1 Доступ к объектному хранилищу.
Двухфакторная аутентификация — ваша почта в сигме:
Или через Меню:
- Узнайте из материалов митапа о создании из бакета статического сайта.
О подходах к наделению правами
Обратите внимание на разницу в подходах к наделению правами между сервером postgres и объектным хранилищем.
На сервере postgres все учетные записи изначально являются равноправными, read-only, и не привязаны к отделам, т.е. нет такого понятия как “командное пространство” и с точки зрения прав каждый сам по себе. Например, вы создали базу данных — значит, вы ее владелец и можете наделять коллег теми или иными дополнительными правами. Симметрично: чтобы получить права сверх чтения на сущность, созданную не вами, вы должны запросить их у владельца. Узнать владельца и отредактировать права можно в свойствах сущности.
В объектном хранилище Облака УВА аналог командного пространства существует — это бакет. Получая доступ к бакету отдела, вы можете писать в него свои объекты и удалять любые объекты ваших коллег по отделу. Но, разумеется, вы не можете изменять содержимое бакетов других отделов — только просматривать и скачивать.
- сервер PostgreSQL: нет командного пространства, владелец наделяет правами на объект;
- объектное хранилище: есть командное пространство — бакет, политика бакета регулирует права на объект.
Дополнительные материалы/Что дальше
- Обзор бесплатных API LLM. Авторы Гуляева В.А, Гордеева Е.В. Ноутбук ipynb, лог.
- создайте SSH-ключ на виртуальной машине и скопируйте его публичную часть в свою учетную запись на GitHub;
- узнайте, как устанавливать python-пакеты и управлять проектами с помощью замечательного менеджера uv;
- узнайте, как подключиться к вашим базам данных на сервере PostgreSQL с помощью SQLAlchemy;
- узнайте, как управлять запуском вашего приложения с помощью systemd;
- узнайте, как управлять контейнерами и подами с помощью Podman.
Пример простого сервиса: banki.ru
| Вертикаль | ОАИТ (Северо-Западный банк) |
|---|---|
| Автор | Меределин Евгений Игоревич |
| Тема | Жалобы и негативные отзывы клиентов на работу банков |
| Старт | 1 января 2025 г. |
| Период обновления | сутки |
| Тип | таблица |
| Поля | дата публикации, текст жалобы, ссылка на жалобу, населенный пункт автора, банк, банковская услуга |
| Доступные форматы | csv, json, parquet, xlsx |
| Инструменты | FastAPI, Pydantic, SQLAlchemy, aiobotocore, Gradio, Pydantic AI, Cloud.ru Foundation Models |
| Репозиторий API | GitHub |
| Репозиторий Gradio UI | GitHub |
| Swagger API | 10.0.4.62:1706/docs |
| Gradio UI | 10.0.4.62:17060 |
| Сервер PostgreSQL | bankiru db — bankiru schema — reviews table |
| Объектное хранилище (Object Storage) | oait-bucket — bankiru_reviews_db_backup.parquet |
Обновление от 12.01.2026
- Сервис получил интерфейс Gradio, работающий на 10.0.4.62:17060. Примеры:
- Чтобы суммаризировать жалобы моделями сервиса Cloud.ru Foundation Models из выпадающего списка Cloud model, создайте API-ключ как описано здесь, и вставьте его в поле Cloud API key. Для скачивания файла с выборкой в формате Format ключ не требуется.
- В выпадающем списке Bank топ-50 банков по количеству жалоб за 2025 г. в алфавитном порядке. Если оставить поле Bank пустым, оно не будет ограничивать результирующую выборку, что равносильно выбору всех банков, которых намного больше, чем 50. Такая же логика работает для Product и Location.
- В выпадающем списке Product — банковские услуги из рубрикатора banki.ru: сначала для физлиц, затем для юрлиц. Оба блока оканчиваются опцией Другое.
- В выпадающем списке Location административные центры субъектов РФ.
Получение данных по API на личной машине
Доступ к API базы данных bankiru предоставлен виртуальным машинам всех отделов. Скачивайте данные на локальную машину, подключаясь к API через вашу виртуальную машину по SSH-туннелю:
ssh -L 1706:10.0.4.62:1706 <your-username>@<ECS-external-IP>-L 1706— произвольно выбранный порт, на котором приложение будет доступно локально.
10.0.4.62:1706— эти данные должны остаться без изменения.
<your-username>@<ECS-external-IP>замените на свои логин и внешний IP виртуальной машины.
Пример запроса — данные за лето 2025 г. в xlsx:
http://localhost:1706/reviews?startDate=20250601&endDate=20250831&outputFormat=xlsxПрекратить проброс порта: Ctrl+C или Ctrl+D.
Еще проще с Termius: создайте профиль проброса порта и подключайтесь в один клик:
Получение данных по API в сигме
- Подключение к виртуальной машине в консоли Cloud.ru Advanced — см. п.5 раздела Подключение к виртуальной машине.
- На всех машинах в Облаке УВА установлен HTTPie. Пример запроса тот же — данные за лето 2025 г. в xlsx:
$ http 10.0.4.62:1706/reviews \ > startDate==20250601 endDate==20250831 outputFormat==xlsx \ > --unsortedhttp(илиhttps, если требуется) — утилита HTTPie;
- метод не указан, по умолчанию GET для запроса без тела;
10.0.4.62:1706/reviews— внутренний IP-адрес машины ОАИТ, порт, на котором работает приложение и эндпоинт;
startDate,endDate,outputFormat— query-параметры запроса;
--unsorted— опция для вывода полей в ответе в порядке их следования в модели данных (а не в алфавитном).
⚠️Завершите сессию командой
exitперед закрытием вкладки браузера.
- Укороченная ссылка от spoo.me в сигме не откроется, а оригинальная весьма длинная. Поэтому смотрим имя файла в поле
filenameи забираем из бакета ОАИТ:
Запуск проекта в Облаке УВА Advanced
В проекте используются все услуги Облака УВА Advanced, доступные на момент написания в августе 2025: виртуальная машина, сервер PostgreSQL и объектное хранилище. Пожалуйста, проходите этот раздел после выполнения инструкций выше.
Сервис сбора и хранения негативных отзывов/жалоб с banki.ru состоит из двух частей:
- Парсер. В начале наступившего дня собирает данные за истекшие сутки и отправляет их в API базы данных.
- API базы данных. Публикует пришедшие от парсера новые записи в базе данных. После каждого коммита (добавления или удаления записей) делает резервную копию базы данных в формате parquet и перезаписывает предыдущую версию в бакете объектного хранилища. Принимает запрос на получение из БД выборки в заданном формате с фильтрацией по интервалу дат, банкам, банковским услугам, городам авторов жалоб. Выборка предоставляется в ответе в виде прямой ссылки на скачивание файла из бакета объектного хранилища. Возможна суммаризация жалоб при наличии API-ключа, совместимого с Cloud.ru Foundation Models.
Рассмотрим разработку и запуск API как отдельного проекта. Ход работы с парсером аналогичен.
План действий. Разработка API ведется на [локальной] машине с Windows. Площадка запуска и постоянной работы — виртуальная машина с Ubuntu. Мы подготовим проект на локальной машине, создадим для него репозиторий на GitHub, склонируем репозиторий на виртуальную машину, запустим API и посмотрим на его работу.
Инструменты: uv, GitHub CLI, systemd, HTTPie CLI, Pydantic Logfire.
В примере используется SSH-клиент Termius с двумя профилями: PowerShell и bash из поставки Git для Windows (C:\Program Files\Git\bin\bash.exe). Если не указано особо, команда выполняется в bash.
- Установка uv в Windows. В PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" Downloading uv 0.8.9 (x86_64-pc-windows-msvc) Installing to C:\Users\user\.local\bin uv.exe uvx.exe uvw.exe everything's installed!uv --version uv 0.8.9 (68c0bf8a2 2025-08-11)
- Создание проекта с помощью uv:
/d/git $ uv init bankiru-dbapi Initialized project `bankiru-dbapi` at `D:\git\bankiru-dbapi`
- Создание виртуального окружения, установка зависимостей. Изучите документацию uv, если вашему проекту требуется какая-то конкретная версия интерпретатора и чтобы дать виртуальному окружению имя, отличное от
.venvпо умолчанию./d/git $ cd bankiru-dbapi//d/git/bankiru-dbapi (main) $ uv add aiobotocore alembic environs fastapi[standard] logfire[fastapi] pandas psycopg[binary,pool] py-spoo-url pyarrow sqlalchemy Using CPython 3.13.2 Creating virtual environment at: .venv Resolved 104 packages in 814ms Installed 102 packages in 3.93s + aiobotocore==2.24.0 + aiohappyeyeballs==2.6.1 + aiohttp==3.12.15 ... + wrapt==1.17.3 + yarl==1.20.1 + zipp==3.23.0pyproject.toml:/d/git/bankiru-dbapi (main) $ cat pyproject.toml [project] name = "bankiru-dbapi" version = "0.1.0" description = "Banki.ru Claims and Negative Reviews Database API" readme = "README.md" requires-python = ">=3.13" dependencies = [ "aiobotocore>=2.24.0", "alembic>=1.16.4", "environs>=14.3.0", "fastapi[standard]>=0.116.1", "logfire[fastapi]>=4.3.3", "pandas>=2.3.1", "psycopg[binary,pool]>=3.2.9", "py-spoo-url>=0.0.6", "pyarrow>=21.0.0", "sqlalchemy>=2.0.43", ]Заполним поле
description. В проекте естьalembic, но создание системы миграций здесь не рассматривается. Для чтения переменных окружения используетсяenvirons. Обратите также внимание на замечательную библиотеку dataclass-wizard.
- Мы поработали и написали в корневой папке проекта несколько py-модулей и/или пакетов. Также мы добавим:
- файл с переменными окружения
.env;
- файл
.env.example, чтобы использующие код знали, какие переменные окружения он ожидает;
- файл
.gitignore, исключающий из отслеживания.envи.venv;
- юнит systemd
bankiru-dbapi.serviceдля запуска API на виртуальной машине.
/d/git/bankiru-dbapi (main) $ ls -a -1 . .. .env .env.example .git .gitignore .python-version .venv README.md alembic alembic.ini bankiru-dbapi.service botocore_client.py database.py handlers.py logfire_auto_tracing.py main.py models.py pyproject.toml schemas.py uv.lock - файл с переменными окружения
.env.example:/d/git/bankiru-dbapi (main) $ cat .env.example API_TOKEN= LOGFIRE_TOKEN= POSTGRES_URL=postgresql+psycopg://<username>:<password>@<ip>/<db_name> AWS_REQUEST_CHECKSUM_CALCULATION=when_required AWS_RESPONSE_CHECKSUM_VALIDATION=when_required OBS_BUCKET= OBS_ACCESS_KEY= OBS_SECRET_KEY= OBS_REGION= OBS_ENDPOINT= ECS_PRIVATE_IP= ECS_PORT=
bankiru-dbapi.service:/d/git/bankiru-dbapi (main) $ cat bankiru-dbapi.service [Unit] Description=bankiru-dbapi After=syslog.target After=network.target [Service] Type=simple User=evm WorkingDirectory=/home/evm/bankiru-dbapi ExecStart=/home/evm/bankiru-dbapi/.venv/bin/python /home/evm/bankiru-dbapi/logfire_auto_tracing.py Restart=always [Install] WantedBy=multi-user.target
- Выпуск токена доступа/аутентификации personal access token (PAT) на GitHub здесь. Требование к токену: The minimum required scopes are
repo,read:org,admin:public_key.
- Установка GitHub CLI в Windows: скачать msi или с помощью winget.
/d/git/bankiru-dbapi (main) $ winget install --id GitHub.cli Found GitHub CLI [GitHub.cli] Version 2.76.2 This application is licensed to you by its owner. Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. Downloading https://github.com/cli/cli/releases/download/v2.76.2/gh_2.76.2_windows_amd64.msi ██████████████████████████████ 17.4 MB / 17.4 MB Successfully verified installer hash Starting package install... The installer will request to run as administrator. Expect a prompt. Successfully installed/d/git/bankiru-dbapi (main) $ gh --version gh version 2.76.2 (2025-07-30) https://github.com/cli/cli/releases/tag/v2.76.2
- Аутентификация в GitHub CLI с использованием токена из п.7. Публичная часть SSH-ключа будет скопирована и появится здесь с назначенным ему именем.
/d/git/bankiru-dbapi (main) $ gh auth login ? Where do you use GitHub? GitHub.com ? What is your preferred protocol for Git operations on this host? SSH ? Upload your SSH public key to your GitHub account? C:\Users\user\.ssh\id_ed25519.pub ? Title for your SSH key: (GitHub CLI) ... ? Title for your SSH key: ... ? How would you like to authenticate GitHub CLI? Paste an authentication token Tip: you can generate a Personal Access Token here https://github.com/settings/tokens The minimum required scopes are 'repo', 'read:org', 'admin:public_key'. ? Paste your authentication token: **************************************** - gh config set -h github.com git_protocol ssh ✓ Configured git protocol ✓ Uploaded the SSH key to your GitHub account: C:\Users\user\.ssh\id_ed25519.pub ✓ Logged in as EvgenyMeredelinТокен аутентификации хранится безопасно:
/d/git/bankiru-dbapi (main) $ gh auth status github.com ✓ Logged in to github.com account EvgenyMeredelin (keyring) - Active account: true - Git operations protocol: ssh - Token: ghp_************************************ - Token scopes: ...
- Коммит проекта. Но перед этим добавим описание в
README.md./d/git/bankiru-dbapi (main) $ git add ./d/git/bankiru-dbapi (main) $ git commit -m "First commit" [main (root-commit) 3dbd33a] First commit 19 files changed, 2808 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 README.md create mode 100644 alembic.ini create mode 100644 alembic/README create mode 100644 alembic/env.py create mode 100644 alembic/script.py.mako create mode 100644 alembic/versions/45600a192211_initial_migration.py create mode 100644 bankiru-dbapi.service create mode 100644 botocore_client.py create mode 100644 database.py create mode 100644 handlers.py create mode 100644 logfire_auto_tracing.py create mode 100644 main.py create mode 100644 models.py create mode 100644 pyproject.toml create mode 100644 schemas.py create mode 100644 uv.lock
- Создание репозитория и пуш коммита в него. Источник — текущая папка, поэтому репозиторий получит ее имя:
bankiru-dbapi./d/git/bankiru-dbapi (main) $ gh repo create --source=. --private --push ✓ Created repository EvgenyMeredelin/bankiru-dbapi on github.com https://github.com/EvgenyMeredelin/bankiru-dbapi ✓ Added remote git@github.com:EvgenyMeredelin/bankiru-dbapi.git Enter passphrase for key '/c/Users/user/.ssh/id_ed25519': Enumerating objects: 23, done. Counting objects: 100% (23/23), done. Delta compression using up to 8 threads Compressing objects: 100% (21/21), done. Writing objects: 100% (23/23), 99.42 KiB | 1.33 MiB/s, done. Total 23 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0) remote: Resolving deltas: 100% (1/1), done. To github.com:EvgenyMeredelin/bankiru-dbapi.git * [new branch] HEAD -> main branch 'main' set up to track 'origin/main'. ✓ Pushed commits to git@github.com:EvgenyMeredelin/bankiru-dbapi.git
- Чтение переменных окружения и подключение к виртуальной машине:
/d/git/bankiru-dbapi (main) $ . .env/d/git/bankiru-dbapi (main) $ ssh evm@<ECS-public-IP> Enter passphrase for key '/c/Users/user/.ssh/id_ed25519': Welcome to Ubuntu 24.04.3 LTS (GNU/Linux 6.8.0-71-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro ...
- Установка uv в Ubuntu:
evm@ecs-evm:~$ curl -LsSf https://astral.sh/uv/install.sh | sh downloading uv 0.8.9 x86_64-unknown-linux-gnu no checksums to verify installing to /home/evm/.local/bin uv uvx everything's installed!evm@ecs-evm:~$ uv --version uv 0.8.9
- По причине несовершенства механизма хранения гитом секретов в Linux мы не будем устанавливать GitHub CLI в Ubuntu. Создадим SSH-ключ по пп.1-2 Подключение к виртуальной машине — с той лишь разницей, что это нужно сделать не на локальной машине, а на виртуальной. Скопируем руками публичную часть ключа и создадим новый ключ в разделе SSH keys здесь.
evm@ecs-evm:~$ cat .ssh/id_ed25519.pub ssh-ed25519 ...
- Клонирование репозитория на виртуальную машину. Ссылку, соответствующую протоколу, в том числе SSH, можно скопировать со страницы репозитория (зеленая кнопка Code).
evm@ecs-evm:~$ git clone git@github.com:EvgenyMeredelin/bankiru-dbapi.git Cloning into 'bankiru-dbapi'... remote: Enumerating objects: 23, done. remote: Counting objects: 100% (23/23), done. remote: Compressing objects: 100% (20/20), done. remote: Total 23 (delta 1), reused 23 (delta 1), pack-reused 0 (from 0) Receiving objects: 100% (23/23), 99.42 KiB | 530.00 KiB/s, done. Resolving deltas: 100% (1/1), done.
- (Вос)создание виртуального окружения:
evm@ecs-evm:~$ cd bankiru-dbapi/ evm@ecs-evm:~/bankiru-dbapi$ uv sync Using CPython 3.13.5 Creating virtual environment at: .venv Resolved 104 packages in 26ms Prepared 46 packages in 2.63s Installed 102 packages in 620ms + aiobotocore==2.24.0 + aiohappyeyeballs==2.6.1 + aiohttp==3.12.15 ... + wrapt==1.17.3 + yarl==1.20.1 + zipp==3.23.0
- Откроем второй терминал и скопируем файл с переменными окружения
.envс локальной машины на виртуальную:/d/git/bankiru-dbapi (main) $ . .env/d/git/bankiru-dbapi (main) $ scp .env evm@<ECS-public-IP>:/home/evm/bankiru-dbapi/ Enter passphrase for key '/c/Users/user/.ssh/id_ed25519': .env 100% 704 50.7KB/s 00:00Теперь весь проект на месте:
evm@ecs-evm:~/bankiru-dbapi$ ls -a -1 . .. alembic alembic.ini bankiru-dbapi.service botocore_client.py database.py .env .env.example .git .gitignore handlers.py logfire_auto_tracing.py main.py models.py pyproject.toml .python-version README.md schemas.py uv.lock .venv
- Скопируем подготовленный в п.6 юнит systemd и запустим его:
evm@ecs-evm:~/bankiru-dbapi$ sudo cp bankiru-dbapi.service /etc/systemd/system evm@ecs-evm:~/bankiru-dbapi$ sudo systemctl daemon-reload evm@ecs-evm:~/bankiru-dbapi$ sudo systemctl enable bankiru-dbapi.service Created symlink /etc/systemd/system/multi-user.target.wants/bankiru-dbapi.service → /etc/systemd/system/bankiru-dbapi.service. evm@ecs-evm:~/bankiru-dbapi$ sudo systemctl start bankiru-dbapi.serviceЮнит работает:
evm@ecs-evm:~$ sudo systemctl status bankiru-dbapi.service ● bankiru-dbapi.service - bankiru-dbapi Loaded: loaded (/etc/systemd/system/bankiru-dbapi.service; enabled; preset: enabled) Active: active (running) since Wed 2025-08-13 21:17:43 MSK; 4s ago Main PID: 34936 (python) Tasks: 11 (limit: 4144) Memory: 124.8M (peak: 125.2M) CPU: 1.849s CGroup: /system.slice/bankiru-dbapi.service └─34936 /home/evm/bankiru-dbapi/.venv/bin/python /home/evm/bankiru-dbapi/logfire_auto_tracing.py Aug 13 21:17:43 ecs-evm systemd[1]: Started bankiru-dbapi.service - bankiru-dbapi. Aug 13 21:17:43 ecs-evm python[34936]: Logfire project URL: https://logfire-us.pydantic.dev/... Aug 13 21:17:44 ecs-evm python[34936]: INFO: Started server process [34936] Aug 13 21:17:44 ecs-evm python[34936]: INFO: Waiting for application startup. Aug 13 21:17:44 ecs-evm python[34936]: INFO: Application startup complete. Aug 13 21:17:44 ecs-evm python[34936]: INFO: Uvicorn running on http://... (Press CTRL+C to quit)Выход:
:q. Число запускаемых юнитов не ограничено. Главное чтобы на запускаемый юнитами ваш код хватало ресурсов машины.
- Итак, API готов к работе. Парсер поднимается аналогично. Мы создали на сервере базу данных, и парсер уже насобирал в нее данные. Установим на локальной машине Chocolatey и HTTPie CLI. В PowerShell:
Run
Get-ExecutionPolicy. If it returnsRestricted, then runSet-ExecutionPolicy AllSignedorSet-ExecutionPolicy Bypass -Scope Process.Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))choco --version 2.5.0choco install httpie Chocolatey v2.5.0 Installing the following packages: httpie By installing, you accept licenses for the packages. Downloading package from source 'https://community.chocolatey.org/api/v2/' Progress: Downloading httpie 3.2.2... 100% ... Successfully installed httpie-3.2.2 The install of httpie was successful. Software install location not explicitly set, it could be in package or default install location of installer. Chocolatey installed 1/1 packages. See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
- Вернемся на локальную машину, выполним проброс локального порта, как описано здесь, и рассмотрим несколько примеров работы API.
Чтение записей. Отзывы за первую неделю августа 2025 в xlsx. Ссылка валидна ограниченное время. Ответ200 OK./d/git/bankiru-dbapi (main) $ http GET localhost:1706/reviews \ > startDate==20250801 endDate==20250807 outputFormat==xlsx \ > --format-options json.sort_keys:false HTTP/1.1 200 OK content-length: 136 content-type: application/json date: Thu, 14 Aug 2025 07:58:48 GMT server: uvicorn { "startDate": "2025-08-01", "endDate": "2025-08-07", "outputFormat": "xlsx", "generateUrl": true, "url": "https://spoo.me/dv7ta3", "comment": null }То же в HTTPie desktop:
С параметрами по умолчанию получим всю БД в parquet:
/d/git/bankiru-dbapi (main) $ http GET localhost:1706/reviews --unsorted HTTP/1.1 200 OK date: Thu, 14 Aug 2025 08:00:09 GMT server: uvicorn content-length: 123 content-type: application/json { "startDate": null, "endDate": null, "outputFormat": "parquet", "generateUrl": true, "url": "https://spoo.me/OuJjmw", "comment": null }
- Добавление записей. Сымитируем работу парсера и добавим в БД одну запись (представим, что парсер отправил список, в котором единственная запись):
/d/git/bankiru-dbapi (main) $ cat reviews.json [ { "datePublished": "2026-01-01 01:23:45", "reviewBody": "Я закопал монетки, и они пропали...", "bankName": "Банк Поле Чудес", "url": "https://banki.ru/buratino-review", "location": "Сказочный город", "product": "Вклад" } ]/d/git/bankiru-dbapi (main) $ http POST localhost:1706/reviews API-Token:$API_TOKEN < reviews.json HTTP/1.1 201 Created content-length: 4 content-type: application/json date: Thu, 14 Aug 2025 08:01:50 GMT server: uvicorn nullОтвет
nullсо статусом201 Created, потому что парсеру ответ не требуется. Как сказано в описании API выше, после каждого коммита (добавления или удаления записей) API создает бэкап базы данных в parquet и перезаписывает предыдущую версию в бакете объектного хранилища:Логика проста. Если это выборка по запросу пользователя, то API дает информативный ответ с полями, описывающими выборку, а файлу дается уникальное uuid-имя. Если эта выборка — автоматический бэкап, спровоцированный парсером, то осмысленный ответ не требуется, а файл в parquet получает [статичное] предопределенное имя
bankiru_reviews_db_backup, и это приводит к перезаписи предыдущего бэкапа.Так наша запись выглядит в БД. На скриншоте 5 последних записей, начиная с последней.
- Удаление записей. Удалим нашу запись, отправив соответствующему эндпоинту массив из одного id, — id записи к удалению:
/d/git/bankiru-dbapi (main) $ echo '[220345]' | http DELETE localhost:1706/reviews API-Token:$API_TOKEN HTTP/1.1 204 No Content content-type: application/json date: Thu, 14 Aug 2025 08:06:48 GMT server: uvicornОжидаемый ответ
204 No Content, запись удалена, а бэкап обновлен, что видно по свежей дате последнего изменения в бакете:
- Примеры валидации данных. В обоих случаях ответ
422 Unprocessable Content.
29 февраля у невисокосного 2025 года:/d/git/bankiru-dbapi (main) $ http GET localhost:1706/reviews \ > startDate==20250229 HTTP/1.1 422 Unprocessable Content content-length: 152 content-type: application/json date: Thu, 14 Aug 2025 08:09:14 GMT server: uvicorn { "detail": [ { "ctx": { "error": {} }, "input": "20250229", "loc": [ "query", "startDate" ], "msg": "Value error, day is out of range for month", "type": "value_error" } ] }Неизвестный формат файла, для которого нет обработчика:
/d/git/bankiru-dbapi (main) $ http GET localhost:1706/reviews \ > outputFormat==abc HTTP/1.1 422 Unprocessable Content content-length: 197 content-type: application/json date: Thu, 14 Aug 2025 08:09:54 GMT server: uvicorn { "detail": [ { "ctx": { "expected": "'csv', 'json', 'parquet' or 'xlsx'" }, "input": "abc", "loc": [ "query", "outputFormat" ], "msg": "Input should be 'csv', 'json', 'parquet' or 'xlsx'", "type": "literal_error" } ] }Здесь используется симпатичный мне подход “бесшовной валидации”. Новые обработчики, конвертирующие выборку из БД в тот или иной формат, пишутся как потомки базового абстрактного класса. В момент выполнения кода
inspectформирует маппинг между расширением файла и соответствующим конвертером. Так, с одной стороны, определяется конвертер по указанному в запросе желаемому выходному формату. С другой — ключи этого маппинга, т.е. расширения, определяют значенияtyping.Literal, который валидирует выходной формат в запросе. Так в запросе валидны только те форматы, для которых в коде существуют конвертеры. Если разработчик написал новый конвертер, то ничего дополнительно делать не нужно: соблюдение протокола базового класса сразу делает конвертер активным, а соответствующее расширение выходного файла — валидным значением в запросе.
- Как это может выглядеть в Pydantic Logfire. Это платформа с огромным функционалом для мониторинга, сбора и анализа телеметрии и логов приложений. Logfire выходит за рамки этого примера и упоминается здесь лишь для того чтобы привлечь ваше внимание к этому замечательному инструменту.
- В конце несколько слов о Termius.
- защищенное подключение к хосту в один клик;
- хранение профилей и данных в зашифрованном хранилище, доступном со всех устройств, включая мобильные;
- личное и командное пространства;
- SFTP-клиент;
- сниппеты для быстрого запуска скриптов на всем прикрепленном парке хостов;
- режим синхронизации терминалов;
- автодополнения как в IDE;
- удобное управление ключами.
Fail2Ban
Fail2Ban на всех машинах уже настроен
На вашу виртуальную машину уже установлен Fail2Ban — пакет, который сканирует логи, например, /var/log/auth.log, и блокирует IP-адреса, которые предпринимают аномально большое число ошибочных попыток подключения.
sudo fail2ban-client version
1.0.2sudo fail2ban-client -h
Usage: fail2ban-client [OPTIONS] <COMMAND>
Fail2Ban v1.0.2 reads log file that contains password failure report
and bans the corresponding IP addresses using firewall rules.
...
- Изменить конфигурацию. Сначала нужно сделать копию
jail.conf—jail.local— и вносить правки вjail.local. Не редактируйтеjail.conf— правки будут перезаписаны при обновлении пакета.sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.localsudo nano /etc/fail2ban/jail.localУ Fail2Ban богатые гибкие настройки, снабженные подробными комментариями. Пожалуйста, изучите их перед активацией/изменением настроек.
Обязательная перезагрузка службы после внесения правок:
sudo systemctl restart fail2ban
- Лог. Последние 50 строк:
sudo tail -50 /var/log/fail2ban.logТолько баны и снятия банов:
sudo zgrep -E 'Ban|Unban' /var/log/fail2ban.log*
- Кто забанен? IP-адреса с разбивкой по джейлам:
sudo fail2ban-client bannedАдреса в конкретном jail с указанием времени начала и окончания бана:
read -p "Jail (default: sshd): " jail; sudo fail2ban-client get ${jail:-sshd} banip --with-time
- Отслеживать обновление
auth.log, чтобы увидеть, что пытаются сделать боты:sudo tail -f /var/log/auth.log
- Забанить IP вручную:
read -p "IP to ban: " ip; read -p "Jail (default: sshd): " jail; sudo fail2ban-client set ${jail:-sshd} banip $ip
- Разбанить IP:
read -p "IP to unban: " ip; read -p "Jail (default: sshd): " jail; sudo fail2ban-client set ${jail:-sshd} unbanip $ip
Сменить метод двухфакторной аутентификации
Раздел предназначен для пользователей, созданных до 7 декабря 2025 г. включительно
В сигме есть проблема с долгим получением кода двухфакторной аутентификации (2FA) на почту. Желающие могут подключить приложение для генерирования одноразовых паролей — например, Authy или GoogleAuthenticator:
- Перейдите в настройки безопасности. Вход в консоль Cloud.ru Advanced осуществляется с помощью IAM username и IAM password.
- Отсканируйте появившийся в консоли QR-код установленным приложением (например, Authy). Так вы создадите в приложении запись для генерирования одноразовых паролей для входа в консоль Cloud.ru Advanced.
- Введите в консоли 2 подряд идущих кода из приложения, чтобы завершить регистрацию.
- Напишите об изменении метода 2FA с почты на one-time-password-приложение администратору Облака УВА — мне или Радику Махмутову.
Подключить приложение одноразовых паролей
Раздел предназначен для пользователей, создаваемых начиная с 8 декабря 2025 г.
Ваш метод двухфакторной аутентификации (2FA) — Virtual MFA Device. Завершите настройку 2FA, подключив приложение для генерирования одноразовых паролей:
- Введите ваши IAM username и IAM password в консоли Cloud.ru Advanced.
- Установите на телефон приложение для генерирования одноразовых паролей — например, Authy или GoogleAuthenticator, — и прикрепите его к вашей учетной записи в Cloud.ru:
- Отсканируйте приложением появившийся в консоли QR-код.
- Введите в консоли 2 подряд идущих кода из приложения, чтобы завершить регистрацию.
Требования к паролям
- Перейдите в настройки безопасности. Вход в консоль Cloud.ru Advanced осуществляется с помощью IAM username и IAM password.
- Изучите поля во вкладках Password Policy и Login Authentication Policy. Эти требования распространяются и на IAM password, и на пароль к вашей учетной записи на виртуальной машине.
Last update: 2026-01-24, evm


















































