3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

paiza×Qiita記事投稿キャンペーン「プログラミング問題をやってみて書いたコードを投稿しよう!」

label-studio + Cloud Run + Litestreamで作る小規模向けアノテーションツール

Last updated at Posted at 2024-07-30

背景

label-studioというアノテーションツールがあり、まずは個人利用のためローカルで利用していたのもつかの間、あっという間に利用ユーザ数が増えたのでちゃんとしたサービスにしようということでGoogle Cloud PlatformのCloud Runで運用しようというきっかけでlabel-studioサービスを立ち上げることになりました。

課題と対策

label studioのgitリポジトリを読んでいると「Run on Google Cloud」とあるので簡単にサービス立ち上げできるかなと思いきや、コスト最小化の制約をつけると以下の課題がわかった。

  1. コスト最小化のため、CloudRunのインスタンス数を0にするとLabel-Studioサービス内で保存しているデータが削除される
  2. データ永続化のために、CloudSQLを使うと月あたり100ドルを余裕で超えてくる

こういった課題からどうやったらデータを永続化しつつコスト最小でサービスを立ち上げることができるか?と検討した結果、Litestream + CloudRunという構成でCloudRunサービスのデータ永続化できることがわかったので、これをlabel-studioに適用してみた。

フロー

以下本サービス立ち上げに関して実施した手順である。

  1. 方針の検討と決定
  2. カスタムlabel-studioイメージの作成
  3. ArtifactRegistryへの登録
  4. CloudRunのデプロイ
  5. カスタムドメインでの運用

方針の検討と決定

クラウドサービスを作るにあたって、やっぱりgitリポジトリを作成しその中にソースを入れ・・・といったことをやるととっても面倒なので、今回はGoogle Cloudコンソール上で必要なソースを取得し、そのソースの一部だけを変更しDockerイメージを作成する。
作成したDockerイメージをArtifactRegistryに登録し、それをCloudRunサービスとしてデプロイするというとってもシンプルな進め方にした。

カスタムlabel-studioイメージの作成

以下の順番通り実施することで、カスタムlabel-studioイメージを作成しました。

Google Cloudコンソールの立ち上げ

ブラウザ経由で進めてもいいが、ターミナルソフトで立ち上げるのが気に入っているので以下のコマンドでGoogle Cloudコンソールを起動する

gcloud cloud-shell ssh --authorize-session

label-studioのソースを取得

以下のコマンドでlabel-studioのソースを取得する

git clone https://github.com/HumanSignal/label-studio

litestreamの導入

label-studioはデフォルトでSQLite動作するのでそのあたりの変更は全くせず、デフォルトで保存されているSQLiteファイルの場所を確認し、以下のパスに保存されていることを確認した。

/label-studio/data/label_studio.sqlite3

この内容を用いて以下のようなlitestream.ymlをローカルPC内に作成する。Google Cloud Storage(以後:GCS)のパスは自分の環境に合わせて決めてください。

litestream.yml
dbs:
  - path: /label-studio/data/label_studio.sqlite3
    replicas:
      - url: gcs://[Google Cloud Storageのバケット名]/[保存したいフォルダ名]

その後、litestream経由でlabel-studioを起動するシェルスクリプトentrypoint.shを以下のような感じでローカルPCに作成する。

entrypoint.sh
#!/bin/bash
set -e

# when launching instance, remove sqlite file if it exists.
if [ -f /label-studio/data/label_studio.sqlite3 ]; then
  rm /label-studio/data/label_studio.sqlite3
fi

# Restore the database
litestream restore -if-replica-exists -config /etc/litestream.yml /label-studio/data/label_studio.sqlite3

# Run litestream with label-studio as the subprocess.
exec litestream replicate -exec "label-studio" -config /etc/litestream.yml

gitクローンによって取得したlabel-studioディレクトリ内にあるDockerfileを以下のように修正する。これはGoogle Cloud コンソール内なので、viを用いるかGoogle Cloud Shellエディタを用いて修正する。
修正した内容は以下の通り。

  1. litestreamをgithubから取得→解凍→Dockerイメージ内/usr/local/binに展開
  2. 先ほど作成したlitestream.ymlおよびentorypoint.shをDockerイメージ内にコピー
  3. 環境変数「LABEL_STUDIO_ONE_CLICK_DEPLOY」を1に設定
    必要に応じて「LABEL_STUDIO_DISABLE_SIGNUP_WITHOUT_LINK」や「LABEL_STUDIO_USERNAME」、「LABEL_STUDIO_PASSWORD」を設定して不用意にユーザ追加できないようにするのもあり。
  4. 起動時にlabel-studioを立ち上げるのではなく、entorypoint.shを立ち上げるように変更
