バージョニングファイルと処理済みファイルをタグ付けしてS3 ライフサイクルポリシーで削除

2024.05.18

はじめに

データアナリティクス事業本部ビッグデータチームのyosh-kです。
今回はS3 Bucketの不要なバージョニングファイルとdoneフォルダ(処理済みフォルダ)配下に移動したオブジェクトを特定の期間過ぎたら削除するライフサイクルポリシーの設定をやっていきたいと思います。

前提

今回処理対象のS3 フォルダ構成は以下になります。

前提としてS3 Bucketはバージョニングされているので、src配下のファイルをdone配下に移動した場合、src配下にはバージョニングされたファイルが残ります。今回削除したい要件としては、このsrc配下のバージョニングされたファイルとdoneに移動した処理済みオブジェクトになります。プロジェクトの要件によっては、何年かは過去データを保持する必要があると思いますが、そのままにしておくと永久にファイルは溜まり続けますので、一定の期間が経ったら削除する仕組みを導入したいです。

上記を実現するために、src配下のファイルをdone配下へ移動する処理の前後でそれぞれ別のタグを付与し、タグを条件としてS3 ライフサイクルポリシーで絞り込むことで削除することを実現したいと思います。ファイルの移動とタグ付けについては、以下ブログを参考にシェルスクリプトで実装を実現します。

シェルスクリプト実装

それでは実装になります。実装コードはリンクに格納しています。

@37_move_and_tag_deleting_with_lifecycle_policy % tree
.
├── README.md
└── move_put_tagging.sh

1 directory, 2 files
@37_move_and_tag_deleting_with_lifecycle_policy %
#!/bin/bash
# Move S3 Objects and put them tags.

err() {
  echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}

function tag_object() {
  local bucket_name="$1"
  local object_key="$2"
  local tag_key="$3"
  local tag_value="$4"
  aws s3api put-object-tagging --bucket "$bucket_name" --key "$object_key" --profile "$PROFILE" \
    --tagging "{\"TagSet\": [{\"Key\": \"$tag_key\", \"Value\": \"$tag_value\"}]}" || {
    err "Error: failed to put tag to $bucket_name/$object_key"
    return 1
  }
}

