Cloudflare ContainersでDrizzle Gatewayを動かす

Drizzle Gatewayを使うとDrizzle StudioをSelf Hostできます。

gateway.drizzle.team

drizzle-kit studio をそのまま本番でセルフホストすれば良くね?と思っていましたが公式ドキュメントの Limitations に、ローカル開発向けであり、リモート(VPS など)で使うことは想定していないと明記されています。

orm.drizzle.team

Our hosted version Drizzle Studio is meant to be used for local development and not meant to be used on remote (VPS, etc).

今回はこれを Cloudflare Containers 上で動かしました。 ここで問題になるのが永続ストレージです。Cloudflare Containers のローカルディスクは永続化されないため、Gateway が STORE_PATH に設定やセッションを書き込む要件を、そのままでは満たせません。そこで R2 を FUSE(tigrisfs)でマウントし、そのマウント先を STORE_PATH に割り当てることで回避します。

Worker 側は薄く、getContainer(env.DRIZZLE_GATEWAY) で取得したコンテナへ プロキシするだけです。

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const container = getContainer(env.DRIZZLE_GATEWAY);
    return container.fetch(request);
  },
};

コンテナ側もベースイメージは ghcr.io/drizzle-team/gateway を使い、FUSE と tigrisfs を追加して、起動するだけです。

FROM ghcr.io/drizzle-team/gateway:latest

ARG TIGRISFS_VERSION=v1.2.1

USER root

RUN if command -v apt-get > /dev/null 2>&1; then \
      apt-get update && apt-get install -y --no-install-recommends \
        ca-certificates fuse curl && \
      rm -rf /var/lib/apt/lists/*; \
    elif command -v apk > /dev/null 2>&1; then \
      apk add --no-cache ca-certificates fuse curl; \
    fi

RUN curl -fL "https://github.com/tigrisdata/tigrisfs/releases/download/${TIGRISFS_VERSION}/tigrisfs_${TIGRISFS_VERSION#v}_linux_amd64.tar.gz" | \
    tar -xzf - -C /usr/local/bin/

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENV STORE_PATH=/data
ENV PORT=4983

CMD ["/entrypoint.sh"]

スクリプトでは、まず tigrisfs を起動してマウントが有効になるまで待ち、その後に Gateway を立ち上げます。

MOUNT_DIR="${STORE_PATH:-/data}"
R2_ENDPOINT="https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com"
/usr/local/bin/tigrisfs --endpoint "${R2_ENDPOINT}" -f "${R2_BUCKET_NAME}" "${MOUNT_DIR}" &
until mountpoint -q "${MOUNT_DIR}"; do sleep 1; done
node /app/index.js &

trap cleanup TERM INT
fusermount -u "${MOUNT_DIR}" 2>/dev/null || umount "${MOUNT_DIR}" 2>/dev/null || true

この構成なら Worker はシンプルなままにして、Gateway の状態だけを R2 に逃がせます。FUSE 越しのオブジェクトストレージは高頻度 I/O には向きませんが、Drizzle Studio のような管理 UI を載せる用途であれば、十分現実的な構成かなと思います。