👻

期間制約を考慮したS3ストレージクラスのライフサイクル設定

2024/04/25に公開

ストレージクラスの移行

S3ではライフサイクルを使用することでオブジェクトのストレージクラスを移行することができる。ストレージクラスを変更することで、可用性と価格を制御することができる。

移行元と移行先のストレージクラスには制約があり、任意のストレージクラス間で変更できるわけではない。サポートされているストレージクラスの移行は以下の通り。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/lifecycle-transition-general-considerations.html

ストレージクラスの移行に伴う最小日数

ストレージクラスの変更について、種類だけでなく日数に関する制約も存在する。具体的には以下の通り。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/storage-class-intro.html#sc-compare

ストレージクラス 最小ストレージ期間
Standard IA 30日
One Zone IA 30日
Glacier Instant Retrieval 90日
Glacier Flexible Retrieval 90日
Glacier Deep Archive 180日
その他 なし

ただし、Standard IAおよびOne Zone IAに対する最小ストレージ期間の意味と、Glacier系に対する最小ストレージ期間の意味は少し異なる。

Standard IAおよびOne Zone IAは最小ストレージ期間以下のオブジェクトは許容されない。すなわち、作成してから29日以下のオブジェクトをStandard IAまたはOne Zone IAに移行することはできない。このようなライフサイクル設定を作成しようとするとエラーになってしまう。

一方でGlacier系は最小ストレージ期間を下回るオブジェクトは作成可能だが、料金は最小ストレージ期間の分だけ請求される。このため、オブジェクト作成直後にGlacierのストレージクラスに移行するライフサイクル設定を作成することは可能。

これについても公式ドキュメントに記載がある。

S3 標準 - IA または S3 1 ゾーン - IA にオブジェクトを移行する前に、これらのオブジェクトを少なくとも 30 日間 Amazon S3 に保存する必要があります。例えば、作成から 1 日後にオブジェクトを S3 標準 – IA ストレージクラスに移行するライフサイクルルールを作成することはできません。

Amazon S3 Glacier にアーカイブされているデータの削除は、削除するオブジェクトが最小ストレージ期間より長い期間アーカイブされている場合は無料です。アーカイブされたオブジェクトを最小ストレージ期間以内に削除または上書きする場合は、Amazon S3 によって比例配分された早期削除料金が課金されます。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/lifecycle-transition-general-considerations.html?icmpid=docs_amazons3_console

terraformによる移行日数の指定

terraformでS3のライフサイクルを指定するには aws_s3_bucket_lifecycle_configuration リソースを利用する。公式ドキュメントに記載の通り以下のように設定可能。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration

resource "aws_s3_bucket_lifecycle_configuration" "example" {
  bucket = aws_s3_bucket.example.id

  rule {
    id = "rule-1"
    status = "Enabled"

    transition {
      days = 30
      storage_class = "STANDARD_IA"
    }
    transition {
      days = 60
      storage_class = "GLACIER"
    }

  }
}

ただし、ドキュメントに記載の通り対象のストレージクラスによって指定可能な日数は異なる。
設定不可能な日数を指定するとterraform apply時にエラーになる。具体的なエラーメッセージは以下の通り。

Valid values depend on storage_class, see Transition objects using Amazon S3 Lifecycle for more details.

$ cat main.tf
resource "aws_s3_bucket" "example" {
  bucket = "sample-lifecycle-configuration-min-duration"
}

