5просмотров

💽 Переход на S3 через ActiveStorage Mirroring

В этом посте я расскажу, как безопасно перейти на S3 для хранения всех файлов Ruby on Rails-приложения.

Краткий план

Чтобы безопасно перейти на S3 (self-hosted/AWS), сначала нужно скопировать все существующие файлы так, чтобы они хранились и у нас (local), и на сервере (S3). Только после этого можно спокойно удалить локальные файлы и полностью перейти на удалённое хранение.

Настройка зеркалирования

В config/storage.yml добавляем конфигурации для локального, S3 и mirror-сервисов:

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

s3: # имя можно выбрать любое, например aws
  service: S3
  endpoint: "https://s3.example.com"
  access_key_id: <%= Rails.application.credentials.dig(:s3, :access_key_id) %>
  secret_access_key: <%= Rails.application.credentials.dig(:s3, :secret_access_key) %>
  region: us-east-1 # укажите ваш регион
  bucket: <%= Rails.application.credentials.dig(:s3, :bucket) %>
  force_path_style: true

mirror:
  service: Mirror
  primary: local
  mirrors: [s3]

Я использовал Rails.application.credentials для хранения чувствительных токенов, но вы можете взять их из любых ENV-переменных или другого хранилища.

Секция mirror — это и есть «магия»: здесь мы указываем, что хотим хранить файлы и локально, и дублировать их в S3.

Далее в нужном окружении (config/environments/production.rbconfig/environments/staging.rb и т. п.) переключаем сервис:

# config/environments/production.rb

config.active_storage.service = :mirror

Советую включать :mirror только в окружениях на серверах, а в development и test оставить :local.

Копирование существующих файлов

После обновления конфигурации новые файлы сразу будут сохраняться через mirror, а старые останутся в локальной папке. Чтобы их перенести, выполняем в консоли:

# Один раз
ActiveStorage::Blob.update_all(service_name: "mirror")
ActiveStorage::Blob.find_each { |blob| blob.mirror_later }

Этот код обновит все записи и запустит фоновые задачи для загрузки файлов в S3. После этого все старые файлы появятся в облаке, и новые тоже будут дублироваться.

Спасибо Oliver Eidel за его пост, который помог разобраться с миграцией.

Полный переход на S3

Когда все файлы успешно скопированы:

  1. Удаляем секцию mirror из config/storage.yml — она больше не нужна.
  2. Меняем в окружениях config.active_storage.service = :mirror на config.active_storage.service = :s3 (или на имя вашего S3-сервиса).

Чтобы сделать S3 «мастером» для всех существующих записей, выполняем:

ActiveStorage::Blob.update_all(service_name: "s3")

Опционально: можно очистить локальное хранилище:

Сначала убедитесь, что все файлы хранятся в s3!

rm -rf storage/

Готово! Теперь ваше Ruby on Rails-приложение хранит все файлы только в S3.