Hori Blog

フリーランスでバックエンドエンジニアとして活動している Ryota Hori のブログです。
最近はテック系記事より雑記ブログ気味。

S3 の Lifecycle をコードベースで管理できる環境を整備した

S3 の Lifecycle をポチポチしているのが辛くなったので、カッとなって作りました。

awscli と jq があれば動くので、簡易的なコードベース管理の雛形としてお使いください。

hori-ryota/s3-lifecycle-manager

あくまで個人使用のために作成したので、細かいアレコレはご容赦ください。

お約束ですが、 使用は自己責任でお願いします。

以下、記事公開時点の README.md と同内容のものに補足を加えたものです。

README.md

hori-ryota/cloudfront-manager: Scripts for CloudFront から派生して作りました。

S3 の lifecycle をポチポチ運用するのが辛いので awscli を用いた json 管理にするやつです。

(基礎知識)主要な aws コマンド

AWS CLI を使用したライフサイクル設定の設定 - Amazon Simple Storage Service

ディレクトリ構成

targetBuckets.txt # 管理対象とするbucketリスト
json/             # apiから取得したjson置き場

更新は json ディレクトリ内のファイルを更新して S3 に反映してください。

スクリプト

vim の quickrun で叩きやすくするため、dirname などでのパス解決はしていないです。 s3-lifecycle-manager/ ディレクトリ直下で実行してください。

fetchall.sh

初期化用。 targetBuckets.txt に記載されている bucket の lifecycle を取ってきて json ディレクトリに反映。

削除済みの json 削除は行わないので、削除も必要なら json ディレクトリを削除後に実行してください。

update.sh

./update.sh ${targetCName}

更新用。get-bucket-lifecycle-configuration の json と put-bucket-lifecycle-configuration の形式は若干違うので、jq コマンドで整形したものを入力へ。

全 bucket を targetBuckets.txt に入れたい場合

このコマンドで入るかと思います。

aws s3api list-buckets | jq -r '.Buckets[].Name' > targetBuckets.txt

補足

lifecycle が未設定な bucket に fetch をかけるとエラーになるので、以下のようなスクリプトで初期化するのも良いと思います。

apply-cleaning-multipart-upload.sh
#!/bin/bash

set -eu

dir='json'
mkdir -p $dir

buckets="$(cat ./targetBuckets.txt)"

json='{
  "Rules": [
    {
      "Filter": {
        "Prefix": ""
      },
      "Status": "Enabled",
      "ID": "incomplete-multipart",
      "AbortIncompleteMultipartUpload": {
        "DaysAfterInitiation": 1
      }
    }
  ]
}'


for bucket in $buckets; do
  echo "fetch $bucket"
  echo $json | jq '.' > "$dir/$bucket.json"
done

上記のスクリプトは targetBuckets.txt の全ての bucket の json に対し、不完全な Mupltipart Upload の残骸を 1 日で削除する lifecycle を設定指定しています。

その上で fetchall.sh を以下のように書き換えて実行すると、既存のもののみ上書きされるので初期化に良いです。

fetchall.sh
#!/bin/bash

set -u

dir='json'
mkdir -p $dir

buckets="$(cat ./targetBuckets.txt)"

for bucket in $buckets; do
  echo "fetch $bucket"
  target=$(aws s3api get-bucket-lifecycle-configuration --bucket "$bucket")
  if [ $? -ne 0 ]; then
    echo "not initialized"
    continue
  fi
  echo $target | jq '.' > "$dir/$bucket.json"
done

書き換えた部分は set -eue フラグを外してエラーが生じても落ちないようにしたのと、 if [ $? -ne 0 ] によって fetch の成否で後続処理を分岐させているところです。

とりあえず Multipart Upload のゴミ掃除はどの bucket でも設定しておきたいものだとは思うので初期化としては妥当ではないでしょうか。

以上

やっぱりコードベースでインフラ管理をできるのは設定の手間もミスも無くせる上にバージョン管理やレビューも導入できて幸福度が高いですね。どんどん推し進めていきたいと思います。

lifecycle はそれなりの数(試したところ 200 は少なくとも設定できた)が設定できるので、大量のオブジェクトを削除する際に prefix で絞れる場合は lifecycle を 1d で設定して待つとリクエスト数も節約できる上に楽なので、コードベースで気軽にベタベタ変更できるのはとても嬉しいです。

ちなみに Terraform でも lifecycle の管理はできるようなので、 bucket を Terraform で管理している場合はそちらを使用するのが良いかもしれません。今のところ私の使い方では影響範囲を絞ってフランクに管理したかったのでスクリプトでの json 管理が捗っています。