Собственное S3-хранилище на базе MinIO
В этой статье разберём, что такое S3 и Объектные хранилища, где его взять, а также как поднять своё собственное на VPS используя MinIO.
Реклама
В статье "Гайд по первоначальной настройке VPS" я упомянул об утилите для создания бэкапов — ReBack. В процессе разработки стояла задача найти компромисс для хранения бекапов, который соответствовал бы следующим параметрам: надежно, просто, быстро и надолго - таким решением мне показалось использование S3 хранилища.
После публикации статьи начали поступать вопросы о том "как создать и настроить своё S3-хранилище?"
Поэтому в этой статье мы рассмотрим:
- какие бывают виды хранилищ?
- что из себя представляет S3 хранилище?
- какие есть способы получить S3 хранилище?
- как развернуть собственное S3 хранилище с помощью MinIO?
Что такое S3 и объектное хранилище?
S3 (Simple Storage Service) — это облачный сервис для хранения файлов, предоставляемый компанией Amazon. Он предназначен для хранения неструктурированных данных (или объектов) в интернете. Основное преимущество S3 заключается в его удобстве и масштабируемости: пользователи могут хранить практически неограниченное количество данных и управлять ими через простой интерфейс.
Со временем протокол и стандарт, изначально разработанные Amazon, стали использоваться другими компаниями для создания альтернативных решений. Такие сервисы называют S3-совместимыми. Они поддерживают те же API и функционал, что и оригинальный Amazon S3, что делает их удобным выбором для разработчиков.
Стоит отметить, что название S3 стало именем нарецательным, то есть оно применимо как и к оригинальному продукту от Amazon, так и к S3-совместимым решениям, будь то Minio или S3 от хостинг провайдера.
Объектное хранилище — это система, где данные хранятся не в традиционной файловой структуре, а в виде объектов. Каждый объект состоит из:
- Данных (содержимое файла).
- Метаданных (дополнительной информации о данных, например, даты создания или типа файла).
- Уникального идентификатора (обычно называемого ключом или названием объекта).
Этот подход к хранению данных обладает несколькими важными преимуществами:
- Простота масштабирования для хранения огромных объёмов данных.
- Возможность эффективного доступа через API, вместо традиционного файлового интерфейса.
Объектные хранилища идеально подходят для работы с большими объёмами неструктурированных данных, таких как:
- Изображения и видео.
- Резервные копии.
- Журналы.
- Научные данные.
Как получить S3-хранилище
Существует два основных способа обзавестись S3-хранилищем: использование облачных решений или развёртывание собственного (Self-Hosted) хранилища.
Облачные решения
Облачные S3-хранилища предоставляются хостинг-провайдерами, которые берут на себя все технические аспекты, такие как управление ресурсами, настройка доступов и поддержка инфраструктуры. Пользователю нужно лишь выбрать подходящий тариф, оплатить его и получить данные для подключения.
Преимущества облачных решений:
- Простота настройки и использования.
- Удобный веб-интерфейс для управления хранилищем.
- Автоматическое масштабирование и техническая поддержка.
Примеры облачных решений:
- Amazon AWS S3 — оригинальное S3-хранилище от Amazon.
- TimeWeb — удобное S3-совместимое решение с серверами на территории России.
- Cloud.ru — предоставляет 15 ГБ бесплатного хранилища на момент написания статьи.
- Другие хостинги — существует множество провайдеров с различными ценами и условиями, но все они совместимы с протоколом Amazon S3.
Self-Hosted решения
Self-Hosted хранилища разворачиваются на собственных серверах. Этот вариант требует больше усилий и знаний, но предоставляет полный контроль над данными и их безопасностью.
Преимущества Self-Hosted решений:
- Полная автономность и контроль над данными.
- Возможность настройки под собственные нужды.
- Отсутствие зависимости от сторонних провайдеров.
Примеры Self-Hosted решений:
- MinIO — масштабируемое объектное хранилище, полностью совместимое с API S3.
- Zenko — платформа для управления несколькими облачными хранилищами и гибридными облаками.
- Ceph — распределённая система хранения с высокой отказоустойчивостью.
- Другие — например, Nextcloud (для обмена файлами) или OpenStack (для создания частных облаков).
Что мы будем использовать?
В этой статье мы будем использовать MinIO, так как это популярное, простое в настройке и экономичное решение.
MinIO — высокопроизводительная платформа для объектного хранения, полностью совместимая с Amazon S3 API. Она может быть развёрнута как на локальных серверах, так и в облачных инфраструктурах. MinIO поддерживает основные возможности объектного хранилища, такие как:
- Управление версиями объектов.
- Создание бакетов.
- ACL (списки управления доступом).
MinIO ориентирован на масштабируемость и простоту использования, что делает его отличным выбором для Self-Hosted решений.
- Официальный сайт: https://min.io/
- Документация: https://min.io/docs/
Что ещё понадобится?
- VPS
Если у вас ещё нет настроенного VPS, вы можете ознакомиться с инструкцией в статье "Гайд по первоначальной настройке VPS". - Docker
MinIO будет установлен в контейнере, поэтому необходим Docker. Установку Docker я также описывал в вышеупомянутом гайде. - Caddy (веб-сервер)
Для обработки запросов и управления HTTPS-соединением мы будем использовать Caddy — простой и удобный веб-сервер. Подробнее об этом сервере можно почитать в статье "Веб-сервер Caddy - Альтернатива NGINX и Apache". - Доменное имя
Для доступа к MinIO по HTTPS нужно доменное имя, настроенное с помощью A-записи. Если вы не знаете, как это сделать, ознакомьтесь с постом "Docker 5.1 Почтовый сервер на Docker Mailserver - настройка домена".
Docker Compose
Директория проекта
Для удобства работы создадим отдельную директорию для проекта, чтобы все необходимые файлы находились в одном месте.
Если вы подключены к VPS от имени пользователя root
, его домашняя директория будет /root/
. Если используется другой пользователь, то домашняя директория будет /home/user_name/
. Все команды ниже выполняются из домашней директории текущего пользователя.
Сначала создадим директорию для проекта и сразу перейдём в неё:
mkdir minio && cd minio
minio
— это имя директории, в которой будет располагаться наш проект.
Проверьте, что вы находитесь в нужной директории, выполнив команду pwd
. Результат должен быть следующим:
- Для пользователя
root
:/root/minio/
- Для другого пользователя:
/home/user_name/minio/
Создание файла docker-compose.yml
Теперь создадим файл docker-compose.yml
, где будут описаны сервисы для MinIO и Caddy.
Чтобы создать и открыть файл, воспользуемся редактором nano
. Если файл ещё не существует, nano
автоматически создаст его при сохранении изменений.
Выполним команду:
nano docker-compose.yml
nano
— это текстовый редактор, простой и удобный для работы в терминале.
Файл docker-compose.yml
После выполнения команды откроется окно редактора, в котором нам необходимо описать конфигурацию сервисов.
Первая строка будет ключом services:
:
services:
Важно! Формат YAML
требует строгого соблюдения отступов! Каждый уровень вложенности должен быть отделён ДВУМЯ ПРОБЕЛАМИ!
Сервис Caddy
Начинаем с описания сервиса для Caddy.
После строки services:
делаем два пробела и прописываем ключ caddy:
. На следующей строке, после отступа, прописываем параметры для этого сервиса.
Нам нужно указать 5 ключей:
image:
— образ для использования. Указываемcaddy:latest
для последней версии образа.container_name:
— задаём имя контейнераcaddy
. Если имя не указано, контейнер получит имя по умолчанию, например,minio-caddy-1
, что менее удобно.restart:
— политика перезапуска контейнера. Используем значениеunless-stopped
, чтобы контейнер перезапускался автоматически, пока его не остановят вручную.ports:
— перенаправление портов. Прописываем внешний и внутренний порты:- "80:80"
— для HTTP.- "443:443"
— для HTTPS.
volumes:
— монтирование локальных директорий и файлов в контейнер:- ./Caddyfile:/etc/caddy/Caddyfile
— локальный файлCaddyfile
будет заменять файл внутри контейнера.- caddy_data:/data
и- caddy_config:/config
— Docker volume для хранения данных и конфигурации, чтобы данные сохранялись при перезапуске контейнера.
Готовое описание сервиса Caddy:
services:
caddy:
image: caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
Сервис MinIO
После описания сервиса caddy
оставляем пустую строку и на уровне двух отступов добавляем ключ minio:
.
В этом сервисе пропишем семь ключей, некоторые из которых уже знакомы:
image:
— используем образminio/minio:latest
.container_name:
— задаем имя контейнераminio
.restart:
— используем политикуunless-stopped
, чтобы контейнер перезапускался при сбоях, но не при остановке вручную.volumes:
— подключаем Docker volumes для хранения данных, чтобы они не терялись при перезапуске контейнера:- minio-storage:/data
- minio-config:/root/.minio
Новые ключи:
environment:
— передаем массив переменных окружения внутрь контейнера в формате "ключ=значение":- MINIO_ROOT_USER=miniouser
— задаем имя пользователя для администратора.- MINIO_ROOT_PASSWORD=admin123
— задаем пароль администратора.- MINIO_BROWSER_REDIRECT_URL=https://your_domain.com/console/
— указываем путь, по которому будет доступна консоль MinIO. Адрес должен включатьhttps://
и маршрут.- MINIO_DOMAIN=your_domain.com
— задаем домен, на котором будет работать MinIO (безhttps://
).
command:
— указывает команду, которая будет выполнена при запуске контейнера. В нашем случае это команда для старта сервиса:server /data --console-address ":9001"
.healthcheck:
— настройка для проверки состояния контейнера. Используем типичный пример из документации для MinIO.
Готовое описание сервиса:
minio:
image: minio/minio:latest
container_name: minio
restart: unless-stopped
volumes:
- minio-storage:/data
- minio-config:/root/.minio
environment:
- MINIO_ROOT_USER=miniouser
- MINIO_ROOT_PASSWORD=admin123
- MINIO_BROWSER_REDIRECT_URL=https://your_domain.com/console/
- MINIO_DOMAIN=your_domain.com
command: server /data --console-address ":9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
Docker-Volume
Мы прописали использование Docker-volume, но не инициализировали их.
После сервиса minio
оставляем пустую строку и прописываем ключ volumes:
без отступов от границы. Далее, на внутреннем уровне добавляем используемые Docker-volume:
volumes:
caddy_data:
caddy_config:
minio-storage:
minio-config:
Полный пример конфигурации
services:
caddy:
image: caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
minio:
image: minio/minio:latest
container_name: minio
restart: unless-stopped
volumes:
- minio-storage:/data
- minio-config:/root/.minio
environment:
- MINIO_ROOT_USER=miniouser
- MINIO_ROOT_PASSWORD=admin123
- MINIO_BROWSER_REDIRECT_URL=https://your_domain.com/console/
- MINIO_DOMAIN=your_domain.com
command: server /data --console-address ":9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
volumes:
caddy_data:
caddy_config:
minio-storage:
minio-config:
Сохраняем файл с помощью CTRL+S
и выходим из редактора, нажав CTRL+X
.
Caddyfile
После настройки конфигурации Docker Compose, необходимо создать файл конфигурации для Caddy.
Откроем файл с помощью редактора, чтобы он создался при сохранении:
nano Caddyfile
Формат Caddyfile напоминает упрощённый JSON, поэтому сначала покажу готовую конфигурацию, а затем разберём её:
your_domain.com {
tls info@pressanybutton.ru
log {
output stdout
format json
level WARN
}
reverse_proxy /console/api/* minio:9000 {
header_up Host {host}
header_up X-Real-IP {remote}
}
handle_path /console/* {
reverse_proxy minio:9001 {
header_up Host {host}
header_up X-Real-IP {remote}
}
}
handle_path /* {
reverse_proxy minio:9000 {
header_up Host {host}
header_up X-Real-IP {remote}
}
}
}
- Сначала прописывается доменное имя, за которым открываются фигурные скобки.
- Внутри блока указываем ключ
tls
с адресом электронной почты. Это сообщает Caddy, что нужно получить SSL-сертификат для этого домена для работы через HTTPS. - В блоке
log
указываем, что выводить следует только предупреждения уровняWARN
и выше в формате JSON. Это исключает информационные сообщения и оставляет только важные логи. - Далее начинается интересная часть. Обычно панель управления и API-сервис располагают на разных доменах, но для удобства мы будем использовать один.
- В блоке
reverse_proxy
перенаправляем запросы с пути/console/api/*
на API-портminio:9000
. Здесьminio
— это имя сервиса вdocker-compose.yml
, а9000
— внутренний порт контейнера.
- В блоке
- С помощью
handle_path
отслеживаем путь/console/*
и перенаправляем запросы на порт консолиminio:9001
. - В конце, чтобы правильно обрабатывать запросы к API, с помощью
handle_path
отслеживаем все остальные маршруты/*
и перенаправляем их на API-портminio:9000
. - Во всех блоках мы передаем вместе с запросом информацию о хосте и IP-адресе клиента. Это необходимо для корректной работы MinIO.
После внесения изменений сохраняем файл с помощью CTRL+S
и выходим из редактора, нажав CTRL+X
.
Альтернатива: Использование NGINX
Не все хотят использовать Caddy в качестве веб-сервера по разным причинам, поэтому решено вкратце рассказать об альтернативном варианте - использование веб-сервера NGINX.
Изменения в docker-compose.yaml
Для того, чтобы сменить Caddy на NGINX, необходимо модифицировать docker-compose.yml
:
services:
nginx:
image: nginx:latest
container_name: nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/ssl
- nginx_data:/data
image
- теперь ссылается на образnginx
.volumes
- тут несколько изменений:- Вместо Caddyfile, мы передаём файл конфигурации
nginx.conf
- Подключаем локальную директорию с SSL-сертификатами. Как их получить описано в статье "Certbot - бесплатный SSL-сертификат для сайта"
- Подключаем Docker volume -
nginx_data
. Не забудьте добавить его в блокvolumes
в конце файла!
- Вместо Caddyfile, мы передаём файл конфигурации
Файл конфигурации nginx.conf
Структура и принцип работы достаточно сильно отличается от Caddyfile.
Создадим файл nginx.conf
открыв его в редакторе nano
:
nano nginx.conf
И пропишем следующее содержимое:
worker_processes auto;
events {
worker_connections 1024;
}
http {
log_format json '{ "time_local": "$time_local", "remote_addr": "$remote_addr", "request": "$request", "status": "$status", "body_bytes_sent": "$body_bytes_sent", "request_time": "$request_time", "upstream_response_time": "$upstream_response_time", "remote_user": "$remote_user", "http_referer": "$http_referer", "http_user_agent": "$http_user_agent" }';
access_log /var/log/nginx/access.log json;
error_log /var/log/nginx/error.log warn;
upstream minio_s3 {
server minio:9000;
}
upstream minio_console {
server minio:9001;
}
server {
listen 80;
listen [::]:80;
server_name storage.napkincontent.ru;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name storage.napkincontent.ru;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
location / {
proxy_pass http://minio_s3;
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;
}
location /console/ {
rewrite ^/console/(.*) /$1 break;
proxy_pass http://minio_console;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
Разбор конфигурации:
worker_processes auto;
— указывает NGINX автоматически определять количество рабочих процессов в зависимости от числа доступных ядер процессора.events { worker_connections 1024; }
— настраивает количество одновременных подключений, которые NGINX может обрабатывать в одном рабочем процессе.http { ... }
— блок, который включает настройки для обработки HTTP-запросов.log_format json
— указывает формат логирования запросов в формате JSON. Это позволяет собирать информацию о запросах в структурированном виде.upstream minio_s3
иupstream minio_console
— блоки, которые настраивают пул серверов для проксирования запросов.server { listen 80; ... }
— перенаправление всех HTTP-запросов на HTTPS. Это гарантирует, что трафик всегда будет зашифрован.server { listen 443 ssl; ... }
— конфигурация для работы через HTTPS. Здесь мы указываем сертификаты SSL (ssl_certificate
иssl_certificate_key
), а также настраиваем проксирование запросов:location / { proxy_pass http://minio_s3; ... }
— проксируем запросы на основной сервис MinIO (порт 9000).location /console/ { ... }
— проксируем запросы на консоль MinIO (порт 9001), с дополнительной настройкой для корректной работы WebSocket-соединений, необходимых для работы интерфейса MinIO.
proxy_set_header
— эти строки обеспечивают правильную передачу заголовков при проксировании запросов, что важно для корректной работы с хостом и IP-адресами клиентов.
После внесения изменений сохраняем файл с помощью CTRL+S
и выходим из редактора, нажав CTRL+X
.
Перед запуском не забудьте создать директорию ssl
и поместить в неё ваши SSL-ключи и удостоверьтесь, что названия файлов совпадают с указанными в nginx.conf
.
Запуск
Теперь, когда все настройки завершены, осталось только запустить сервисы!
Для этого выполните команду:
sudo docker compose up -d
up
— указывает на запуск сервисов, определённых в Docker Compose.-d
— запускает контейнеры в фоновом режиме.
Запуск начнётся с загрузки образов. Когда процесс завершится, вы увидите сообщение Started
рядом с именем контейнера.
Теперь откройте в браузере домен, указанный в конфигурации. Если все сделано правильно, вас встретит страница авторизации:
Минимальная настройка
После авторизации вы попадаете в консоль управления вашим хранилищем.
MinIO предоставляет множество настроек, политик безопасности и других опций. Чтобы не перегружать вас лишней информацией, рассмотрим только несколько ключевых моментов: как указать регион, создать бакет и получить ключи доступа.
Указание региона
В оригинальном Amazon S3 параметр "Регион" определяет физическое местоположение сервера. Однако, в S3-совместимых хранилищах этот параметр может быть реализован по-разному: где-то его просто нет, а где-то используется "заглушка".
Это связано с тем, что протокол совместимости S3 требует обязательного указания региона. В некоторых случаях отсутствие региона может вызвать конфликты, особенно при использовании библиотек, предназначенных для Amazon S3. Несмотря на то, что MinIO не требует указания региона, для обеспечения лучшей совместимости с другими сервисами, его всё же рекомендуется указать.
Для этого откройте раздел "Configuration". В первом пункте конфигурации — "Region" — укажите нужный регион. Например, у хостинга TimeWeb это может быть "ru-1", а у Cloud.ru — "ru-central-1".
Для примера давайте укажем "ru-central-1" и нажмём "Save":
После сохранения появится уведомление, что для применения изменений необходимо перезагрузить сервер. Нажмите "Restart", чтобы завершить настройку.
Создание ключа доступа
Чтобы подключаться к вашему S3-хранилищу с помощью сторонних программ (например, ReBack) или библиотек (например, boto3
для Python), необходимо создать пару ключей: access
и secret
.
Для этого перейдите в раздел "Access Keys" и нажмите кнопку "Create access key".
На следующей странице вам будут показаны ключи: access
и secret
. Обязательно сохраните их в безопасном месте, так как после создания их можно будет увидеть только один раз — в дальнейшем они станут недоступными и их придётся создавать заново.
На этой странице также можно указать срок действия ключа, его название и описание.
Нажмите "Create".
После этого вам снова покажут ваши ключи и предупредят, что в следующий раз они будут недоступны для просмотра.
Создание бакета
Чтобы хранить файлы в объектном хранилище, необходимо создать "Бакет". Это своего рода контейнер, к которому будет происходить подключение. В MinIO можно создать несколько бакетов, каждый для разных задач или файлов.
Для создания бакета откройте раздел "Buckets" и нажмите "Create Bucket".
На открывшейся странице в поле "Bucket Name" введите имя бакета. Имя бакета должно соответствовать строгим правилам, которые можно просмотреть, нажав кнопку "View Bucket Naming Rules". Также на этой странице доступны дополнительные настройки, такие как контроль версий или ограничения на размер загружаемых файлов.
Я назову свой бакет "local-backups", после чего нажму "Create Bucket".
После создания бакета вы можете перейти в раздел "Object Browser" и загрузить файлы напрямую в бакет:
Также можно использовать программы или библиотеки, например, результат работы ReBack:
Заключение
S3-хранилища стали отраслевым стандартом для хранения файлов. Они используются не только для бэкапов и файлов пользователей, но и для других целей. Например, вы можете настроить Django для хранения статей и изображений, а вариантов применения таких хранилищ масса.
Теперь, благодаря этому руководству, вы знаете, что такое S3-хранилище, как его получить или как развернуть собственное решение на базе MinIO.
Все статьи