# syntax=docker/dockerfile:1
ARG NODE_VERSION=18
 :
(省略)
 :
RUN python3 label_studio/manage.py collectstatic --no-input && \
    chown -R 1001:0 $LS_DIR && \
    chmod -R g=u $LS_DIR

### =====================================================
# add litestream for SQLite replication
### -----------------------------------------------------
ADD https://github.com/benbjohnson/litestream/releases/download/v0.3.13/litestream-v0.3.13-linux-amd64.tar.gz /tmp/litestream.tar.gz
RUN tar -C /usr/local/bin -xzf /tmp/litestream.tar.gz
COPY --chmod=755 web/new/entrypoint.sh /usr/bin/entrypoint.sh
COPY web/new/litestream.yml /etc/litestream.yml
ENV LABEL_STUDIO_ONE_CLICK_DEPLOY=1
### =====================================================

ENV HOME=$LS_DIR
 :
(省略)
 :
ENTRYPOINT ["./deploy/docker-entrypoint.sh"]

### =====================================================
# add litestream for SQLite replication
### -----------------------------------------------------
#CMD ["label-studio"]
CMD ["/usr/bin/entrypoint.sh"]
### =====================================================

作成したファイルをコピーや編集対象ファイル

litestream.ymlとentorypoint.shをGoogle Cloud Shellエディタに対して直接D&Dすることで所定のディレクトリにコピーできる。
ここでコピーする場所は以下の通りである。また編集するDockerfileの位置も同様に示す。
(補足:web以下に配置した理由は私のDocker知識があまりないせいでどうもCOPYでエラーになるため、COPYでエラーにならないディレクトリを探した結果webディレクトリ以下だったからである。これは後程解決したい問題の一つです)

/label-studio
  |___/web
  |     |____/new                   <---新規追加
  |            |___litestream.yml   <---新規追加
  |            |___entorypoint.sh   <---新規追加
  |___Dockerfile                    <---上書き修正

Dockerイメージファイルの作成

カレントディレクトリを/label-studioに移動し、以下のコマンドを実行しDockerイメージを作成する

docker build -f Dockerfile -t label-studio .

起動確認など

実際に作ったDockerイメージを動かして無事litestreamのサブプロセスとしてlabel-studioが起動していることを確かめた。

docker run -it label-studio

ArtifactRegistryへの登録

リポジトリ作成

以下のように、Google Cloudコンソール上でArtifactRegistryサービスに移動し適切なリポジトリ名でリポジトリを作成する。ここではリージョンはasia-northeast1、リポジトリ名はlabel-studioとする。
image.png
image.png
image.png

リージョンasia-northeast1のDockerリポジトリに対する認証を設定

以下のコマンドを実行し、Dockerリポジトリに対する認証設定をする。

gcloud auth configure-docker asia-northeast1-docker.pkg.dev

タグ付け

ビルドしたDockerイメージに対してArtifactRegistry用にタグ付けをする。
以下のコマンドを実行し、作成したDockerイメージのIMAGE IDを取得する

docker image list

REPOSITORY     TAG       IMAGE ID       CREATED          SIZE
label-studio   latest    5064a45a61ea   16 seconds ago   1.46GB

そのIMAGE IDを用いて以下のコマンドでタグ付けをする。

docker tag 5064a45a61ea asia-northeast1-docker.pkg.dev/[GCPのプロジェクト名]/label-studio/202407261200

docker tag [IMAGE ID] [ArtifactRegistryの場所]/[GCPのプロジェクト名]/[リポジトリ名]/[リポジトリで利用するイメージ名]

ArtifactRegistryへ登録

タグ付け後、以下のコマンドでArtifactRegistryに登録する。

docker push asia-northeast1-docker.pkg.dev/[GCPのプロジェクト名]/label-studio/202407261200

CloudRunのデプロイ

以下のコマンドで直接Cloud Runサービスを立ち上げることができる。

