В этой статье я бы хотел рассказать о такой технологии как 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 вы можете проверить наличие файла
Важное свойство, которое стоит знать при работе с path в bucket – это то что можно указать свой path руками. Если посмотреть на пример выше, то у нас path выглядит так:
file_name = 'titanic.csv'
, но можно задать любой path, для примера вот так: file_name = 'raw/kaggle/2022-04-01/titanic.csv'
и получим в bucket такую структуру:
Также стоит отметить, что если мы удалим файл по данному 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 можно улучшать при помощи сторонних сервисов:
Apache Hudi
LakeFS
etc
Пишите в комментариях, что ещё хотели бы узнать про S3 и сервисы для дата-инженеров.
Также если вам необходима консультация/менторство/мок-собеседование и другие вопросы по дата-инженерии, то вы можете обращаться ко мне. Все контакты указаны по ссылке.
Комментарии (8)
temadiary
06.07.2024 05:45не ясно почему выбраны и для чего те или иные пакеты
на веру? ну такое, всё равно что копипастить с SOk0rsakov Автор
06.07.2024 05:45minio – нужен для общения с Minio
pandas – для чтения удаленного .csv и удобной работы с ним
fsspec – необходимый пакет для записи в S3
s3fs – необходимый пакет для записи в S3
lair
06.07.2024 05:45S3 (Simple Storage Service) — протокол передачи данных, разработанный компанией Amazon. Также — объектное хранилище.
Вообще-то, это сервис, предлагаемый Amazon (даже из названия - Simple Storage Service - это следует). MinIO - это имитация амазоновского сервиса, которая поддерживает тот же протокол, чтобы было проще заменять одно на другое. При этом внутренняя функциональность у них не обязана быть одинаковой.
Ну а то, что вы для работы с S3 используете пакет MinIO, лишний раз показывает, что вы не понимаете, кто на ком стоял, и зачем это на самом деле нужно.
lev
06.07.2024 05:45+1Тоже немного позанудствую - никакого path в s3 нет, есть понятие key, который может выглядеть как '0/1/path/to/file.txt'
https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html
lair
06.07.2024 05:45...и использование
/
, афаик,только конвенция, и штатный апи позволяет при запросе списка объектов бить по разным сепараторам.
temadiary
так какие зависимости?
из команды установки сложно разобраться какие именно package's нужны
pip install -r requirements.txt
k0rsakov Автор
minio==7.2.7
pandas==2.2.2
fsspec==2024.6.1
s3fs==2024.6.1
vanzhiganov
Вот же полный список зависимостей:
aiobotocore==2.13.1
aiohttp==3.9.5
aioitertools==0.11.0
aiosignal==1.3.1
argon2-cffi==23.1.0
argon2-cffi-bindings==21.2.0
attrs==23.2.0
botocore==1.34.131
certifi==2024.7.4
cffi==1.16.0
frozenlist==1.4.1
fsspec==2024.6.1
idna==3.7
jmespath==1.0.1
minio==7.2.7
multidict==6.0.5
numpy==2.0.0
pandas==2.2.2
pycparser==2.22
pycryptodome==3.20.0
python-dateutil==2.9.0.post0
pytz==2024.1
s3fs==2024.6.1
six==1.16.0
typing_extensions==4.12.2
tzdata==2024.1
urllib3==2.2.2
wrapt==1.16.0
yarl==1.9.4