Cloud Storageでオブジェクトクラスを変更しても料金が安くならないときの対処法

記事タイトルとURLをコピーする

G-gen の杉村です。料金が安くなることを期待して Cloud Storage オブジェクトのオブジェクトクラス変更を実施したところ、料金が安くなるどころか逆に高くなってしまいました。この事象の原因と、対処方法をご共有します。

事象

Cloud Storage バケット上の複数(数百程度)のオブジェクトに対して、gcloud コマンドを使って Standard クラスから Nearline クラスへのストレージクラス変更を行いました。

$ gcloud storage objects update gs://${BUCKET_NAME}/${OBJECT_NAME} --storage-class=nearline

これにより、以降はより安価な Nearline クラスの単価で課金されるようになることを期待しました。

しかし、数日後に請求先アカウントの課金レポートを確認したところ、Standard クラスの保管料金と Nearline クラスの保管料金の両方が課金されていることが確認されました。料金が安価になることを期待したのに、二重に課金されているような状態となっています。

なお前述のコマンド例では gcloud storage コマンドを利用していますが、gsutil rewrite コマンドでも同様の事象が発生しました。

原因

gcloud storage objects updategsutil rewrite によるオブジェクトのストレージクラスの変更は、オブジェクトの書き換えという挙動になります。

この挙動は「変更後のストレージクラスでオブジェクトを上書きする」という処理を行っています。これにより、上書き前の古いオブジェクトは Soft delete 状態で、数日間(デフォルトで7日間)残り続けます。

Soft delete は、削除または上書きされた Cloud Storage オブジェクトを一定期間保持し、復元可能にする機能です。デフォルトでは、7日間の保持期間が設定されており、7日間から90日間の間で設定できるほか、明示的に無効にすることもできます。Soft delete が有効化されているバケットでは、上書きまたは削除された古いオブジェクトは Soft delete 状態として保持されます。

なお Soft delete は日本語ドキュメントで「削除(復元可能)」と表記されますが、当記事ではわかりやすくするため Soft delete という表記で統一します。

Soft delete 状態のオブジェクトには、課金が発生します。今回のケースでは、コマンドによりオブジェクトを上書きしてストレージクラスを変更したため、Standard クラスの古いオブジェクトが Soft delete 状態で残り続けていました。そのため Soft delete 状態の Standard クラスの古いオブジェクトと、Nearline クラスの新しいオブジェクトが同時に存在していることになり、両方に課金が発生していました。

対処法

Soft delete 状態のオブジェクトを明示的に削除する方法はありません。バケットに設定した Soft delete 期間が経過すると、Soft delete 状態のオブジェクトは自然に削除されます。

あとからバケットの Soft delete を無効化したり、Soft delete 期間を短くしても、オブジェクトを削除または上書きしたときに設定されていた Soft delete 期間の設定が有効なため、当初に設定されていた Soft delete 期間の経過を待つ必要があります。

この事象の発生を予防するには、ライフサイクルルールや Autoclass 機能を使ってストレージクラスを変更する必要があります。

オブジェクトのライフサイクルは、事前に定義したルールに基づいて、例えば「作成から30日間経過したオブジェクトは Nearline クラスに移行する」「90日間経過したオブジェクトは削除する」のような自動処理を定義できる機能です。

Autoclass は、オブジェクトのアクセス状況に基づいて、自動的にオブジェクトのストレージクラスを変更する機能です。

いずれの機能も、ストレージクラスの変更は「オブジェクトの書き換え」とは異なる処理で行われるため、オブジェクトが Soft delete 状態になることはなく、二重課金を回避できます。またいずれの機構も、オブジェクト取得料金や早期削除料金が発生しないなどのコストメリットがあります。よって大量の(またはサイズが大きい)オブジェクトのストレージクラスを変更する場合は、ライフサイクルルールや Autoclass 機能を使うことが推奨されます。

検証(手動でストレージクラスを変更)

オブジェクトのアップロード

以下のコマンドで、ローカルマシンにあるテスト用ファイルを Cloud Storage バケットにアップロードします。

$ gcloud storage cp ./test-object.txt gs://my-test-bucket
Copying file://./test-object.txt to gs://my-test-bucket/test-object.txt
  Completed files 1/1 | 21.0B/21.0B 

ls コマンドで、オブジェクトが正しくアップロードできていることを確認します。また describe コマンドで、オブジェクトのストレージクラスを確認します。このバケットはデフォルトのストレージクラスが Standard なので、アップロードしたオブジェクトのストレージクラスも Standard になっています。

$ gcloud storage ls gs://my-test-bucket
gs://my-test-bucket/test-object.txt
$ 
$ gcloud storage objects describe gs://my-test-bucket/test-object.txt --format="value(storage_class)"
STANDARD

ストレージクラスの変更

update コマンドで、オブジェクトのストレージクラスを Nearline に変更します。

$ gcloud storage objects update gs://my-test-bucket/test-object.txt --storage-class=nearline
Rewriting gs://my-test-bucket/test-object.txt...                                                                                                             
  Completed 1
$ 
$ gcloud storage objects describe gs://my-test-bucket/test-object.txt --format="value(storage_class)"
NEARLINE

Soft delete 状態のオブジェクトの確認

gcloud storage objects update コマンドでオブジェクトのストレージクラスを変更したため、オブジェクトは上書きされ、Standard クラスの古いオブジェクトが Soft delete 状態で残っているはずです。

ls コマンドに --soft-deleted オプションを付けることで、Soft delete 状態のオブジェクトのみを一覧表示できます。