echo "**********START $0 **********"
if [ $# -ne 3 ]; then
  echo "引数が不正です。実行するには3個の引数が必要です。" >&2
  echo "ex) sh move_put_tagging.sh s3://cm-kasama-life-cycle-test/src test_header.csv iam-role" >&2
  err "スクリプトの実行に失敗しました。"
  exit 1
fi

target=$1
DEST_DIR="done/"
EXCLUDE_FILE="test.csv"
EXCLUDE_FILE_HEADER=$2
OBJECT_DELETE_TAG_KEY="delete_marker_tag"
OBJECT_DELETE_TAG_VALUE=true
OBJECT_DONE_TAG_KEY="done_tag"
OBJECT_DONE_TAG_VALUE=true
PROFILE=$3

# 移動するファイルのURIリストを取得
TARGET_OBJECT_URIS="$(aws s3 mv "$target"/ "$target"/"$DEST_DIR" --profile "$PROFILE" --recursive --exclude "$EXCLUDE_FILE" \
  --exclude "$EXCLUDE_FILE_HEADER" --exclude "${DEST_DIR}*" --dryrun | awk '{print $3}')"

for uri in $TARGET_OBJECT_URIS; do
  bucket_name="$(echo "$uri" | cut -d '/' -f 3)"
  object_key="$(echo "$uri" | cut -d '/' -f 4-)"
  tag_object "$bucket_name" "$object_key" "$OBJECT_DELETE_TAG_KEY" "$OBJECT_DELETE_TAG_VALUE"
done

MOVED_OBJECT_URIS="$(aws s3 mv "$target"/ "$target"/"$DEST_DIR" \
  --profile "$PROFILE" --recursive --exclude "$EXCLUDE_FILE" --exclude "$EXCLUDE_FILE_HEADER" \
  --exclude "${DEST_DIR}*" --no-progress --output text | cut -d ' ' -f 4)"
if [ $? -ne 0 ]; then
  # 警告(戻り値:2)の場合も通知する
  echo "エラー通知します。" 1>&2
  err "次のファイル移動に失敗しました。 | ${target}"
  exit 1
fi

echo "S3 objects have been successfully moved to: $target/$DEST_DIR"

for uri in $MOVED_OBJECT_URIS; do
  bucket_name="$(echo "$uri" | cut -d '/' -f 3)"
  object_key="$(echo "$uri" | cut -d '/' -f 4-)"
  tag_object "$bucket_name" "$object_key" "$OBJECT_DONE_TAG_KEY" "$OBJECT_DONE_TAG_VALUE"
done

echo "**********SUCCESS $0 **********"
exit 0

実装の要点については先ほど紹介したブログをご確認いただければと思います。ブログからの変更点としては、移動対象のオブジェクトに対して、移動前にタグを付与するために、aws s3 mvコマンドに--dryrunオプションを追加することで移動対象を抽出してタグを設定しています。

S3 ライフサイクルポリシー設定

次にS3 ライフサイクルポリシーを設定していきます。今回設定するのは3つになります。

done-tag-object-removal-rule

doneに移したオブジェクトを削除するライフサイクルルールになります。一定期間経過したら完全に削除されるように設定します。

  • ライフサイクルルール名: done-tag-object-removal-rule
  • フィルタータイプ:
    • prefix: 未設定
  • オブジェクトタグ:
    • done_tag: true
  • オブジェクトの現行バージョンを有効期限切れにする
    • オブジェクト作成後の日数の指定:1日
  • オブジェクトの非現行バージョンを完全に削除
    • オブジェクトが現行バージョンでなくなってからの日数:1日

オブジェクトを現行バージョン作成後からN日後に有効期限切れにします。今回は検証用に1日と設定していますが、プロジェクトによって適切なデータ保持期間を設定いただければと思います。オブジェクトが非現行バージョンになってからは1日で削除するように設定しています。

delete-marker-tag-object-removal-rule

src配下のバージョニングされたオブジェクトを削除するライフサイクルルールになります。

  • ライフサイクルルール名:delete-marker-tag-object-removal-rule
  • フィルタータイプ:
    • prefix: 未設定
  • オブジェクトタグ:
    • delete_marker_tag: true
  • オブジェクトの非現行バージョンを完全に削除
    • オブジェクトが現行バージョンでなくなってからの日数:1日

src直下のファイルがaws s3 mvで移動されたことでバージョニングされたオブジェクトは非現行バージョンとなり、削除マーカーが現行バージョンとなります。そのため、本ルールで赤枠の非現行バージョンを削除するライフサイクルポリシーとなります。

expired-delete-marker-removal-rule

src配下の有効期限切れのオブジェクト削除マーカーを削除するライフサイクルルールになります。

  • ライフサイクルルール名:expired-delete-marker-removal-rule
  • フィルタータイプ:
    • prefix: 未設定
  • オブジェクトタグ:
    • 未設定
  • 有効期限切れのオブジェクト削除マーカーまたは不完全なマルチパートアップロードを削除
    • 期限切れのオブジェクト削除マーカーを削除する

先ほどのdelete-marker-tag-object-removal-ruleで非現行バージョンは削除したので、現行バージョンが削除マーカーであるオブジェクトが残ります。このように過去バージョンが1つもない削除マーカーのことを有効期限切れオブジェクト削除マーカーと言います。画像赤枠の有効期限切れオブジェクト削除マーカーを削除することでオブジェクトを完全に削除します。この辺りの概念は以下資料もご確認いただければと思います。

実行結果

1日目

それでは実際に実行していきたいと思います。まずは、src配下にheader ファイルとdone移動対象の2つのcsvファイルを格納します。

処理対象のS3 Bucketへの操作権限を設定してあるIAM Roleをprofile引数に設定し、シェルスクリプトを実行します。 第一引数に移動したいオブジェクトが格納されているs3 path、第二引数は処理対象外のファイル名、第三引数にprofile名を指定します。

sh move_put_tagging.sh s3://cm-kasama-life-cycle-test/src test_header.csv <iam-profile>

2回バージョニングの処理が走り、問題なくmove処理が実行されていることを確認しました。

src配下では、test_1.csvとtest_2.csvは削除マーカーが付与されていること、delete_marker_tagタグが付与されていることを確認しました。

done配下ではcsvファイルが現行バージョンとして存在し、done_tagが付与されていることを確認しました。

2日目(17:00頃)

2日目以降は日本時間で考えると午前9時にオブジェクトの削除が処理される想定ですが、以下ブログにも言及がある通り、9時ちょうどに削除されるわけではないため、時間をおいて17時あたりに確認したいと思います。

src配下

変化無し。

done配下

変化無し。

3日目(17:00頃)

src配下

非現行バージョンオブジェクトが削除されていることを確認しました。

done配下

オブジェクトが現行バージョンから有効期限切れになったことがわかります。

バージョンの表示を設定しない場合は、オブジェクトが消えていることがわかります。

4日目(17:00頃)

src配下

3日目から変化無し。

done配下

3日目から変化無し。

5日目(17:00頃)

src配下

有効期限切れオブジェクト削除マーカーが削除された状態になりました。

done配下

3日目から変化無し。

6日目(17:00頃)

done配下

非現行バージョンオブジェクトが削除されていることを確認しました。

7日目(17:00頃)

done配下

有効期限切れオブジェクト削除マーカーが削除され、全て空になりました。

まとめ

結果をまとめると以下のようになりました。src配下と比較してdone配下の非現行バージョンオブジェクト削除から有効期限切れオブジェクト削除マーカー削除に1日の空きがないので、確認する時間によっては結果が変わっていたかもしれませんが、実現したいことは確認できたので検証は正常終了とします。

日付 src配下の状態 done配下の状態
1日目 移動したオブジェクトに削除マーカーとdelete_marker_tagタグ付与 オブジェクトが現行バージョンとして存在、done_tagタグ付与
2日目 変化無し 変化無し
3日目 非現行バージョンオブジェクト削除 オブジェクトが現行バージョンから有効期限切れに
4日目 3日目から変化無し 3日目から変化無し
5日目 有効期限切れオブジェクト削除マーカー削除 3日目から変化無し
6日目 非現行バージョンオブジェクト削除
7日目 有効期限切れオブジェクト削除マーカー削除

最後に

今回はS3ライフサイクルポリシーでの削除を設定しましたが、システムによっては永久保存であることもあります。そのような場合は削除ではなくS3 ストレージクラスの変更を設定するとコスト削減につながると思います。このブログが少しでもどなたかのお役に立てれば幸いです!