メインコンテンツに移動

Lakebase plugin

Lakebase plugin

Databricks Lakebase オートスケーリング 向けの PostgreSQL 接続プールを提供し、OAuth トークンを自動でリフレッシュします。

主な機能:

  • あらゆる PostgreSQL ライブラリや ORM で利用できる標準の pg.Pool
  • OAuth トークンの自動リフレッシュ(トークン有効期間 1 時間、リフレッシュバッファ 2 分)
  • API 呼び出しを最小限に抑えるトークンキャッシュ
  • OpenTelemetry 計装を標準搭載(クエリ実行時間、プール接続数、トークンのリフレッシュ)
  • クエリおよび接続イベント向けに AppKit ロガーを既定で構成

Lakebase を使い始める

Lakebase plugin を使い始めるには、Databricks CLI で AppKit と Lakebase plugin をインストール済みの Databricks app を新規作成するのが最も簡単です。

前提条件

Steps

  1. まず、Get started ドキュメントに従って、新しい Lakebase Postgres オートスケーリング project を作成します。
  2. Lakebase plugin をプロジェクトに追加するには、databricks apps init コマンドを実行し、対話形式で Lakebase plugin を選択します。CLI の案内に従って、Lakebase の project、branch、データベースを選択してください。
    • 確認を求められたら Yes を選択し、作成直後にアプリを Databricks Apps へ deploy します。

基本的な使い方

import { createApp, lakebase, server } from "@databricks/appkit";

await createApp({
  plugins: [server(), lakebase()],
});

プールへのアクセス

初期化後は、AppKit.lakebase オブジェクト経由で Lakebase にアクセスします。

const AppKit = await createApp({
  plugins: [server(), lakebase()],
});

await AppKit.lakebase.query(`CREATE SCHEMA IF NOT EXISTS app`);

await AppKit.lakebase.query(`CREATE TABLE IF NOT EXISTS app.orders (
  id SERIAL PRIMARY KEY,
  user_id VARCHAR(255) NOT NULL,
  amount DECIMAL(10, 2) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)`);

const result = await AppKit.lakebase.query(
  "SELECT * FROM app.orders WHERE user_id = $1",
  [userId],
);

// 生の pg.Pool(ORM や高度な用途向け)
const pool = AppKit.lakebase.pool;

// ORM にそのまま渡せる設定オブジェクト
const ormConfig = AppKit.lakebase.getOrmConfig();  // { host, port, database, ... }
const pgConfig = AppKit.lakebase.getPgConfig();    // pg.PoolConfig

設定

環境変数

必須の環境変数は次のとおりです。

変数説明
LAKEBASE_ENDPOINTendpoint リソースのパス (例: projects/.../branches/.../endpoints/...)
PGHOSTLakebase のホスト (本番環境では postgres Databricks Apps リソースが自動的に注入します)
PGDATABASEデータベース名 (本番環境では postgres Databricks Apps リソースが自動的に注入します)
PGSSLMODETLS モード。require を指定します (本番環境では postgres Databricks Apps リソースが自動的に注入します)

postgres データベースリソースを構成した状態で Databricks Apps にデプロイすると、PGHOSTPGDATABASEPGSSLMODEPGUSERPGPORTPGAPPNAME はプラットフォームが自動的に注入します。明示的に設定する必要があるのは LAKEBASE_ENDPOINT のみです。

env:
  - name: LAKEBASE_ENDPOINT
    valueFrom: postgres

ローカル開発では、.env ファイルは databricks apps init によって、お使いの Lakebase project に対応した正しい値で自動生成されます。

設定の完全なリファレンス (SSL、プールサイズ、タイムアウト、ロギング、ORM の例) については、@databricks/lakebase README を参照してください。

プール設定

デフォルト値を上書きするには、pool オブジェクトを渡します。

await createApp({
  plugins: [
    lakebase({
      pool: {
        max: 10,                      // プールの最大接続数(デフォルト: 10)
        connectionTimeoutMillis: 5000, // 接続タイムアウト(ミリ秒、デフォルト: 10000)
        idleTimeoutMillis: 30000,      // アイドル接続のタイムアウト(ミリ秒、デフォルト: 30000)
      },
    }),
  ],
});

On-Behalf-Of (OBO) — ユーザーごとの接続

アプリで行レベルセキュリティ (RLS) やユーザー単位のデータ分離が必要な場合は、asUser(req) を使用して、ユーザーごとの Lakebase 接続プールでクエリを実行します。各ユーザーのプールはそのユーザーの Databricks ID で認証されるため、PostgreSQL の current_user には実際のユーザーが反映されます。