$ gcloud storage ls gs://my-test-bucket --soft-deleted --recursive
gs://my-test-bucket/:
gs://my-test-bucket/test-object.txt#1732163813118979

上記のように、test-object.txt#1732163813118979 という名称で、Soft delete 状態のオブジェクトが存在していることが確認できました。このオブジェクトのストレージクラスを以下のコマンドで確認します。

$ gcloud storage objects describe gs://my-test-bucket/test-object.txt#1732163813118979 --soft-deleted --format="value(storage_class)"
STANDARD

Soft delete 状態のオブジェクトが Standard クラスであることが確認できました。このSoft-delete 状態のオブジェクトは、Nearline クラスに変更した新オブジェクトとは別のオブジェクトとして存在しているため、Nearline に変更した新オブジェクトと、Standard の旧オブジェクトで二重課金状態になっていることがわかります。

この検証により、gcloud storage objects update によるオブジェクトクラスの変更を行うと、既存オブジェクトが新しいストレージクラスで上書きされ、古いオブジェクトが Soft delte 状態で残ることが確認できました。

削除ができないことを確認

なお、この Soft delte 状態のオブジェクトは gcloud storage rm コマンド等で削除することはできません。保持日数が経過するのを待つ必要があります。

$ gcloud storage rm gs://my-test-bucket/test-object.txt#1732163813118979
Removing objects:
  Completed 0                                                                                                                                                                                                                              
ERROR: (gcloud.storage.rm) The following URLs matched no objects or files:
gs://my-test-bucket/test-object.txt#1732163813118979
$ 
$ gcloud storage rm gs://my-test-bucket/test-object.txt#1732163813118979 --soft-deleted
ERROR: (gcloud.storage.rm) unrecognized arguments: --soft-deleted 

To search the help text of gcloud commands, run:
  gcloud help -- SEARCH_TERMS

検証(オブジェクトライフサイクルで変更)

オブジェクトのアップロード

次に、オブジェクトライフサイクル機能を用いてストレージクラスを変更した場合を検証してみます。

以下のコマンドで、ローカルマシンにあるテスト用ファイルを Cloud Storage バケットにアップロードします。

$ gcloud storage cp ./test-object-lifecycle.txt gs://my-test-bucket
Copying file://./test-object-lifecycle.txt to gs://my-test-bucket/test-object-lifecycle.txt
  Completed files 1/1 | 21.0B/21.0B 
$ gcloud storage objects describe gs://my-test-bucket/test-object-lifecycle  --format="value(storage_class)"
STANDARD

アップロード直後は、対象オブジェクトのストレージクラスが Standard であることも確認します。

ライフサイクルルールの設定

バケットのオブジェクトライフサイクルを、以下のように設定します。

特定日付より以前に作成されたオブジェクトを Nearline クラスに変更するルールとしました。即時にルールを適用したいので、検証を行った日は2024-11-21ですが、それより先の日付を指定日付としました。

ルールを設定してから、実際に適用されるまでは最大で24時間程度のラグがあります。

Soft delete 状態のオブジェクトの存在確認

しばらく待ったあと、ライフサイクルルールが適用され、オブジェクトのストレージクラスが Nearline に変更されたことを確認します。

$ gcloud storage objects describe gs://my-test-bucket/test-object-lifecycle.txt  --format="value(storage_class)"
NEARLINE

以下のように、Soft delete 状態のオブジェクトがあるかどうかを確認します。

$ gcloud storage ls gs://my-test-bucket --soft-deleted --recursive
gs://my-test-bucket/:

Soft delete 状態のオブジェクトが1つも存在しないことが確認できました。つまり、ライフサイクルルールによってオブジェクトのストレージクラスが変更された場合、オブジェクトの書き換えとは異なる動作のため、Soft delete 状態のオブジェクトは生まれないことがわかりました。

gcloud コマンド等によるストレージクラスの変更は「オブジェクトの書き換え」の動作であり、古いオブジェクトの削除が発生することに対して、ライフサイクルルールは違う挙動であるということは、以下のドキュメントにも記載されています。

ただし、オブジェクトのストレージ クラスを手動で変更する場合と異なり、SetStorageClass を使用してもオブジェクトは書き換えられません。

またライフサイクルルールによるストレージクラスの変更では、以下のようなその他の料金面でのメリットがあることも記述されています。

ストレージ クラスの変更に関連するリージョン間のレプリケーション料金、取得料金、早期削除料金は発生しません。

なおライフサイクルルールでオブジェクトクラスを変更されたオブジェクトを describe すると、以下のように、creation_time は最初にオブジェクトをアップロードした時間のまま変わりませんが、storage_class_update_time が変更されています。オブジェクトの上書きを行わずに、ストレージクラスのみが変更されていることがわかります。

$ gcloud storage objects describe gs://my-test-bucket/test-object-lifecycle.txt
bucket: my-test-bucket
content_type: text/plain
crc32c_hash: Sd5KXw==
creation_time: 2024-11-21T03:00:34+0000
etag: CKKH9cK37IkDEAI=
generation: '1732158034887586'
md5_hash: QGEgRtde1doCj1rGmxWK6w==
metageneration: 2
name: test-object-lifecycle.txt
size: 80
storage_class: NEARLINE
storage_class_update_time: 2024-11-21T06:58:34+0000
storage_url: gs://my-test-bucket/test-object-lifecycle.txt#1732158034887586
update_time: 2024-11-21T06:58:34+0000

杉村 勇馬 (記事一覧)

執行役員 CTO

元警察官という経歴を持つ IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 認定資格および Google Cloud 認定資格はすべて取得。X(旧 Twitter)では Google Cloud や Google Workspace のアップデート情報をつぶやいています。