3переглядів

💽 Перехід на 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.rb, config/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.