前提条件

  1. Databricks App で postgres スコープを指定して ユーザー認可を有効化 します。設定手順は User authorization を参照してください。databricks.yml では次のように記述します:

    resources:
      apps:
        app:
          user_api_scopes:
            - postgres

    databricks apps init と Lakebase plugin でスキャフォールディングしたアプリには、この設定が自動的に含まれます。

  2. アプリのユーザーごとに Lakebase 上の Postgres ロール が必要です。Databricks CLI で作成します:

    databricks postgres create-role "projects/{project_id}/branches/{branch_id}" \
      --json '{"spec": {"identity_type": "USER", "postgres_role": "user@example.com"}}'

    Lakebase UI の Branch OverviewAdd role からロールを作成することもできます。

    note

    OBO ユーザーに databricks_superuser を付与しないでください。スーパーユーザーは RLS を回避してしまいます。代わりに fine-grained grants を使用してください。

使い方

設定は不要です。asUser(req) を呼び出すだけです。

const AppKit = await createApp({
  plugins: [server(), lakebase()],
});

// サービスプリンシパルによるクエリ(デフォルト — テーブル所有者として RLS をバイパス)
const all = await AppKit.lakebase.query("SELECT * FROM app.orders");

// ユーザースコープのクエリ(ユーザーごとのプール、RLS が適用される)
app.get("/api/my-orders", async (req, res) => {
  const result = await AppKit.lakebase
    .asUser(req)
    .query("SELECT * FROM app.orders ORDER BY created_at DESC");
  res.json(result.rows);
});

asUser(req) を呼び出すと、次の処理が行われます。

  1. x-forwarded-access-token および x-forwarded-email ヘッダー (Databricks Apps が自動的に設定) から、ユーザーのトークンと ID が抽出されます。
  2. ユーザーの OAuth 資格情報を使って、ユーザーごとの pg.Pool が作成 (または再利用) されます。
  3. query()pool はそのユーザーのプールを使用し、PostgreSQL の current_user にはそのユーザーの ID が反映されます。

行レベルセキュリティ (RLS) の例

-- サービスプリンシパルとして実行(アプリのセットアップ時):
ALTER TABLE app.orders ENABLE ROW LEVEL SECURITY;

CREATE POLICY user_orders ON app.orders
  FOR ALL TO PUBLIC
  USING (owner = current_user);

-- OBO ユーザーがクエリを実行できるようにアクセス権を付与
GRANT USAGE ON SCHEMA app TO PUBLIC;
GRANT SELECT, INSERT ON ALL TABLES IN SCHEMA app TO PUBLIC;

仕組み

  • サービスプリンシパルプール (AppKit.lakebase.pool) は常に作成され、DDL 操作、シード処理、管理用クエリに使用されます。
  • ユーザーごとのプールは最初の asUser(req) 呼び出し時に作成され、ユーザー ID ごとにキャッシュされます。各プールは独自の OAuth トークンのリフレッシュサイクルを持ちます。
  • ユーザーごとのプール内のアイドル接続は自動的にクローズされます (アイドルタイムアウトは 30 秒) 。空になったプールオブジェクトは定期的にクリーンアップされます。
  • シャットダウン時には、すべてのプール (SP + ユーザー) が正常にクローズされます。
  • 開発モード (NODE_ENV=development) では、ユーザートークンが利用できない場合、asUser(req) は警告を出力して SP プールにフォールバックします。
RLS とスーパーユーザー

PostgreSQL のスーパーユーザーは行レベルセキュリティ (RLS) を完全にバイパスします。databricks_superuser ロールを持つユーザーは、RLS ポリシーに関係なくすべての行を参照できます。RLS を確実に適用するには、スーパーユーザーロールではなくfine-grained grantsを使用してください。

データベース権限

はじめにガイドに従って Lakebase リソースを持つアプリを作成すると、サービスプリンシパルに postgres リソースに対する CONNECT_AND_CREATE 権限が自動的に付与されます。これにより、サービスプリンシパルはデータベースに接続して新しいオブジェクトを作成できますが、既存のスキーマやテーブルにはアクセスできません。

ローカル開発

