Как работать с объектным хранилищем на Python

от автора

Файлы в проекте можно хранить разными способами: локально на компьютере, в базе данных или S3-хранилище (объектное хранилище). Последнее — одно из самых популярных решений. Оно отличается надежностью и масштабируемостью. Использовать S3 можно не только в личных целях, но и для решения бизнес-задач. Для специалиста навык работы с объектным хранилищем востребован. Он поможет быстрее дойти до следующего уровня в карьере.

Под катом расскажем о преимуществах S3, научимся загружать и получать файлы, сверстаем небольшой сайт с его использованием!

Используйте навигацию, если не хотите читать текст полностью:

Немного об S3
Переходим к практике
Создаем объектное хранилище
Тестируем код/a>
→ Создаем приватный контейнер

Заключение

Немного об S3


Если вы слышали, что S3-хранилище — только про Amazon и использование за границей, то это не так. Изначально компания AWS разработала технологию как API для простого доступа к объектам с помощью уникальных URL по HTTP или HTTPS. Однако на рынке уже давно представлены отечественные решения — например, объектное хранилище Selectel.

Технология поддерживает любой тип данных. Вы можете хранить архивные логи, документы, фото и видео — все, что есть на вашем сайте. S3 подходит и в качестве приватного хранилища данных пользователей.

Один из популярных сценариев использования S3 — бэкапирование. Здесь особую роль играет надежность: как только вы загружаете файл в хранилище, он перемещается сразу в три дата-центра. Следовательно, вы не потеряете свои данные даже в случае сбоя одного из них. Рассмотрим другие преимущества технологии.

  • Практически бесконечный объем хранилища — вы можете хранить вплоть до нескольких петабайт данных.
  • Автоматическое масштабирование. В случае резкого всплеска трафика ресурсы мгновенно пополнятся. Так можно параллельно работать с большим количеством пользователей.
  • Разграничение доступов. Для каждого контейнера можно задать список пользователей и команд с различными правами доступа — чтение или чтение и запись.

Переходим к практике


Напишем небольшой скрипт на Python. Позже вы сможете переиспользовать его в любых проектах. Скрипт подключается к объектному хранилищу и работает с файлами.

1. Для начала установим зависимости. Используем одну из самых популярных асинхронных библиотек для работы с S3 — aio-botocore.

pip install aiobotocore 

Если вам интересен синхронный вариант, вы пишете на Django или Flask, используйте botocore. В случае с асинхронным кодом оставляйте aio-botocore. Реализация у них идентичная.

2. Далее создадим класс. Назвать его можно как угодно, в нашем случае — S3Client. Это будет универсальный код, не привязанный к конкретной реализации S3 или провайдеру.

class S3Client:     def __init__(             self,             access_key: str,             secret_key: str,             endpoint_url: str,             bucket_name: str,     ): 

Рассмотрим переменные, которые будем принимать при инициализации проекта:

  • ключ доступа,
  • Secret Key,
  • Access Key,
  • Endpoint URL (адрес нашего хранилища),
  • Bucket Name.

Среди переменных Secret — это некое «имя пользователя», а Access Key — пароль.

3. Создадим некоторую переменную Config (но вы можете назвать ее как угодно). Здесь дадим несколько ключей для подключения.

        self.config = {             "aws_access_key_id": access_key,             "aws_secret_access_key": secret_key,             "endpoint_url": endpoint_url,         }         self.bucket_name = bucket_name         self.session = get_session() 

Не обращайте внимания, что переменные в библиотеке называются AWS (Amazon Web Services). Использовать их можно с любым хранилищем. Bucket Name сохраняем в переменной на всякий случай. Чтобы можно было работать с нашим хранилищем, добавим сессию get_session — ее импортируем из библиотеки aio-botocore, которую скачали ранее.

4. Создадим подключение Client. Здесь будем использовать уже знакомую get_session — в контекстном менеджере выбираем функцию Create Client.

Выбор функции Create Client в контекстном менеджере.

Имя задаем S3, раскрываем конфигурационный файл **self.config. Чтобы можно было использовать конструкцию get_client как контекстный менеджер, навесим декоратор asynccontextmanager. Он уже встроен в Python — импортируем из библиотеки context lib.

   @asynccontextmanager     async def get_client(self):         async with self.session.create_client("s3", **self.config) as client:             yield client 

5. Осталось сделать асинхронную функцию для загрузки файла. Принимать будем несколько параметров. Во-первых — адрес файла. Конечно, на практике вы вряд ли встретитесь с локальным хранением, но так как в нашей реализации нет фронтенда, клиентов и API, пока оставим так. Во-вторых — название, Object Name.

   async def upload_file(             self,             file_path: str,     ): 

6. Откроем контекстный менеджер. Здесь уже ничего не нужно передавать — весь конфиг мы прописали ранее, дальше можем переиспользовать get_client для загрузки, скачивания, удаления и прочих операций. Так как работаем с локальными файлами, естественно, их тоже нужно открывать через контекстный менеджер. Используем read binary mode, rb. Указываем бакет, а Object Name задаем сами. Бакет — это сущность для хранения объектов в S3.

       object_name = file_path.split("/")[-1]  # /users/artem/cat.jpg         try:             async with self.get_client() as client:                 with open(file_path, "rb") as file:                     await client.put_object(                         Bucket=self.bucket_name,                         Key=object_name,                         Body=file,                     ) 

Но что значит put в client.put_object? Возможно, если вы пишете API, то уже сталкивались с этим понятием. Put – это изменение. Важно понимать, что в S3 все операции являются перезаписью. Если пишете новый файл, он добавится в систему. Если же файл уже существует и вы пишете put_object, он перезапишется новой версией. Исходный файл во втором сценарии будет утерян.