resource "aws_s3_bucket_lifecycle_configuration" "example" {
  bucket = aws_s3_bucket.example.id

  rule {
    id     = "example-rule"
    status = "Enabled"

    transition {
      storage_class = "ONEZONE_IA"
    }
  }
}
$ terraform apply
...
╷
│ Error: updating S3 Bucket Lifecycle Configuration (sample-lifecycle-configuration-min-duration): operation error S3: PutBucketLifecycleConfiguration, https response error StatusCode: 400, RequestID: TZJVZJ0AEA87Q25D, HostID: h6xl6MDiy3B1fsOmhN8yxG6DmsTAZruFAftZksmZ168+DTO82ITul1tAr320LvEI6ENr2yx/uPc=, api error InvalidArgument: 'Days' in Transition action must be greater than or equal to 30 for storageClass 'ONEZONE_IA'
│ 
│   with aws_s3_bucket_lifecycle_configuration.example,
│   on main.tf line 5, in resource "aws_s3_bucket_lifecycle_configuration" "example":
│    5: resource "aws_s3_bucket_lifecycle_configuration" "example" {
│ 
╵

より詳細なapply errorとなる条件は以下の通り。

  1. storage_classに"STANDARD_IA" または "ONEZONE_IA"を指定しており、daysの指定が30未満

daysの指定が30未満、またはdaysもdateも指定しないとdaysに0が指定されたものと見なされるのでこれもエラーになる。明示的に30以上の日数を指定する必要がある。

エラーになる例
resource "aws_s3_bucket_lifecycle_configuration" "example" {
  bucket = aws_s3_bucket.example.id

  rule {
    id     = "example-rule"
    status = "Enabled"

    transition {
      days          = 3
      storage_class = "ONEZONE_IA"
    }
  }
}
  1. 複数のtransitionルールを指定しており、日数の条件が移行可能なストレージ間に対応していない

30日経過したらONEZONE_IAに、60日経過したらGLACIERに移行するというルールはSTANDARD -> ONEZONE_IA -> GLACIERというストレージクラス間の移行が許容されているので設定できる。

成功する例
resource "aws_s3_bucket_lifecycle_configuration" "example" {
  bucket = aws_s3_bucket.example.id

  rule {
    id     = "example-rule"
    status = "Enabled"

    transition {
      days = 30
      storage_class = "ONEZONE_IA"
    }
    transition {
      days          = 60
      storage_class = "GLACIER"
    }
  }
}

逆に、30日経過したらGLACIER、60日経過したらSTANDARD_IAに移行するというルールは GLACIER -> STANDARD_IAのストレージクラス間移行が許容さていないので設定できない。
同様に、ONEZONE_IA -> STANDARD_IAの移行も許容されていないので、STANDARD_IAのtransition.daysはONEZONE_IAのtransition.daysより大きな値を指定しなくてはならない

エラーになる例
resource "aws_s3_bucket_lifecycle_configuration" "example" {
  bucket = aws_s3_bucket.example.id

  rule {
    id     = "example-rule"
    status = "Enabled"

    transition {
      days          = 30
      storage_class = "GLACIER"
    }
    transition {
      days          = 60
      storage_class = "ONEZONE_IA"
    }
  }
}
$ terraform apply
...
aws_s3_bucket_lifecycle_configuration.example: Modifying... [id=sample-lifecycle-configuration-min-duration]
╷
│ Error: updating S3 Bucket Lifecycle Configuration (sample-lifecycle-configuration-min-duration): operation error S3: PutBucketLifecycleConfiguration, https response error StatusCode: 400, RequestID: GYDRVEMB933B3393, HostID: e3TiVNz0ksNdethv7psJUFIl+ii30LjfUiq5J6c4uMr6f/WxFyhbkqvJ7jUbFB4IVjc9VHifA5lN+o9OZ77+8w==, api error InvalidArgument: 'Days' in the 'Transition' action for StorageClass 'GLACIER' for filter '(prefix=)' must be greater than 'Days' in the 'Transition' action for StorageClass 'ONEZONE_IA' for filter '(prefix=)'
│ 
│   with aws_s3_bucket_lifecycle_configuration.example,
│   on main.tf line 5, in resource "aws_s3_bucket_lifecycle_configuration" "example":5: resource "aws_s3_bucket_lifecycle_configuration" "example" {
│ 
╵

エラーにならないケースとして、dateを指定する場合がある。
AWSマネコン上では指定できないが、terraformなどのAPIでは移行を実施する日付(date)を指定できる。日付指定の場合はライフサイクル設定作成時ではエラーにならなかった。
未検証だが、ストレージクラスにSTANDARD_IAを指定した場合、Dateで移行日を指定できるが、移行日に条件を満たしていない生成から30日未満のオブジェクトは単に無視される?

Discussion