gcloud run deploy label-studio --image asia-northeast1-docker.pkg.dev/[GCPのプロジェクト名]/label-studio/202407261200:latest

gcloud run deploy [リポジトリ名] --image [ArtifactRegistryの場所]/[GCPのプロジェクト名]/[リポジトリ名]/[リポジトリで利用するイメージ名]:[tag]

GCPのアクセス権関係の付与

CloudRunで動作するlabel-studioサービスはlitestream.ymlで設定したGCSにアクセスするため、デプロイ後にGoogle Cloudコンソール上でCloudRunサービスにアクセスし、YAML内のserviceAccountNameからサービスアカウント名を確認し、そのサービスアカウントに対して権限を付与する。
image.png

サービスアカウントに付与した権限リスト.
storage.buckets.get
storage.buckets.getIamPolicy
storage.buckets.update
storage.objects.create
storage.objects.delete
storage.objects.get
storage.objects.getIamPolicy
storage.objects.list
storage.objects.update
resourcemanager.projects.get
resourcemanager.projects.list
storage.managedFolders.get
storage.managedFolders.list

カスタムドメインでの運用

以下CloudRunサービスにある統合で「インテグレーションを追加」を押して「カスタムドメイン-Google Cloud Load Balancing」を選択する。あとは追加したいドメインを記述して作成することで、カスタムドメイン接続に必要な情報が生成されるので、それを利用する。
image.png
image.png

カスタムドメインの設定後はLoad BalancerやCloud ArmorやIAPを設定すれば必要最低限のネットアクセスが可能なのでセキュアなサイト構築ができるので、そこは環境に合わせて設定するように。

Label-Studioの設定

アクセス権の設定

label-studioのマニュアルを参照し、クラウドストレージを利用する場合、必要に応じてアクセス権を付与する必要がある。

GCSに対するCORSの設定

label-studioのマニュアルを参照し、こちらの環境下であるGCSのバケットに対してCORS設定を更新した。

それでもソースファイルを見に行った時に以下のエラーが生じた場合、ADCの設定を見直すとできるときがある。
image.png
実際に私が実施した内容は、設定したADC設定は以下の図に「Paste the contents of credentials.json here OR ...」書いてあるので、サービスアカウントのJSONを作成し、そのファイルを開いて中身をすべて選択しコピーした内容を「Google Application Credentials, leave blank to use default credentials(ADC)」にペーストした。結果、上記エラーが起きなくなった
image.png

その後

以下のように環境変数を組み合わせることで、デプロイするだけで特定snapshotに復元してから立ち上げたりとかできるので、用途に合わせて組み込んでいくといい感じだった。

entrypoint.sh
# (抜粋)
  if [ "$USE_TARGET_GENERATION" = 'true' ]; then
    litestream restore -if-replica-exists -generation $TARGET_GENERATION -o /label-studio/data/label_studio.sqlite3 gcs://(GCSのパス)
  else
    litestream restore -if-replica-exists -config /etc/litestream.yml /label-studio/data/label_studio.sqlite3
  fi
ローカルで世代を確認するコマンド.
./litestream snapshots gcs://(GCSのパス)

replica  generation        index  size    created
gcs      0d97977e3789e113  0      780271  2024-08-13T07:07:22Z
gcs      28b7e7f8c4753701  0      780272  2024-08-20T01:24:12Z

以下のようにコマンドで実行してもよいし、Cloud Runコンソールで環境変数を設定してデプロイしても良い。

Cloud Runへのデプロイ.
gcloud run deploy [リポジトリ名] --image [ArtifactRegistryの場所]/[GCPのプロジェクト名]/[リポジトリ名]/[リポジトリで利用するイメージ名]:[tag] --set-env-vars "USE_TARGET_GENERATION=true" --set-env-vars "TARGET_GENERATION=(generationの値)"

※Cloud Runの環境変数に設定されるので、一度立ち上げた後はCloud Runコンソールからその環境変数を削除しておこう。

動作確認環境 (2024/9/11追記)

label-studio:1.13.1.dev0
確認したブラウザ:Google Chrome 127.0.6533.0

上記追加した理由は新しいGoogle Chrome 128.x.x.xではプロジェクトの内容が描画されなかったため、label-studio側のアップデートが必要になったため
label-studio側をアップデートしてどうなるかは今後検討する。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?