Создаем объектное хранилище


Пора создать объектное хранилище и получить ключи для авторизации.

1. В панели управления заходим во вкладку Объектное хранилище → Создать контейнер. Имя зададим test-public-bucket1, но вы можете выбрать любое другое. Тип можно выбрать приватный или публичный. Если вы хотите, чтобы ни у кого из интернета не было прямого доступа до ваших файлов — выбирайте приватный. Мы пока рассмотрим публичный.

2. Переходим к классу хранения. Если речь идет о бэкапах, архивных логах или данных, к которым вы редко возвращаетесь, но они очень ценны — выбирайте холодное хранение. Стандартное обычно выбирается для сервисов, где идет постоянная загрузка файлов, их просмотр и т. д. Нажимаем Создать контейнер.

Контейнер создается за несколько секунд. Но работать с ним пока можно только из браузера.

3. Чтобы взаимодействовать по API, следует создать сервисного пользователя. Переходим в Управление доступом → Сервисные пользователи → Добавить пользователя. Задаем имя пользователя и генерируем пароль, в поле Роль выбираем Администратор объектного хранилища. Выбираем наш проект из списка и нажимаем Добавить пользователя.

4. Получим ключи. Во вкладке Управление пользователями выбираем нужного и в поле S3 ключи нажимаем Добавить ключ. В окне Добавление S3 ключа выбираем наш проект и нажимаем Сгенерировать.

Окно добавления S3 ключа.

Полученные ключи.

5. Ключи копируем и добавляем в проект. Чтобы обращаться к бакету, указываем endpoint_url — s3.storage.selcloud.ru. Задаем bucket-name — в нашем случае это test-public-bucket1. Создаем асинхронную функцию main, в которой создаем объект хранилища S3Client. Загружаем файл test.txt и указываем относительный путь — await S3_client.upload_file(«test.txt»).

async def main():     s3_client = S3Client(         access_key="",         secret_key="",         endpoint_url="",          bucket_name="",     )      # Проверка, что мы можем загрузить, скачать и удалить файл     await s3_client.upload_file("test.txt")     await s3_client.get_file("test.txt", "text_local_file.txt")     await s3_client.delete_file("test.txt")   if __name__ == "__main__":     asyncio.run(main()) 

Тестируем код


Переходим к тестированию нашего кода — запускаем скрипт. Проверим, есть ли изменения в объектах. В контейнере должен отображаться новый файл. Здесь же можно получить ссылку на объект.

Помимо прочего, из панели управления вы можете проставить лимиты. С помощью них можно ограничить объем данных, которые загружаются в хранилище.

Раздел «Лимиты» во вкладке объектного хранилища.

Посмотрим, как загружать файлы из S3 на сайте. Будем использовать простейший одностраничный сайт, исключительно для проверки функций. Создаем файл index.html и выбираем пятую версию html. Положим сюда любой объект из хранилища, в качестве примера используем изображение и видеофайл.

<! doctype html> <html lang="en"> <head>     <meta charset="UTF-8">     <meta name="viewport"          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">     <meta http-equiv="X-UA-Compatible" content="ie=edge">     <title>Document</title> </head> <body>     <div>         <video src="https://445614ac-52e0-4209-bd5e-7efcc3ad83c3.selstorage.ru/jetski.mov" />         <img src="https://326158a3-9309-4662-a565-ff0e15038960.selstorage.ru/2024-03-22%2011.03.30.jpg" />         </div> </body>  </html> 

Переходим на сайт. Видим, что файлы пришли из S3-хранилища. Видеофайл jetski.mov на 212 МБ присылается чанками (порционно). Это помогает S3 не сталкиваться с нагрузкой из-за большого трафика.

Панель администратора на созданном сайте.

Создаем приватный контейнер


Вернемся к выбору типа контейнера в панели управления. В этот раз создадим приватный контейнер с холодным классом хранения. Будем использовать его для бэкапов. Это хранилище, к которому мы также можем обращаться по API, например, через скрипт для резервного копирования. О том, как выбрать тип бэкапа — в обзоре.

Создание приватного контейнера с холодным хранением в панели управления.

Ключевое отличие от созданного ранее контейнера в том, что никто не сможет получить доступ к этому бакету. Здесь нет публичной ссылки и мы не можем расшарить файл, потому что это приватное хранилище. Но мы можем сгенерировать одноразовую ссылку и наложить на нее временные ограничения.

Настройки доступа к файлу в приватном контейнере.

Заключение


Мы поработали с приватными и публичными бакетами, поняли, как загружать и получать данные, как их отображать на сайте. Одно из важных преимуществ объектного хранилища, которое можно рассмотреть в заключение статьи — цена является его цена.

Допустим, у нас есть маркетплейс на 10 000 клиентов, где мы храним 1 ГБ карточек товаров в сжатом виде. Каждый клиент смотрит по 30 фотографий — суммарно уходит 10 ГБ исходящего трафика в месяц. При таких показателях стоимость будет около 24 ₽/мес.

Естественно, аренда объектного хранилища гораздо выгоднее, чем построение надежной и масштабируемой системы своими силами. В случае с бэкапами и холодным хранением цены, как правило, будут еще ниже. Рассчитать стоимость аренды объектного хранилища S3 вы можете на сайте.

Демонстрация работы S3-хранилища и другие подробности о его функциях — в видео

Автор: Артем Шумейко, автор канала на YouTube.


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


Комментарии

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

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