3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IBM Cloud Object Storage(ICOS)のAPI Callの課金について

Last updated at Posted at 2024-03-06

はじめに

Cloud上で非常に安価で大量のデータを格納できるストレージとしてICOSがよく利用されます。ICOSの課金の仕組みは2つの要素で決まります。
1つ目は月次保管データ・ボリュームの平均、2つ目はシステムによって処理される操作要求の総数です。
今回は2つ目の操作要求を対象として、ICOSのデータのアップロード、ダウンロード、リストなどを実行する際に発生するAPI Callがどのようにカウントされるのか確認することを目標に検証を行いました。

検証結果として APIコマンド1回に対して、class Aもしくはclass Bのカウント1回。API 1回で複合的にclass A, class Bがカウントされることはありませんでした。 詳細な検証結果は本記事の後半で記載してあります。

API Callの課金について

API Callは要求内容によってClass AとClass Bの2種類が存在します。

Class Aの要求には、変更またはリスト作成が関係します。
Class Aの要求に該当する例としてはバケットの作成、オブジェクトのアップロードまたはコピー、バケットのリスト、バケットの内容のリスト、ACLの設定、およびCORS 構成の設定などが挙げられます。

Class Bの要求は、システムからのオブジェクトなどの取得に関連する要求です。
Class Bの要求に該当する例としてはオブジェクトおよびメタデータの取得が挙げられます。

また、バケットまたはオブジェクトをシステムから削除する場合はClass A・Bどちらにも該当せず、料金は発生しません。

クラス要求の金額はストレージクラスによって異なりますが、Smart Tierの場合はClass Aは1000回あたり¥0.774、Class Bは10,000回当たり¥0.774となっています。

また、Class AとClass Bの量に応じてSmart TierのデータプランがHot・Cool・Coldの3段階に分かれます。storage(具体的には保管されたデータの合計量(GB))とretrievals(取得されたデータの合計ボリューム(GB))、requests(クラス A (書き込み) 要求の数に、クラス B (読み取り) 要求の数の 1/10 を加算した合計)の関係値によって以下の通りに分類されます。

Hot : requests > 1000 x (storage - retrievals)
Cold : requests < (storage - retrievals)
Cool : その他

より詳細な料金はポータルの製品情報からご確認ください。
https://cloud.ibm.com/objectstorage/create#pricing

手順

本記事で実施した検証内容は以下の通りです。

  1. curlを使用した際のAPI Callの確認
  2. Pythonを使用した際のAPI Callの確認
  3. バケット内に大量のファイルが存在する場合のリスト取得で発生するAPI Callの確認

また、本記事の構成図は以下のようになっています。

スクリーンショット 2024-03-05 1.06.19.png

使用する環境

本記事で使用する環境は以下のとおりです

  • IBM Cloud Object Storage(ICOS)の東京リージョンのBucket

    スクリーンショット 2024-02-12 18.03.45.png
    バケットのログをActivity Trackerに送信するようにあらかじめ設定しておきます。

    スクリーンショット 2024-02-12 18.03.57.png

  • 東京リージョンのIBM Cloud Activity Tracker

    スクリーンショット_2024-02-12_18_10_25.png

また、pythonの環境としてGoogleのcolaboratoryを利用しています。

1. curlを使用した際のAPI Callの確認

まずはじめにcurlを使用してICOSの操作を実施し、API Callの発生を確認します。
作業内容はこちらのdocsを参考に進めています。
また、外部からICOSへのアクセスのためのトークン取得はこちらのQiita記事を参考にしています。

手順は以下の通りです。

  1. ICOSアクセスのためのtokenの取得
  2. curlを使用したICOSのバケットへファイルのアップロード・リスト・ダウンロード
  3. Billing APIからAPI Callの確認

1-1. ICOSアクセスのためのtokenの取得

まずはじめにICOSへアクセスするためのbearer tokenを取得します。tokenの取得コマンドは以下の通りです。[apikey]には事前に取得したapikeyを代入します。apikeyの取得方法についてはこちらの記事を参考にしてください。

$  curl -k -X POST --header "Content-Type: application/x-www-form-urlencoded" --header "Accept: application/json" --data-urlencode "grant_type=urn:ibm:params:oauth:grant-type:apikey" --data-urlencode "apikey=[apikey]" "https://iam.cloud.ibm.com/identity/token"
{"access_token":"bearertoken","refresh_token":"not_supported","ims_user_id":9985776,"token_type":"Bearer","expires_in":3600,"expiration":1709474315,"scope":"ibm openid"}%

