7
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?

More than 1 year has passed since last update.

Livebook のスポンサーである Tigris を使ってみる -S3 互換のキャッシュ付クラウドストレージ-

Last updated at Posted at 2024-06-30

はじめに

2024/3/26 の Livebook ブログで紹介されている Tigris を使ってみます

Tigris は Livebook のスポンサーにもなっているので、私としても応援したいですね

実装したノートブックはこちら

Tigris とは

Tigris is a globally distributed S3-compatible object storage service that provides low latency anywhere in the world, enabling developers to store and access any amount of data for a wide range of use cases.

和訳

Tigrisは、グローバルに分散されたS3互換のオブジェクトストレージサービスで、世界中どこでも低遅延で利用できます。これにより、開発者は多様な用途に応じてあらゆる量のデータを保存およびアクセスすることが可能です。

Tigris は Amazon S3 と互換性のあるストレージサービスです

そのため、 AWS CLI や、各言語の AWS SDK から S3 と全く同じように使うことができます

S3 互換という点では以前紹介した Cloudflare R2 と同じですね

Elixir の場合は ExAWS から操作できます

最大の特徴は CDN (Contents Delivery Network)がデフォルトで付いている点です

ファイルは地理的に最も近いデータセンターからダウンロードされ、2回目以降のアクセスではキャッシュが使われるため高速にアクセス可能です

S3 の場合は CloudFront を使う必要がありますが、 Tigris は特に何もしなくても CDN が付いてきます

Tigris の料金体系

Tigris では保存するデータ容量、リクエスト数で従量課金されます

私の感覚としては、他のサービスと比べても安くなっているように思います

項目 料金体系
保存容量 $0.02/GB/month
PUT, COPY, POST, LIST リクエスト $0.005/1000 requests
GET, SELECT, その他のリクエスト $0.0005/1000 requests
データ転送 $0.00/GB

データ転送で課金されない点も要注目です

他のストレージサービスでは「どれくらいアップロード・ダウンロード・リージョン間移動したか」でも課金されますが、ここが 0 なのは珍しいです

また、無料利用枠も用意されています

  • 毎月5GBのデータストレージ
  • 月間 10,000 件の PUT, COPY, POST, LIST リクエスト
  • 月間 100,000 件の GET, SELECT, その他のリクエスト

Tigris のはじめ方

公式サイトの右上、 "Dashboard" をクリックします

スクリーンショット 2024-06-28 13.38.49.png

Fly.io のサインインを求められます

実は Tigris には Fly.io のアカウントでサインインするようになっています

スクリーンショット 2024-06-28 13.40.43.png

サインアップ、サインインすると Tigris のダッシュボードが開きます

スクリーンショット 2024-06-28 13.42.11.png

S3 と同じようにバケット内でオブジェクトを管理します

Create a new bucket をクリックしてバケットを作ってみましょう

モーダルでバケット名を入力し、 Create をクリックします

スクリーンショット 2024-06-28 13.45.07.png

バケットが作成されました

スクリーンショット 2024-06-28 13.46.20.png

アクセスキーの作成

左メニューの "Access Keys" からアクセスキーの一覧を表示します

スクリーンショット 2024-06-29 8.31.44.png

右上 "Create New Access Key +" をクリックするとアクセスキー作成モーダルが開きます

アクセスキー名を入力し、バケットに対する権限を選択してから "Create" をクリックします

下画像の例では全バケットの更新権限を与えています

スクリーンショット 2024-06-29 8.32.36.png

アクセスキーが作成され、以下の情報が表示されます

  • Access Key ID
  • Secret Access Key
  • Endpoint URL S3
  • Region

注意文言にある通り、二度と Secret Access Key は表示されないため、どこか安全な場所に保存しておきましょう

スクリーンショット 2024-06-29 8.33.01.png

閉じるとアクセスキー一覧に戻ります

スクリーンショット 2024-06-29 8.35.22.png

ブラウザからのオブジェクト操作

バケット一覧でバケット名をクリックすると、バケット内のファイル一覧に遷移します

最初は何もファイルがない状態です

スクリーンショット 2024-06-29 8.36.15.png

"Upload" ボタンをクリックするとモーダルが開きます

スクリーンショット 2024-06-29 8.36.40.png

ファイルをドラッグ&ドロップして選択し、右下 "Upload" ボタンをクリックします

スクリーンショット 2024-06-29 8.37.07.png

一覧にファイルが追加されました

スクリーンショット 2024-06-29 8.37.56.png

