はじめに
RailsをAWSなどのクラウド上で動かしている場合、carrierwaveなどを使って、S3に画像をアップロードして、CloudFrontなどのCDNで配信するケースはよくあると思います。
こんなとき、別のテスト環境にデータと画像を移行したいとか、画像のバックアップをローカル・オンプレに取得しておきたい・・・なんてことが最近あり、rakeでタスク化して対処しました。
実装方法
Gemfile
gem 'aws-sdk'
lib/tasks/aws.rake
require 'aws-sdk'
AWS.config(
access_key_id: '<Access Key Id>',
secret_access_key: '<Secret Access Key>',
s3_endpoint: "s3-ap-northeast-1.amazonaws.com")
namespace :aws do
desc 'backup files in bucket.'
task :s3backup => :environment do
bucket_name = ENV['BUCKET']
s3 = AWS::S3.new
bucket = s3.buckets[bucket_name]
raise "Not found bucket #{bucket_name}" if bucket.nil?
backup_dir = File.expand_path("tmp/backup_#{Time.now.strftime("%Y-%m-%d_%H-%M-%S")}")
bucket.objects.each do |obj|
next if o.key.end_with?('/')
puts "#{Time.now} writing #{o.key}"
path = File.join(backup_dir, obj.key)
dir = File.dirname(path)
FileUtils.mkdir_p(dir) unless FileTest.exists?(dir)
File.open(path, 'wb') do |file|
obj.read do |chunk|
file.write(chunk)
end
end
end
end
end
- バケット名はrakeコマンド実行時に渡します。
- Railsルートのtmp配下に現在日時つきのフォルダを作成する形としてます。
- サブフォルダがあっても、フォルダ構造を維持した状態でバックアップ可能です。
- Railsじゃなくても利用可能なように、あえてActiveSupportは利用してません。
使い方
rake aws:s3backup BUCKET=my_bucket
ちなみに、定期的にバックアップしたい場合は、rakeをジョブスケジューラに登録するのもよいですね。