Sionの技術ブログ

SREとして日々の学習を書いて行きます。twitterは@sion_cojp

AWS S3 Glacierの取り出しをRubyで検証してみる

f:id:sion_cojp:20210316152558p:plain

What

  • S3のGlacier, Glacier Deep Archiveがあるが、実際に取り出したことがあまりない
  • 取り出すにはリクエストが必要
  • 今働いてる chikakurailsをメインにしてるので、rubyで検証しました

Glacier周りの料金や仕様

f:id:sion_cojp:20210316145443p:plain:w400

ref: https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/restoring-objects.html

やったこと

  • s3にオブジェクト(動画)を保存
  • 動画は https://www.home-movie.biz/free_movie.html から拝借しております
  • 下記のように3種類ストレージクラスを用意し、ダウンロードしてみる
    • STANDARD
    • Glacier...今回は迅速取り出し(Expedited)をやります
    • Deep Archive

f:id:sion_cojp:20210316143845p:plain

今回使ったコード

Gemfile

source 'https://rubygems.org'

gem 'aws-sdk-s3'

main.rb

### 秘匿情報はxxxxxで隠してます
### awsにはsaml認証経由でアクセスしてます
require 'aws-sdk-s3'

ENV['AWS_REGION'] = "ap-northeast-1"

def main(object_key)
  bucket_name = 'xxxxx'
  local_path = "./#{object_key}"
  role_arn = "arn:aws:iam::xxxxx:role/xxxxx"
  role_session_name = "xxxxx"

  sts_client = Aws::STS::Client.new(profile: 'saml')
  role_credentials = Aws::AssumeRoleCredentials.new(
    client: sts_client,
    role_arn: role_arn,
    role_session_name: role_session_name
  )

  client = Aws::S3::Client.new(credentials: role_credentials)

  s3_download(client, bucket_name, object_key, local_path)
end

# glacierはrestoreしてからダウンロードする
def s3_download(s3_client, bucket_name, object_key, local_path)
  # storageクラスによってはrestoreする必要があるので、取得する
  resp = s3_client.list_objects_v2(
    {
      bucket: bucket_name,
      prefix: object_key,
    }
  )

  case resp.contents[0].storage_class
  when "STANDARD"
  when "GLACIER"
    restore(s3_client, bucket_name, object_key, local_path, "Expedited")
  when "DEEP_ARCHIVE"
    # こいつだけrestoreが終わるまで下記エラーが出て実行できない
    # Error getting object: Object restore is already in progress
    restore(s3_client, bucket_name, object_key, local_path, "Standard")
  end
  download(s3_client, bucket_name, object_key, local_path)

rescue StandardError => e
  puts "Error getting object: #{e.message}"
end

# glacierはrestoreする
def restore(s3_client, bucket_name, object_key, local_path, tier)
  s3_client.restore_object(
    {
      bucket: bucket_name,
      key: object_key,
      restore_request: {
        days: 1,
        glacier_job_parameters: {
          # https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/restoring-objects.html
          # Standard...標準取り出し
          # Bulk...大容量取り出し
          # Expedited...迅速取り出し。deep archiveは対応してない
          tier: tier
        },
      },
    }
  )
end

# download
def download(s3_client, bucket_name, object_key, local_path)
  s3_client.get_object(
    response_target: local_path,
    bucket: bucket_name,
    key: object_key
  )
end

# 動作確認用
def list_bukets(s3_client)
  puts s3_client.list_buckets
end

# 動作確認用
def list_objects(s3_client, bucket_name)
  s3_client.list_objects(bucket: bucket_name).contents.each do |object|
    p object.key
  end
end

# STANDARD
main(mov_hts-samp001.mp4)

# Glaicer
main(mov_hts-samp002.mp4)

# Deep Archive
main(mov_hts-samp003.mp4)

実行

$ bundle install --path vendor/bundle

# 最初はglacier両方ともエラー
$ bundle exec ruby main.rb
Error getting object: Object restore is already in progress
Error getting object: Object restore is already in progress

# 1分後くらい
$ bundle exec ruby main.rb
Error getting object: Object restore is already in progress

# Glacierはダウンロードできたけど、Deep Archiveはだめだった
# 30分すぎても取り出せないので諦めた

結論