ファイル名の右にあるアイコンから以下の操作が可能です

  • アップロード用署名付リンク作成
  • ダウンロード用署名付リンク作成
  • ダウンロード
  • 削除

リンクを作成する際やダウンロードを実行する際はアクセスキーを選択します

まだアクセスキーを作っていない場合は作成します

スクリーンショット 2024-06-29 8.38.44.png

AWS CLI からオブジェクトを操作する

以下のように環境変数を設定します

コマンドは macOS や Linux の場合です

export AWS_ACCESS_KEY_ID=<Tigris のアクセスキー ID>
export AWS_SECRET_ACCESS_KEY=<Tigris のシークレットアクセスキー>
export AWS_ENDPOINT_URL_S3=https://fly.storage.tigris.dev
export AWS_REGION=auto

以下のようにバケット一覧が取得できます

$ aws s3api list-buckets
{
    "Buckets": [
        {
            "Name": "rwakabay",
            "CreationDate": "2024-06-28T04:46:02+00:00"
        }
    ],
    "Owner": {
        "DisplayName": "tid_XXX",
        "ID": "tid_XXX"
    }
}

その他も S3 と同様に操作できます

アップロード

$ aws s3 cp ~/Downloads/ryo-000.png s3://rwakabay/
upload: Downloads/ryo-000.png to s3://rwakabay/ryo-000.png

一覧取得

$ aws s3 ls s3://rwakabay/
2024-06-29 09:07:08     249972 ryo-000.png

ダウンロード

$ aws s3 cp s3://rwakabay/ryo-000.png .
download: s3://rwakabay/ryo-000.png to ./ryo-000.png

Livebook からのオブジェクト操作

Elixir から操作する場合も S3 や R2 と全く同じに扱えます

セットアップ

S3 を操作するときと同じく、 ex_awsex_aws_s3 をインストールします

また、ファイル一覧などを表形式にするため Explorer 、画像ファイルを画像処理するために Evision などもインストールします

Mix.install([
  {:ex_aws, "~> 2.5"},
  {:ex_aws_s3, "~> 2.4"},
  {:poison, "~> 5.0"},
  {:hackney, "~> 1.20"},
  {:sweet_xml, "~> 0.7"},
  {:explorer, "~> 0.8"},
  {:evision, "~> 0.2"},
  {:req, "~> 0.5"},
  {:kino, "~> 0.13"}
])

エイリアスやマクロの準備をしておきます

alias ExAws.S3
alias Explorer.DataFrame
alias Explorer.Series
require Explorer.DataFrame

認証情報の入力

認証情報入力用の UI を作ります

Livebook の Secrets を使っても OK です

access_key_id_input = Kino.Input.password("ACCESS_KEY_ID")
secret_access_key_input = Kino.Input.password("SECRET_ACCESS_KEY")
endpoint_host_input = Kino.Input.text("ENDPOINT_HOST")

[
  access_key_id_input,
  secret_access_key_input,
  endpoint_host_input
]
|> Kino.Layout.grid(columns: 3)

