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

Cloudflare R2を使って公開のmavenリポジトリを作る(Gradle)

Last updated at Posted at 2023-12-13
YUMEMI New Grad Advent Calendar 2023

Gradleには標準でS3やCloud Storageをmavenリポジトリとして扱う機能がついているのですが、Google Cloudのライブラリが古すぎて認証に一部問題があるようです。
GitHubからOIDCを使って接続しようと思ったら古いライブラリを使っているせいで認証できませんでした。
Google CloudならArtifact Registry使えばいいのですが、無料枠が0.5GBまでで転送料もかかることからもっと安く済む手段を探します。
マネージドなサービスであることの良さはもちろんありますが、今回はよりコストを抑えることを目的としています。

ということでCloudflare R2をmavenリポジトリとして運用していきます。

今回検証に利用したコードは以下のリポジトリにあります。

Cloudflare R2とは

Cloudflareの公開しているS3互換のあるオブジェクトストレージです。
S3などと比べて無料枠が大きく、比較的コストの低いストレージになります。
S3互換であるため既存のAWS SDKから操作ができます。R2専用のライブラリを使用しなくてもよい部分も魅力的です。
課金は使用したストレージ容量と書き込みアクセス、読み取りアクセスの回数でなされます。

環境

  • Java 17
  • Gradle 8.4
  • Terraform v1.6.4

事前準備

Cloudflareのアカウントを用意し、課金の設定をしてください。
無料枠の範囲内で使用していれば課金されることはありませんが、R2を使用するためには設定が必要です。

R2 Bucketの作成

Account IDとTokenの確認

まずR2にBucketを作成するためのAccount IDの確認とTokenの作成をします。
R2のページにアクセスして右側にAccount IDがあるのでメモしておきます。

その下にあるManage R2 API TokenからTokenの作成ができます。
Create Tokenと進み、以下のようにAdmin Read & Writeを選択して権限設定を行います。

他の設定項目はそのままで進めます。
次の画面に進むとTokenが作成されます。
またその下にAccess KeyとSecret Keyも表示されます。
このキーはS3クライアントからアクセスするために使用できます。

TokenやAccess Keyなどはこの画面でしか確認できないため、忘れずにメモしてください

今回はこのAccess KeyとSecret KeyでGradleからアップロードします。

Tokenの作成自体は https://dash.cloudflare.com/profile/api-tokens からでも行えます。

権限として、Worker R2 Storageを選択し、Editの権限とすることでR2の操作ができます。
ここから作成した場合には他の権限を付与することもできます。
R2のページから作成したTokenもここに表示されるので、権限を追加することもできます。

S3互換のAccess KeyとSecret KeyはR2のページからTokenを作成した場合のみ確認できるので、S3クライアントで使うTokenはR2のページから作成してください。

Bucketの作成

BucketはTerraformで作ります。

terraform {
  required_providers {
    cloudflare = {
      source = "cloudflare/cloudflare"
      version = "~> 4"
    }
  }
}

provider "cloudflare" {
  api_token = var.cloudflare_token
}

resource "cloudflare_r2_bucket" "cloudflare-bucket" {
  account_id = var.cloudflare_account
  name       = var.bucket_name
  # See https://developers.cloudflare.com/r2/reference/data-location for location
  # location   = "apac"
}

api_tokenaccount_id は上で確認したものを入れてください。
bucketの名前は適当なものを設定してください。
locationは5箇所ほど用意されているようです。
何も入力しないと近い地域のリージョンが選ばれます。
GDPRなど地理的な制限がある場合は指定する必要があるかなと思います。
locationについては https://developers.cloudflare.com/r2/reference/data-location/ で説明されています。

Applyすれば作成されます。

Gradleの設定

準備

認証情報として使うのでR2のAccess KeyとSecret Keyを用意してください。
Tokenの作成をすると一緒に表示されます。

build.gradle.kts の設定

maven-publish プラグインを設定し、以下のようにpublishの設定をしました。

publishing {
    publications {
        create("mavenJava", MavenPublication::class) {
            from(components.named("java").get())
        }
    }
    repositories {
        val bucketName = project.findProperty("r2_bucket_name") ?: System.getenv("R2_BUCKET_NAME") ?: ""
        maven {
            name = "R2"
            url = uri("s3://${bucketName}")
            credentials(AwsCredentials::class) {
                accessKey = (project.findProperty("r2_access_key") ?: System.getenv("R2_ACCESS_KEY") ?: "") as String
                secretKey = (project.findProperty("r2_secret_key") ?: System.getenv("R2_SECRET_KEY") ?: "") as String
            }
        }
    }
}

r2_bucket_name にはBucketの名前、 r2_access_keyr2_secret_key にはそれぞれR2のAccess KeyとSecret Keyを設定しています。
R2はS3互換なので、URLにはS3のスキーマを設定しています。

https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:supported_transport_protocols に記述例が載っています。