コマンドを打つと、access_tokenの後ろにbearer tokenが出力されます(上の"bearetoken"に当たる部分)。
注意点として生成したtokenは有効期限が1時間となっているため、期限切れの場合再び作成し直す必要があります。

1-2. curlを使用したICOSのバケットへファイルのアップロード・リスト・ダウンロード

次に先ほど取得したbearer tokenを使用してcurlからICOSを操作を実施します。
以下、バケットの操作コマンドとなります。

ファイルのアップロード
$  curl -X PUT “https://s3.jp-tok.cloud-object-storage.appdomain.cloud/[バケット名]/[登録ファイル名]” -H “Authorization: bearer [bearer token]” -T “[送付したいファイル]”
ファイルのダウンロード
$  curl "https://s3.jp-tok.cloud-object-storage.appdomain.cloud/[バケット名]/[ダウンロードファイル]" -H "Authorization: bearer [bearer token]" --output [ダウンロードファイル保存名]
バケット内ファイルのリスト
curl "https://s3.jp-tok.cloud-object-storage.appdomain.cloud/[バケット名]" -H "Authorization: bearer [bearer token]"

今回は東京リージョンのバケットのためエンドポイントがs3.jp-tok.cloud-object-storage.appdomain.cloudとなっており、別リージョンの場合は対応したエンドポイントに変更してください。また、[bearer token]・[バケット名]などの中身は対応したものを代入してください。

1-3. Activity Tracker(or API Billing)からAPI Callの確認

ICOSの操作後にAPI Callがどのくらい発生しているか2通りの手段で確認します。

1-3-1. Activity Trackerを使用した確認方法

Activity Trackerに流れるログを確認することでAPI Callがどれくらい発生しているか確認することができます。
今回は以下の操作を実施してログを確認します。

  1. sample1.txtファイルをICOSのバケット上にアップロード
  2. sample1.txtファイルをICOSのバケットからダウンロード
  3. ICOSのバケット内のファイルのリストアップ

これらの操作を先ほど記載したcurlを利用して実施した後、Activity Trackerで確認したものが以下の画像となります。

スクリーンショット_2024-03-04_21_31_45.png

それぞれ詳細を確認すると以下の様になっています。

ファイルのアップロード
スクリーンショット 2024-03-04 23.07.13.png

ファイルのダウンロード
スクリーンショット 2024-03-04 23.07.25.png

バケット内ファイルのリスト
スクリーンショット 2024-03-04 23.07.33.png

これらを確認するとファイルのアップロードではputコマンド(Class A)、ファイルのダウンロードではgetコマンド(Class B)、バケット内ファイルのリストではバケットリストのためのgetコマンド(Class B)が呼び出されていることが確認できます。

1-3-2. Billing APIからの確認方法

Billing APIを見ることでAPI Callがどのくらい発生したのかを確認できます。API Billingを入手するためにはresouce_incetance_idaccount_idが必要なのでこれらを確認します。

resouce_incetance_idの確認

ポータルのICOS画面からサービス資格情報新規資格情報を選択します。

スクリーンショット_2024-02-09_16_48_37.png

任意の名前をつけ、ロールを管理者、HMAC資格情報を含めるをオンにして作成します。

スクリーンショット_2024-02-09_16_50_55.png

作成後、サービス資格情報の画面から先ほど作成した資格情報が確認できるのでその中のresource_instance_idをコピーしておきます。

スクリーンショット_2024-02-09_16_57_50.png

account_idの確認

次にaccount_idを確認します。
ポータルの右上にある管理アカウントを選択します。

スクリーンショット_2024-03-04_16_31_18.png

続いて左側のメニューからアカウント設定を選択するとアカウントIDが表示されるのでコピーしておきます。

スクリーンショット_2024-03-04_16_22_39.png

billing APIの取得

取得した情報をもとにbilling APIを入手します。

billingの取得
curl -X "GET" "https://billing.cloud.ibm.com/v4/accounts/[ACCOUNT_ID]/resource_instances//usage/[BILLING_MONTH]?resource_instance_id=[resource_instance_id]&region=[region]" \
-H "Authorization: Bearer [bearer token]" --output billingbefore_2402.json