deploy済みの Lakebase データベースに対してローカルで開発する手順は次のとおりです。

  1. まずアプリをdeployします。 初回deploy時に、サービスプリンシパルがデータベーススキーマとテーブルを作成します。databricks apps init で生成したアプリはこの処理を自動で行います。起動時にテーブルの有無を確認し、すでに存在する場合は作成をスキップします。

  2. databricks_superuser を付与します (Lakebase project のオーナーであればスキップしてください。すでにフルアクセス権があります) :

    # databricks_superuser を持つ新しいロールを作成する
    databricks postgres create-role "projects/{project_id}/branches/{branch_id}" \
      --json '{"spec": {"identity_type": "USER", "postgres_role": "user@example.com", "membership_roles": ["DATABRICKS_SUPERUSER"]}}'

    既存のロールに スーパーユーザー を付与するには、update-role を使用します:

    databricks postgres update-role \
      "projects/{project_id}/branches/{branch_id}/roles/{role_id}" \
      "spec.membership_roles" \
      --json '{"spec": {"membership_roles": ["DATABRICKS_SUPERUSER"]}}'

    また、Lakebase オートスケーリング UI で project の Branch Overview ページ → Add role / Edit role からロールを管理することもできます。

  3. ローカルで実行します。 OAuth 認証には Databricks のユーザー ID (メールアドレス) が使用されます。databricks_superuser ロールには完全な DML アクセス (データの読み書き) が与えられますが、DDL (スキーマやテーブルの作成) は含まれません。先にdeployすることが重要なのはこのためです (下記の注記を参照) 。

他のユーザーにも同様に、手順 2 を繰り返して各ユーザー用に databricks_superuser を持つ OAuth ロールを作成してください。

tip

Postgres パスワード認証 は、OAuth ロールの権限まわりの複雑さを避けられる、よりシンプルな代替手段です。ただし、Lakebase オートスケーリング UI の Branch Overview ページでユーザーのパスワードを設定しておく必要があります。

なぜ先にdeployするのか?

アプリをdeployすると、サービスプリンシパルがスキーマとテーブルを作成し、そのオーナーになります。databricks_superuser には完全な DML アクセス (読み書き) が与えられますが DDL は含まれないため、ローカル開発が可能になるのはスキーマが作成された後です。

先に npm run dev を実行してしまうと、自分の資格情報がスキーマのオーナーとなり、deployしたアプリ側で permission denied が発生します。復旧するには、まずデータをエクスポートし (pg_dump または一時的なスキーマのコピー) 、スキーマを削除してから再deployしてください。再deploy後、サービスプリンシパルが起動時にスキーマを再作成します。 (PostgreSQL のスキーマ所有権は作成したロールに紐付いており、通常のユーザーが再割り当てすることはできません。)

きめ細かな権限

ほとんどのユースケースでは databricks_superuser で十分です。スキーマ単位の grants が必要な場合は、公式ドキュメントを参照してください。

fine-grained grants 用の SQL スクリプト

これらの grants を実行する前に、アプリを少なくとも一度は deploy して run し、サービスプリンシパルにデータベーススキーマを初期化させてください。

subject はユーザーのメールアドレスに、schema は使用するスキーマ名に置き換えてください。

CREATE EXTENSION IF NOT EXISTS databricks_auth;

DO $$
DECLARE
  subject TEXT := 'your-subject';  -- name@databricks.com のようなユーザーのメールアドレス
  schema TEXT := 'your_schema'; -- 'your_schema' をスキーマ名に置き換えてください
BEGIN
  -- Databricks ID 用の OAuth ロールを作成
  PERFORM databricks_create_role(subject, 'USER');

  -- 接続とスキーマへのアクセス
  EXECUTE format('GRANT CONNECT ON DATABASE "databricks_postgres" TO %I', subject);
  EXECUTE format('GRANT ALL ON SCHEMA %s TO %I', schema, subject);

  -- 既存オブジェクトに対する権限
  EXECUTE format('GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA %s TO %I', schema, subject);
  EXECUTE format('GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA %s TO %I', schema, subject);
  EXECUTE format('GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA %s TO %I', schema, subject);
  EXECUTE format('GRANT ALL PRIVILEGES ON ALL PROCEDURES IN SCHEMA %s TO %I', schema, subject);

  -- 今後作成されるオブジェクトに対するデフォルト権限
  EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %s GRANT ALL ON TABLES TO %I', schema, subject);
  EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %s GRANT ALL ON SEQUENCES TO %I', schema, subject);
  EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %s GRANT ALL ON FUNCTIONS TO %I', schema, subject);
  EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %s GRANT ALL ON ROUTINES TO %I', schema, subject);
END $$;

Databricks Developer Hub

次のエージェント型アプリを数分でリリースする準備はできていますか?

ドキュメントを読む