R2へのPublish

build.gradle.kts の設定ではS3のスキーマを指定していましたが、そのままではAWSのエンドポイントにアクセスしてしまいます。
そのためR2専用のエンドポイントにつなぐよう、Publishのコマンド実行時に設定します。

https://developers.cloudflare.com/r2/api/s3/tokens/ でエンドポイントの説明がされています。
通常であれば https://<ACCOUNT_ID>.r2.cloudflarestorage.com の形式のエンドポイントを使用します。
EUのGDPRに対応するエンドポイントも用意されています。

以下のコマンドでPublishします。

./gradlew -Dorg.gradle.s3.endpoint=<EndPoint URL> publish

-Dorg.gradle.s3.endpoint がGradleで使われるS3のエンドポイントを指定するためのキーです。
https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:s3-repositories にプロパティについての記述があります。

Publishが完了すれば以下のようにファイルがR2にアップロードされていることが確認できます。

既存のバージョンと同じバージョンでPublishしてしまうとエラーなしにファイルが更新されてしまいます。
別の仕組みで上書きしないようにするか、必ずバージョンがインクリメントされる仕組みを使うようにしましょう。

gradle.properties の設定

上記の設定で必要なキーをまとめると以下のようになります。

r2_bucket_name=koma-maven
r2_access_key=<r2_access_key>
r2_secret_key=<r2_secret_key>
r2_maven_url=https://koma-maven.example.com
systemProp.org.gradle.s3.endpoint=https://<ACCOUNT_ID>.r2.cloudflarestorage.com

systemProp.org.gradle.s3.endpoint を設定することで -Dorg.gradle.s3.endpoint を毎回指定する必要がなくなります。

R2の公開

R2は2種類の方法でパブリックアクセスを有効化できます。

  1. r2.devのサブドメインでの公開
  2. 独自ドメインを使用する

r2.devのサブドメインでの公開

こちらの方法はレートリミットなどの制限があるため、本番環境ではお勧めしないと注意書きがされています。
有効にすると https://pub-<Bucket ID>.r2.dev の配下で公開することができます。
Bucketの設定画面から、以下のところで有効にしたりURLの確認ができます。

R2のAPIを調べましたが、APIでサブドメインでの公開を有効にすることはできないようです。
https://developers.cloudflare.com/api/operations/r2-create-bucket

独自ドメイン

この方法ではドメインのDNSがCloudflareで管理されている必要があります。
こちらの方法ではCloudflareのキャッシュやアクセス制限を入れることができます。

Bucketの設定画面から、以下のところで有効にできます。

有効にするとドメインのレコード一覧に表示されるようになります。

レコードのAPIからR2のドメインのデータを取得すると以下のようになります。

{
  "result": {
    "id": "ID",
    "zone_id": "ZONE",
    "zone_name": "example.com",
    "name": "koma-maven.example.com",
    "type": "CNAME",
    "content": "public.r2.dev",
    "proxiable": true,
    "proxied": true,
    "ttl": 1,
    "locked": false,
    "meta": {
      "auto_added": false,
      "managed_by_apps": false,
      "managed_by_argo_tunnel": false,
      "r2_bucket": "koma-maven",
      "read_only": true,
      "source": "primary"
    },
    "comment": null,
    "tags": [],
    "created_on": "2023-11-23T14:09:13.132284Z",
    "modified_on": "2023-11-23T14:09:13.132284Z"
  },
  "success": true,
  "errors": [],
  "messages": []
}

向き先が public.r2.dev である、CNAMEのレコードとして作成されているようです。
meta の中にどのBucketであるか示す r2_bucket の項目があります。

レコードの作成APIにはmetaを設定する項目はなく、Terraformの cloudflare_record でも読み取り専用になってます。
よってR2を公開設定に自動で変更するのは難しいのではないかと思います。

cloudflare_record の、以下のリソースとしてimportすることはできます。

resource "cloudflare_record" "r2-domain" {
  name    = cloudflare_r2_bucket.cloudflare-bucket.name
  type    = "CNAME"
  zone_id = data.cloudflare_zone.zone.id
  proxied = true
  ttl     = 1
  value   = "public.r2.dev"
}

しかしmetaは読み取り専用で変更できないため、管理する意義はほとんどありません。

Bucketのファイルにアクセスする際には、ドメインの後にファイルのパスを繋げたURLを使用します。
jp/co/yumemi/koma/lib/maven-metadata.xml
のファイルへは https://koma-maven.example.com/jp/co/yumemi/koma/lib/maven-metadata.xml でアクセスできます。

Gradleからの参照

上の手順で定義したURLを設定するだけです。

repositories {
    maven {
        name = "R2"
        url = uri("https://koma-maven.example.com/")
    }
}

dependencies {
    implementation("jp.co.yumemi.koma:lib:1.1-SNAPSHOT")
}

のように指定することでR2に公開したファイルを使えます。

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