[]で括られてるものは入手した情報を代入します。[region]は対象となるリージョン(今回ならjp-tok)、[BILLING_MONTH]は取得したいbilling APIの月(2024年2月なら2024-02)を指定します。
コマンド実行後、billing APIがjsonファイルとして出力されます。

2. pythonを使用した際のAPI Callの確認

続いてpythonを使用した際にAPI Callの量が変化するのかを確認します。

手順は以下の通りです。

  1. ICOSのバケットへファイルのアップロード・リスト・ダウンロード
  2. Activity Tracker(or API Billing)からAPI Callの確認

2-1. ICOSのバケットへファイルのアップロード・リスト・ダウンロード

pythonを使用してICOSバケットの操作を実施します。
まず、pythonで使用するライブラリーをインポートします。

import ibm_boto3
from ibm_botocore.client import Config, ClientError

次にpythonからICOSへアクセスするためにはICOS資格情報が必要なので、curlからアクセスする際に作成したICOS資格情報をコピーします。

credencials = {
#資格情報を貼り付ける
}

続いて入手した資格情報をもとに接続を作成します。Endpointは今回東京リージョンのICOSのため、東京リージョンのパブリックエンドポイントを使用しています。他のリージョンを使用する際はポータルのICOSのページ左側のエンドポイントから使用するリージョンのエンドポイントを確認してください。

COS_ENDPOINT = "https://s3.jp-tok.cloud-object-storage.appdomain.cloud"

COS_API_KEY_ID = credencials["apikey"] 

COS_INSTANCE_CRN =  credencials["resource_instance_id"]  

# Create resource
cos = ibm_boto3.resource("s3",
    ibm_api_key_id=COS_API_KEY_ID,
    ibm_service_instance_id=COS_INSTANCE_CRN,
    config=Config(signature_version="oauth"),
    endpoint_url=COS_ENDPOINT
)

ICOSのバケットを操作する関数を作成する

ICOSとの接続が可能になったのでICOSのバケットを操作する関数を作成します。基本的なものに関してはICOSのdocs : pythonの使用を参考に作成しています。

