Ruby
Rails
AWS
S3
RubyOnRails

RakeでS3上のファイルを一括ダウンロードする

More than 3 years have passed since last update.

はじめに

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をジョブスケジューラに登録するのもよいですね。