Инфраструктура для data engineer S3

В этой статье я бы хотел рассказать о такой технологии как S3 со стороны дата-инженерии.

S3 — это один из сервисов, который используется для построения Data Lake и обмена файлами.

Давайте начнем с определения:
S3 (Simple Storage Service) — протокол передачи данных, разработанный компанией Amazon. Также — объектное хранилище.

Что мы имеем по итогу? Это по своей идеи файлообменник. Как вы у себя на компьютере организуете хранение файлов точно таким же образом это можно и организовать и в S3.

Ниже в статье мы S3 будем использовать для создания некого Data Lake.

Поэтому давайте введем несколько терминов, которые нам понадобятся:

  • bucket — это контейнер, в котором вы можете хранить свои файлы (папка)

  • path — это ссылка, которая указывает на конкретную часть bucket (путь в проводнике)

  • object — это какой-то физический файл, который находится по path в bucket. Может иметь разные форматы. (файл)

  • access key — ключ доступа к bucket (логин)

  • secret key — секретный ключ доступа для bucket (пароль)

Так как обычно S3 разворачивается где-то, то для подключения к нему можно использовать разные клиенты с UI:

  • CyberDuck

  • Commander One

  • etc

Но в нашем случае мы будем общаться с S3 через Python.

Давайте для начала развернем этот сервис локально в Docker (весь код и все исходники будут доступны в моём репозитории)

version: "3.9"  
  
services:  
  minio:  
    image: minio/minio:RELEASE.2024-07-04T14-25-45Z  
    restart: always  
    volumes:  
      - ./data:/data  
    environment:  
      - MINIO_ROOT_USER=minioadmin  
      - MINIO_ROOT_PASSWORD=minioadmin  
    command: server /data --console-address ":9001"  
    ports:  
      - "9000:9000"  
      - "9001:9001"

И для запуска сервиса необходимо выполнить команду: docker-compose up -d.

Затем перейдем по адресу http://localhost:9001/browser и увидим Web UI нашего объектного хранилища.

Начнём с перехода в пункт Access Keys и создадим первые ключи доступа, при нажатии на кнопку Create access key + мы перейдем в интерфейс, в котором мы сможем создать наши Access Key и Secret Key. Для дальнейшего использования S3 их необходимо сохранить.

Теперь мы можем работать с нашим S3 через Python

Для этого сначала создадим локальное окружение командой и установим все зависимости для проекта:

python3.12 -m venv venv && \
source venv/bin/activate && \
pip install --upgrade pip && \
pip install -r requirements.txt

Затем создадим небольшой код, который будет проверять существование bucket в нашем S3:

from minio import Minio  
  
# Импорт из локальной переменной секретных данных  
from cred import s3_minio_access_key, s3_minio_secret_key  
  
# Не меняется, это единый endpoint для подключения к S3  
endpoint = 'localhost:9000'  
# access key для подключения к bucket  
access_key = s3_minio_access_key  
# secret key для подключения к bucket  
secret_key = s3_minio_secret_key  
  
client = Minio(  
    endpoint=endpoint,  
    access_key=access_key,  
    secret_key=secret_key,  
    secure=False,  # https://github.com/minio/minio/issues/8161#issuecomment-631120560  
)  
  
buckets = client.list_buckets()  
for bucket in buckets:  
    print(bucket.name, bucket.creation_date)

Если его запустить, то мы ничего не увидим, так как в нашем S3 ещё нет ни одного bucket. Так давайте же создадим новый bucket следующим кодом:

from minio import Minio  
  
# Импорт из локальной переменной секретных данных  
from cred import s3_minio_access_key, s3_minio_secret_key  
  
# Не меняется, это единый endpoint для подключения к S3  
endpoint = 'localhost:9000'  
# access key для подключения к bucket  
access_key = s3_minio_access_key  
# secret key для подключения к bucket  
secret_key = s3_minio_secret_key  
  
client = Minio(  
    endpoint=endpoint,  
    access_key=access_key,  
    secret_key=secret_key,  
    secure=False,  # https://github.com/minio/minio/issues/8161#issuecomment-631120560  
)  
  
client.make_bucket(  
    bucket_name='test-local-bucket'  
)

И если ещё раз запустить предыдущий код для проверки bucket. то он он отобразит наличие bucket test-local-bucket

Важно, что в S3 не поддерживается нижнее подчеркивание и поэтому вместо него необходимо использовать тире.

Давайте теперь загрузим какой-нибудь файл в наш bucket. Для этого воспользуемся следующим кодом:

import pandas as pd  
  
# Импорт из локальной переменной секретных данных  
from cred import s3_minio_access_key, s3_minio_secret_key  
  
bucket_name = 'test-local-bucket'  
file_name = 'titanic.csv'  
  
df = pd.read_csv('https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv')  
  
df.to_csv(  
    path_or_buf=f's3://{bucket_name}/{file_name}',  
    index=False,  
    escapechar='\\',  
    compression='gzip',  
    storage_options={  
        "key": s3_minio_access_key,  
        "secret": s3_minio_secret_key,  
        # https://github.com/mlflow/mlflow/issues/1990#issuecomment-659914180  
        "client_kwargs": {"endpoint_url": "http://localhost:9000"},  
    },  
)

В Web UI вы можете проверить наличие файла

Наличие файла titanic.csv

Наличие файла titanic.csv

Важное свойство, которое стоит знать при работе с path в bucket — это то что можно указать свой path руками. Если посмотреть на пример выше, то у нас path выглядит так:
file_name = 'titanic.csv', но можно задать любой path, для примера вот так: file_name = 'raw/kaggle/2022-04-01/titanic.csv'
и получим в bucket такую структуру:

Прописанный путь руками к titanic.csv

Прописанный путь руками к titanic.csv

Также стоит отметить, что если мы удалим файл по данному path, то весь path исчезнет и не нужно будет очищать пустой path.

Теперь также для чтения нам необходимо будет указать весь этот path. Давайте воспользуемся кодом ниже для чтения нашего .csv из bucket

import pandas as pd  
  
# Импорт из локальной переменной секретных данных  
from cred import s3_minio_access_key, s3_minio_secret_key  
  
bucket_name = 'test-local-bucket'  
file_name = 'titanic.csv'  
# file_name = 'raw/kaggle/2022-04-01/titanic.csv'  
  
df = pd.read_csv(  
    filepath_or_buffer=f's3://{bucket_name}/{file_name}',  
    escapechar='\\',  
    storage_options={  
        "key": s3_minio_access_key,  
        "secret": s3_minio_secret_key,  
        # https://github.com/mlflow/mlflow/issues/1990#issuecomment-659914180  
        "client_kwargs": {"endpoint_url": "http://localhost:9000"},  
    },  
    compression='gzip'  
)  
  
print(df)

Вообще, все примеры того, как можно использовать S3 Minio описаны в официальном GitHub пакета.

В данной статье я показал только основы того как можно взаимодействовать с S3 для своих пет-проектов.

Вообще, S3 набирает популярность в дата-инженерии, потому что довольно простой по своей структуре сервис и покрывает множеств задач дата-инженеров.

Также S3 можно улучшать при помощи сторонних сервисов:

  1. Apache Hudi

  2. LakeFS

  3. etc

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

Также если вам необходима консультация/менторство/мок-собеседование и другие вопросы по дата-инженерии, то вы можете обращаться ко мне. Все контакты указаны по ссылке.

© Habrahabr.ru