テキストファイルを作成しアップロード
def create_text_file(bucket_name, item_name, file_text):
    print("Creating new item: {0}".format(item_name))
    try:
        cos.Object(bucket_name, item_name).put(
            Body=file_text
        )
        print("Item: {0} created!".format(item_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to create text file: {0}".format(e))
バケット内の指定したファイル取得
def get_item(bucket_name, item_name):
    print("Retrieving item from bucket: {0}, key: {1}".format(bucket_name, item_name))
    try:
        file = cos.Object(bucket_name, item_name).get()
        print("File Contents: {0}".format(file["Body"].read()))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to retrieve file contents: {0}".format(e))
バケット内のリスト
def get_bucket_contents(bucket_name):
    print("Retrieving bucket contents from: {0}".format(bucket_name))
    try:
        files = cos.Bucket(bucket_name).objects.all()
        for file in files:
            print("Item: {0} ({1} bytes).".format(file.key, file.size))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to retrieve bucket contents: {0}".format(e))
バケット内のリスト(prefix指定)
def get_bucket_contents_prefix(bucket_name, search_prefix):
    print("Retrieving bucket contents from: {0}".format(bucket_name))
    try:
        files = cos.Bucket(bucket_name).objects.filter(Prefix=search_prefix)
        for file in files:
            print("Item: {0} ({1} bytes).".format(file.key, file.size))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to retrieve bucket contents: {0}".format(e))

それぞれの関数を実行するとICOSの操作が可能です。

2-2. Activity TrackerからAPI Callの確認

先ほど作成した関数を使用してICOSを操作し、Activity TrackerからでAPI Callが送られているかを確認します。
まずはcreate_text_file関数を使用してファイルのアップロードをおこないます。

create_text_file("test-request","test.txt", "hoge")

ポータルで確認すると先ほど作成したファイルが追加されています。

スクリーンショット 2024-02-12 18.30.59.png

また、Activity Trackerで確認するとbucket.getのAPIが呼び出されています。

スクリーンショット 2024-02-12 18.34.23.png

同様にリストとファイル取得も試してみます。

リスト取得

get_bucket_contents("test-request")

出力:
Retrieving bucket contents from: test-request
Item: test.txt (4 bytes).

Activity Tracker:
object.get
スクリーンショット 2024-02-12 19.04.39.png

ファイル取得

get_item("test-request", "test.txt")

出力:
Retrieving item from bucket: test-request, key: test.txt
File Contents: b'hoge'

Activity Tracker:
object.get
スクリーンショット 2024-02-12 19.03.47.png

3. バケット内に大量のファイルが存在する場合のリスト取得で発生するAPI Callの確認

基本的にバケットからファイルのリストを取得する際に発生するクラス要求はClass AのGet要求1回ですが、docsによるとバケット内に1000以上のファイルが存在する場合は1000ファイル毎に要求が発生すると記載がありましたので、検証してみます。

まずはバケット内に大量のファイルをアップロードします。

def mult_object_upload(bucket_name, num, prefix):
  for i in range(num):
    item_name = "{0}/testfile{1}".format(prefix, i)
    file_text = "{0}/testfile{1}".format(prefix, i)
    print("Creating new item: {0}".format(item_name))
    try:
        cos.Object(bucket_name, item_name).put(
            Body=file_text
        )
        print("Item: {0} created!".format(item_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to create text file: {0}".format(e))

試しにprefixを変更したファイルを1000個ずつ合計4000個アップロードします。

mult_object_upload("test-request", 1000, "test-1")
mult_object_upload("test-request", 1000, "test-2")
mult_object_upload("test-request", 1000, "test-3")

上記コマンド実施後、バケット内にはtest-1/testfilexxx・test-2/testfilexxx・test-3/testfilexxxがそれぞれ1000ファイルの3000ファイル+元々バケットにあったファイル3個の合計3003ファイルが存在しています。

3-1. pythonでlist取得する場合

get_bucket_contents("test-request")

Activity Tracker:
スクリーンショット_2024-02-12_20_26_03.png

Activity Trackerを見ると、1回のリスト取得で4回分のクラス要求が発生していることが確認できます。
今度はprefixを指定してバケット内の1000個だけをリスト化してみます。
以前作成した関数を使用してファイル名の頭が"test-1"(test-1/testfile0~test1/testfile999までの1000ファイル)のみを指定してリストを取得します。

get_bucket_contents_prefix("test-request", "test-1")

今回は1000個だけをリスト化しているのでActivity Trackerを見ると、1回のリスト取得で1回だけクラス要求が発生していることが確認できます。

スクリーンショット_2024-02-12_20_30_55.png

3-2. curlでlist取得する場合

curlでも同様にlist取得してみるとActivity Trackerでは1行分のログしか追加されません。
そこでlistをtextファイルとして出力して確認してみます。

バケット内ファイルのリストをtext出力
curl "https://s3.jp-tok.cloud-object-storage.appdomain.cloud/test-request" -H "Authorization: bearer [bearer token]" --output list.txt

出力したtextファイルを確認してみると1000ファイルのみしか出力されていませんでした。
このことから、curlでは1000ファイルを超えたリスト要求があった場合1000ファイルまでしか出力されないことがわかります。

本記事の検証内容は以上となります。

結論

本記事で検証した結果は以下の通りとなりました。

  1. curlからICOSを操作した場合、ダウンロードではClass Bが、アップロード・リスト取得(ファイル1000以下)ではClass Aがそれぞれ1回の操作に対して1回発生した
  2. pythonからICOSを操作した場合、ダウンロードではClass BのAPI Call、アップロード・リスト取得(ファイル1000以下)ではClass AのAPI Callがそれぞれ1回の操作に対して1回発生した
  3. 1000を超えるファイルのリストを実行した場合、pythonは分割されて複数回のAPI Callが発生したのに対し、curlでは1000個のファイルのみリストされたため、1回だけAPI Callが発生した

以上の結果から基本的にはdocsに記載があった通りにICOS操作に対して対応したClass AもしくはClass BのAPI Callが発生していることが確認できました。

ちなみにポータルで操作すると、ポータル上でバケットやファイルを確認するだけでAPI Callが発生します。

また、ポータルやバックアップソフトなどAPI Callが隠蔽されているアプリケーションやソフトウェアなどを利用する場合はICOS操作で想定される以上のAPI Callが発生する可能性があるのでご注意ください。

例として、下の記事ではs3cmdを利用していますが、大容量のファイルを転送する際にファイルが分割されるため、一回のアップロードに複数回のAPI Callが発生しています。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?