表示された入力エリアに Tigris 用のアクセスキーID、シークレットアクセスキー、エンドポイントのホスト名(エンドポイント URL の http:// を除いたもの)を入力します

スクリーンショット 2024-06-29 9.36.19.png

以下のコードで接続用の認証情報を設定します

auth_config = [
  access_key_id: Kino.Input.read(access_key_id_input),
  secret_access_key: Kino.Input.read(secret_access_key_input),
  host: Kino.Input.read(endpoint_host_input)
]

Kino.nothing()

ここから先は S3, R2 と全く同じコードです

バケット一覧の取得

S3 のときと同様、 S3.list_buckets() でバケットの一覧が取得できます

S3.list_buckets()
|> ExAws.request(auth_config)

実行結果

{:ok,
 %{
   body: %{
     owner: %{
       id: "tid_XXX",
       display_name: "tid_XXX"
     },
     buckets: [%{name: "rwakabay", creation_date: "2024-06-28T04:46:02Z"}]
   },
   headers: [
     {"Access-Control-Allow-Headers", "*"},
     {"Access-Control-Allow-Methods", "*"},
     {"Access-Control-Allow-Origin", "*"},
     {"Access-Control-Expose-Headers", "*"},
     {"Content-Length", "353"},
     {"Content-Type", "application/xml"},
     {"Server", "Tigris OS"},
     {"Server-Timing", "total;dur=246"},
     {"Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload"},
     {"X-Amz-Request-Id", "1719620781158576483"},
     {"Date", "Sat, 29 Jun 2024 00:26:21 GMT"}
   ],
   status_code: 200
 }}

以下のようにしてバケット一覧を表形式で表示できます

S3.list_buckets()
|> ExAws.request!(auth_config)
|> then(& &1.body.buckets)
|> DataFrame.new()
|> DataFrame.select(["name", "creation_date"])
|> Kino.DataTable.new()

ファイル一覧の取得

バケット名を入力します

bucket_name_input = Kino.Input.text("BUCKET_ANME")

スクリーンショット 2024-02-09 17.19.51.png

S3.list_objects_v2 でファイル一覧が取得できます
max_keys で一度に取得するファイル数(1 ページ分のファイル数)を指定しています

{contents, next_continuation_token} =
  bucket_name_input
  |> Kino.Input.read()
  |> S3.list_objects_v2(max_keys: 10)
  |> ExAws.request!(auth_config)
  |> then(&{&1.body.contents, &1.body.next_continuation_token})

実行結果

{[
   %{
     owner: %{id: "", display_name: ""},
     size: "249972",
     key: "ryo-000.png",
     last_modified: "2024-06-29T00:07:08Z",
     storage_class: "STANDARD",
     e_tag: "\"d10f45f7c326ecbd54b34db3b2055b5e\""
   },
   ...
   ],
 "xxx"}

取得した next_continuation_token を使って、次のページを取得することができます

bucket_name_input
|> Kino.Input.read()
|> S3.list_objects_v2(max_keys: 10, continuation_token: next_continuation_token)
|> ExAws.request!(auth_config)
|> then(&{&1.body.contents, &1.body.next_continuation_token})

全ファイルの一覧を取得するモジュールは以下のようになります

defmodule S3LS do
  def get_contents(continuation_token, bucket_name, auth_config) do
    bucket_name
    |> S3.list_objects_v2(max_keys: 10, continuation_token: continuation_token)
    |> ExAws.request!(auth_config)
    |> then(&{&1.body.contents, &1.body.next_continuation_token})
  end

  def get_contents_cyclic(continuation_token, bucket_name, auth_config) do
    {contents, next_token} = get_contents(continuation_token, bucket_name, auth_config)

    case next_token do
      # 空であれば次ページを取得しない
      "" ->
        contents

      # 空以外の場合は次ページを取得する
      _ ->
        contents ++ get_contents_cyclic(next_token, bucket_name, auth_config)
    end
  end

  def get_all_contents(bucket_name, auth_config) do
    get_contents_cyclic(nil, bucket_name, auth_config)
  end
end

ファイルアップロード

アップロードする画像ファイルを Web からダウンロードしておきます

ryo_path = "ryo-wakabayashi.jpg"

"https://www.elixirconf.eu/assets/images/ryo-wakabayashi.jpg"
|> Req.get!(into: File.stream!(ryo_path))

ローカルファイルのアップロード

S3.Upload.stream_fileS3.upload でファイルをアップロードできます

ryo_path
|> S3.Upload.stream_file()
|> S3.upload(Kino.Input.read(bucket_name_input), "ryo-wakabayashi.jpg")
|> ExAws.request!(auth_config)

インメモリのアップロード

画像ファイルを evision で読み込んでおきます

mat = Evision.imread(ryo_path)

S3.put_object でインメモリのバイナリデータをアップロードできます

bucket_name_input
|> Kino.Input.read()
|> S3.put_object("ryo_2.jpg", Evision.imencode(".jpg", mat))
|> ExAws.request!(auth_config)

ファイルダウンロード

ローカルファイルへのダウンロード

S3.download_file で R2 上のファイルをダウンロードできます

bucket_name_input
|> Kino.Input.read()
|> S3.download_file("ryo-wakabayashi.jpg", "ryo_downloaded.jpg")
|> ExAws.request!(auth_config)

インメモリへのダウンロード

S3.get_object でバイナリデータとしてダウンロードできます

bucket_name_input
|> Kino.Input.read()
|> S3.get_object("ryo-wakabayashi.jpg")
|> ExAws.request!(auth_config)
|> then(&Evision.imdecode(&1.body, Evision.Constant.cv_IMREAD_COLOR()))

まとめ

Tigris を S3 や R2 と全く同じように操作することができました

料金も安く、 CDN も兼ねているため、画像などのコンテンツ配信には便利そうです

7
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
7
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?