Minio — что это
Minio это простое, быстрое и совместимое с AWS S3 хранилище объектов. Minio создан для размещения неструктурированных данных, таких как фотографии, видеозаписи, файлы журналов, резервные копии, а также образы виртуальных машин и контейнеров. Небольшой размер позволяет включать его в состав стека приложений, аналогичного Node.js, Redis и MySQL. В minio также поддерживается распределенный режим (distributed mode), который предоставляет возможность подключения к одному серверу хранения объектов множества дисков, в том числе расположенных на разных машинах.
Установка Minio
Установка сервера
Поставить и запустить Minio очень просто
brew install minio/stable/minio minio server ~/data
Как советует документация, если была ранее установлена предыдущая версия без указания стабильности, ее необходимо удалить и поставить новую стабильную
brew uninstall minio brew install minio/stable/minio
Справка по командам сервера покажет основные способы его запуска и конфигурации. Локально я его запускаю
minio server --address localhost:9000 ~/data
После запуска сервера он напишет по какому адресу его можно найти, а также ключ с секретным паролем для доступа к нему. Этого в принципе достаточно для начала работы с Minio, подробности — в официальной документации
Установка клиента и основные команды
С помощью клиента Minio можно работать с хранилищем аналогично командной строке Unix. Поставить клиента и посмотреть команды
brew install minio/stable/mc mc --help
из полезного:
mc mb minio/my-uploads-store # создать каталог mc policy -r public minio/my-uploads-store # дать полный доступ к каталогу mc ls minio/my-uploads-store # посмотреть что у нас там есть
В официальном справочном руководстве достаточно подробно все описано
Nginx
Базовые настройки
Nginx позволит сделать много всего полезного, например:
- Спрятать хранилище во внутренней сети
- Организовать кеширование
- Организовать балансировку нагрузки для распределенного хранилища
- Ну и единое место входа для ваших приложений, которое позволит в дальнейшем безболезнено изменить хранилище
Простейшая настройка Nginx дл�� использования Minio
server { listen 80; server_name minio.dev; location / { proxy_set_header Host $http_host; proxy_pass http://localhost:9000; } }
Теперь мы можем обращаться к нашему хранилищу по адресу minio.dev
Кеширование
С кешированием Minio в Nginx как описано в статье у меня были проблемы. Как выяснилось — не только у меня. Выкрутились следующим образом:
- Пишем в хранилище по прямой ссылке на хранилище мимо Nginx (или через него но без кеширования)
- Чтение из хранилища происходит по другой ссылке с кешированием
- Соответствено в нашем RoR приложении ссылка меняется — при записи одна, при чтении — другая с кешированием
proxy_cache_path /var/cache/nginx/minio_cache levels=1:2 keys_zone=minio_cache:10m max_size=10m inactive=60m use_temp_path=off; upstream minio_servers { # можно добавить еще серверов и настроить Load Balancing server localhost:9000; } server { listen 80; server_name minio.dev; location / { proxy_cache minio_cache; add_header X-Cache-Status $upstream_cache_status; proxy_cache_revalidate on; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; proxy_cache_lock on; proxy_ignore_headers Set-Cookie; proxy_cache_valid 1m; proxy_set_header Host $http_host; proxy_pass http://minio_servers; } }
RoR приложениe
Общие настройки
Картинки в Minio загружаем с помощью Shrine (все подробности работы — в неплохой официальной документации и прилагаемых к документации статьях, тут — только особенности для Minio). Непосредственно для работы с Minio необходимо добавить в Gemfile
gem 'shrine-fog' gem 'fog-aws'
require 'shrine/storage/fog' require 'fog/aws' require 'image_processing/mini_magick' minio = Fog::Storage.new( provider: 'AWS', aws_access_key_id: '<key>', aws_secret_access_key: '<secret>', region: 'us-east-1', endpoint: 'http://localhost:9000/', # та самая прямая ссылка path_style: true, ) Shrine.storages[:cache] = Shrine::Storage::Fog.new( connection: minio, directory: '<cache-directory>', public: true, ) Shrine.storages[:store] = Shrine::Storage::Fog.new( connection: minio, directory: '<store-directory>', public: true, )
Само-собой, необходимо через клиента Minio создать соответствующие папки и дать полный доступ к ним (см. раздел выше — клиент Minio).
class AvatarUploader < Shrine include ImageProcessing::MiniMagick plugin :activerecord plugin :determine_mime_type, analyzer: :mime_types plugin :logging, logger: Rails.logger plugin :remove_attachment plugin :store_dimensions plugin :remote_url, max_size: 20*1024*1024 plugin :versions plugin :default_url plugin :processing plugin :host_url, host: 'minio.dev', port: '80' # это собственный плагин, описан чуть дальше Attacher.default_url do |options| # не обязательно, дефолтная картинка '/images/default.svg' end process(:cache) do |io, context| # не обязательно, просто аватар мы у себя уменьшаем при загрузке resize_to_fill!(io.to_io, 300, 300) end end
Собственно, большинство плагинов не обязательны. Подробнее см. официальную документацию к shrine. Обращение как обычно:
User.find(1).avatar_url
Замена ссылки
С заменой ссылки пришлось несколько повозиться. У Shrine достаточно разных плагинов, которые можно использовать для решения большинства задач. ��сть плагин и для замены хоста default_url_options, но в данном конкретном случае он не помог — хост он меняет, а порт игнорирует. Хм, что же делать? А давайте напишем свой собственный плагин к Shrine. Код плагина ниже, как подключается — в предыдущем листинге (80й порт по-умолчанию в итоговой ссылке не прописывается, все остальные — появятся. Можно не писать его, кстати).
class Shrine module Plugins module HostUrl def self.configure(uploader, options = {}) uploader.opts[:host_url] = (uploader.opts[:host_url] || {}).merge(options) end module FileMethods def url(**options) new_uri( URI.parse(super), uploader.opts[:host_url][:host], uploader.opts[:host_url][:port] ) end private def new_uri(uri, new_host, new_port) URI::HTTP.new( uri.scheme, uri.userinfo, new_host, new_port, uri.registry, uri.path, uri.opaque, uri.query, uri.fragment ).to_s end end end register_plugin(:host_url, HostUrl) end end
Код нового плагина положим в lib/shrine/plugins/host_url.rb
Миграция данных
В официальной инструкции, в принципе, все подробно описано. Есть, правда, несколько нюансов — ну там if (attacher = user.avatar_attacher).stored? почему-то возвращает false ну и еще по-мелочи — нужно добавить новое хранилище при существующем старом, сделать миграцию и потом выпилить старое…
Но в данном конкретном случае все можно сделать гораздо проще:
rsync -zavP <юзер>@<удаленный.сервер>:/<путь_к_немигрированным_данным> ~/data/<store-directory>
Собственно все из коробки работает с новым кодом.
Прочее
Да, при переезде на Minio в следующем приложении перенес этот плагин в гем.
Использованные источники
Enterprise-Grade Cloud Storage with NGINX Plus and Minio и русский перевод
