Cloudflare R2
お仕事では巨大な動画ファイルを扱うことも多く、AWS S3 の料金周りの悩みでやりづらい施策も増えてきました。
そこで、Cloudflare R2 のエグレス無料とストレージ料金の効率に関して最近とても注目しております。
とりあえず本記事であらためて調べ、実際に普段サーバサイド書いているGo言語から触ってみました。
Cloudflare R2 とは?
Cloudflare R2 は Cloudflareが提供するクラウドベースのオブジェクトストレージサービスです。
perplexity.aiにサラッと根拠付きでまとめてもらいました。
主な特徴
- Amazon S3と互換性のあるAPIを採用しており、既存のS3ツールやライブラリを使用可能
- Cloudflareのグローバルネットワークを活用し、低レイテンシーでデータにアクセス可能
- Cloudflare Workersと緊密に統合されており、データの処理や変換が容易
- 強力なセキュリティ機能を提供(暗号化、アクセス制御など)
コスト効率の良さ
- エグレス料金が無料:データをR2から取り出す際の料金が発生しないため、大幅なコスト削減が可能
- 柔軟な料金体系:ストレージ容量と操作回数に基づくシンプルな料金設定
- 無料枠の提供:毎月10GBまでのストレージと一定量のリクエストが無料
利便性
- 公開バケット機能:認証なしでアクセス可能な公開バケットを作成可能
- 自動最適化:データアップロード位置に基づき最適なストレージ領域を自動選択
用途の多様性
R2は以下のようなさまざまな用途に適しています
- ウェブコンテンツのストレージ
- メディアファイル(画像、音声、動画)の保存
- クラウドネイティブアプリケーションのストレージ
- データ分析やビッグデータのためのデータレイク
- 機械学習モデルや大規模データセットの保存
Cloudflare R2は、特に頻繁にアクセスされるデータや大規模なデータセットの保存に適しており、エグレス料金が無料であることから、マルチクラウド戦略やデータ集中型アプリケーションで大きなコスト削減が期待できます。
Citations:
[1] https://zenn.dev/kazu0617/articles/4a890a4a21f867
[2] https://developers.cloudflare.com/r2/
[3] https://tks2.co.jp/2022/08/06/cloudflare-r2/
[4] https://future-architect.github.io/articles/20240603a/
[5] https://note.com/effectmoe/n/n9026fd23e130
[6] https://semaphoreci.com/blog/cloudflare-r2
[7] https://reffect.co.jp/cloudflare/cloudflare-r2-basic
[8] https://www.cloudflare.com/ja-jp/developer-platform/r2/
バケットの作成とAPI KEY の発行
かなり初歩的な素振りですが、個人ブログだからいいかな。
とりあえずバケットを作成し、API Keyも発行してみます。
特定のバケットのみに対する権限も、いったんGUIからポチポチでできるようです。
さすがS3互換API。ズバリそれっぽいキーが取得できます。
Golangで基本的なObjectの出し入れをしてみる
aws-sdk-go(今回はv1)を用いて、JSONの保存と取り出しをしてみます。
cloudflare R2 や wasabi 、miniIOなどS3互換APIと呼ばれるものは、基本的にエンドポイントを指定することで向き先をAWSから変えることができます。
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/sanity-io/litter"
"github.com/wano/contextlog/clog"
"os"
)
func main() {
// Cloudflare R2の認証情報とエンドポイント
accessKeyID := os.Getenv(`AWS_ACCESS_KEY_ID`)
secretAccessKey := os.Getenv(`AWS_SECRET_ACCESS_KEY`)
endpoint := os.Getenv("S3_ENDPOINT")
bucketName := os.Getenv("S3_BUCKET")
region := "auto"
// AWSセッションの作成
sess, err := session.NewSession(&aws.Config{
Credentials: credentials.NewStaticCredentials(accessKeyID, secretAccessKey, ""),
Endpoint: aws.String(endpoint),
Region: aws.String(region),
})
if err != nil {
fmt.Printf("セッションの作成に失敗しました: %s\n", err)
return
}
// S3クライアントの作成
svc := s3.New(sess)
type JsonData struct {
Message string `json:"message"`
}
jsonData := JsonData{
Message: "Hello, World!",
}
bys, err := json.Marshal(jsonData)
if err != nil {
clog.Panic(err)
}
_, err = svc.PutObject(&s3.PutObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String("hello.json"),
Body: bytes.NewReader(bys),
})
if err != nil {
clog.Panic(err)
}
fmt.Println("S3にファイルをアップロードしました")
// ファイルのダウンロード
result2, err := svc.GetObject(&s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String("hello.json"),
})
if err != nil {
clog.Panic(err)
}
got := new(JsonData)
err = json.NewDecoder(result2.Body).Decode(got)
if err != nil {
clog.Panic(err)
}
fmt.Println("S3からファイルをダウンロードしました")
litter.Dump(got)
}
実行結果
S3にファイルをアップロードしました
S3からファイルをダウンロードしました
&main.JsonData{
Message: "Hello, World!",
}
通常のS3にアクセスする感覚で簡単に使えましたね。