Freigeben über


Verbinden einer externen App mit Lakebase mithilfe der API

Von Bedeutung

Lakebase Autoscaling ist in den folgenden Regionen verfügbar: eastus, eastus2, centralus, southcentralus, westus, westus2, canadacentral, brazilsouth, northeurope, uksouth, westeurope, australiaeast, centralindia, southeastasia.

Lakebase Autoscaling ist die neueste Version von Lakebase mit automatischer Berechnung, Skalierung bis Null, Verzweigung und sofortiger Wiederherstellung. Wenn Sie ein Lakebase Provisioned-Benutzer sind, lesen Sie Lakebase Provisioned.

In diesem Handbuch wird gezeigt, wie Sie externe Anwendungen mithilfe von direkten REST-API-Aufrufen mit Lakebase-Autocaling verbinden. Verwenden Sie diesen Ansatz, wenn ein Databricks SDK für Ihre Sprache nicht verfügbar ist (Node.js, Ruby, PHP, Elixir, Rust usw.).

Wenn Ihre Programmiersprache SDK-Unterstützung (Python, Java oder Go) bietet, verwenden Sie Verbinden Sie die externe App mit Lakebase über das SDK, um eine einfachere Tokenverwaltung zu ermöglichen.

Sie führen zwei API-Aufrufe aus, um Datenbankanmeldeinformationen mit OAuth-Tokenrotation abzurufen. Beispiele für curl und Node.js.

Hinweis

Zweistufige Authentifizierung: Für diesen Ansatz sind zwei API-Aufrufe für jede Datenbankanmeldeinformation erforderlich: (1) Exchange Service Principal Secret für das OAuth-Token des Arbeitsbereichs, (2) Exchange OAuth-Token für Datenbankanmeldeinformationen. Beide Token laufen nach 60 Minuten ab. Das SDK behandelt Schritt 1 automatisch.

Voraussetzungen

Sie benötigen das gleiche Setup wie der SDK-Ansatz: Dienstprinzipal, Postgres-Rolle und Verbindungsdetails.

Voraussetzung Wichtige Details Mehr Informationen
Service Principal OAuth-Geheimnis mit einer maximalen Lebensdauer von 730 Tagen; Arbeitsbereichszugriff aktivieren. Beachten Sie die Client-ID (UUID) für die Postgres-Rolle und env vars. Service Principal erstellen
Postgres-Rolle Erstellen Sie die OAuth-Rolle im Lakebase SQL-Editor: databricks_create_role('{client-id}', 'SERVICE_PRINCIPAL') und gewähren Sie CONNECT, USAGE, SELECT/INSERT/UPDATE/DELETE. Verwenden Sie die Client-ID aus Schritt 1. Rolle "Postgres erstellen"
Verbindungsdetails Von Lakebase Console Connect: Endpunktname (projects/.../branches/.../endpoints/...), Host, Datenbank (in der Regel databricks_postgres). Abrufen von Verbindungsdetails

Funktionsweise

Der manuelle API-Ansatz erfordert zwei Tokenaustausche:

Manueller API-Tokenaustauschablauf

Tokenlebensdauer:

  • Dienstprinzipalschlüssel: Bis zu 730 Tage (während der Erstellung festgelegt)
  • OAuth-Token des Arbeitsbereichs: 60 Minuten (Schritt 1)
  • Datenbank-Zugangsdaten: 60 Minuten (Schritt 2)

Token-Scoping: Datenbankanmeldeinformationen sind arbeitsbereichsbezogen. Während der endpoint Parameter erforderlich ist, kann das zurückgegebene Token auf eine beliebige Datenbank oder ein Projekt im Arbeitsbereich zugreifen, für den der Dienstprinzipal über Berechtigungen verfügt.

Festlegen von Umgebungsvariablen

Legen Sie diese Umgebungsvariablen fest, bevor Sie Ihre Anwendung ausführen:

# Databricks workspace authentication
export DATABRICKS_HOST="https://your-workspace.databricks.com"
export DATABRICKS_CLIENT_ID="<service-principal-client-id>"
export DATABRICKS_CLIENT_SECRET="<your-oauth-secret>"

# Lakebase connection details (from prerequisites)
export ENDPOINT_NAME="projects/<project-id>/branches/<branch-id>/endpoints/<endpoint-id>"
export PGHOST="<endpoint-id>.database.<region>.cloud.databricks.com"
export PGDATABASE="databricks_postgres"
export PGUSER="<service-principal-client-id>"   # Same UUID as client ID
export PGPORT="5432"

Hinzufügen von Verbindungscode

cURL

Dieses Beispiel zeigt die unformatierten API-Aufrufe. Implementieren Sie für Produktionsanwendungen Tokenzwischenspeicherung und Aktualisierungslogik.

# Step 1: Get workspace OAuth token
OAUTH_TOKEN=$(curl -s -X POST "${DATABRICKS_HOST}/oidc/v1/token" \
  -u "${DATABRICKS_CLIENT_ID}:${DATABRICKS_CLIENT_SECRET}" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&scope=all-apis" \
  | jq -r '.access_token')

echo "Got workspace OAuth token (60-min lifetime)"

# Step 2: Get database credential
PG_TOKEN=$(curl -s -X POST "${DATABRICKS_HOST}/api/2.0/postgres/credentials" \
  -H "Authorization: Bearer ${OAUTH_TOKEN}" \
  -H "Content-Type: application/json" \
  -d "{\"endpoint\": \"${ENDPOINT_NAME}\"}" \
  | jq -r '.token')

echo "Got database credential (60-min lifetime)"

# Step 3: Connect to Postgres
PGPASSWORD="${PG_TOKEN}" psql \
  -h "${PGHOST}" \
  -p "${PGPORT}" \
  -U "${PGUSER}" \
  -d "${PGDATABASE}" \
  -c "SELECT current_user, current_database()"

Node.js

In diesem Beispiel werden Node-Postgres mit einer asynchronen Kennwortfunktion verwendet, die das Abrufen und Zwischenspeichern von Token verarbeitet.

import pg from 'pg';

// Step 1: Fetch workspace OAuth token
async function getWorkspaceToken(host, clientId, clientSecret) {
  const auth = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
  const response = await fetch(`${host}/oidc/v1/token`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Authorization: `Basic ${auth}`,
    },
    body: 'grant_type=client_credentials&scope=all-apis',
  });

  if (!response.ok) {
    throw new Error(`OAuth failed: ${response.status}`);
  }

  const data = await response.json();
  return {
    token: data.access_token,
    expires: Date.now() + data.expires_in * 1000,
  };
}

// Step 2: Fetch database credential
async function getPostgresCredential(host, workspaceToken, endpoint) {
  const response = await fetch(`${host}/api/2.0/postgres/credentials`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${workspaceToken}`,
    },
    body: JSON.stringify({ endpoint }),
  });

  if (!response.ok) {
    throw new Error(`Database credential failed: ${response.status}`);
  }

  const data = await response.json();
  return {
    token: data.token,
    expires: new Date(data.expire_time).getTime(),
  };
}

// Simple caching wrapper (production: use more sophisticated caching)
function cached(fetchFn) {
  let cache = null;
  return async (...args) => {
    const now = Date.now();
    if (!cache || now >= cache.expires - 5 * 60 * 1000) {
      // Refresh 5 min early
      const result = await fetchFn(...args);
      cache = result;
    }
    return cache.token;
  };
}

// Create connection pool with async password function
function createPool() {
  const host = process.env.DATABRICKS_HOST;
  const clientId = process.env.DATABRICKS_CLIENT_ID;
  const clientSecret = process.env.DATABRICKS_CLIENT_SECRET;
  const endpoint = process.env.ENDPOINT_NAME;

  const cachedWorkspaceToken = cached(() => getWorkspaceToken(host, clientId, clientSecret));
  const cachedPostgresToken = cached(async () => {
    const workspaceToken = await cachedWorkspaceToken();
    return getPostgresCredential(host, workspaceToken, endpoint);
  });

  return new pg.Pool({
    host: process.env.PGHOST,
    port: process.env.PGPORT,
    database: process.env.PGDATABASE,
    user: process.env.PGUSER,
    password: cachedPostgresToken, // Async function: () => Promise<string>
    ssl: { rejectUnauthorized: true },
    min: 1,
    max: 10,
    idleTimeoutMillis: 900000, // Example: 15 minutes
    connectionTimeoutMillis: 60000, // Example: 60 seconds
  });
}

// Use the pool
const pool = createPool();
const result = await pool.query('SELECT current_user, current_database()');
console.log('Connected as:', result.rows[0].current_user);

Abhängigkeiten:pg (node-postgres)

Hinweis: Node-postgres (pg) akzeptiert eine asynchrone Funktion als Kennwort. Die Funktion wird jedes Mal aufgerufen, wenn eine neue Verbindung erstellt wird, um frische Token sicherzustellen.

Ausführen und Überprüfen der Verbindung

cURL

Führen Sie das Bash-Skript mit geladenen Umgebungsvariablen aus:

export $(cat .env | xargs)
bash connect.sh

Erwartete Ausgabe:

Got workspace OAuth token (60-min lifetime)
Got database credential (60-min lifetime)
     current_user      | current_database
-----------------------+------------------
 c00f575e-d706-4f6b... | databricks_postgres

Wenn die current_user-Angabe mit der Client-ID des Serviceprincipals übereinstimmt, funktioniert OAuth ordnungsgemäß.

Node.js

Abhängigkeiten installieren:

npm install pg

Ausführen:

node app.js

Erwartete Ausgabe:

Connected as: c00f575e-d706-4f6b-b62c-e7a14850571b

Hinweis: Die erste Verbindung nach dem Leerlauf kann mehr Zeit in Anspruch nehmen, da die Rechenkapazitäten des Lakebase-Autoscaling von Null beginnen.

Problembehandlung

Fehler Reparatur
"invalid_client" oder "Fehlende Clientauthentifizierung" Überprüfen Sie, ob DATABRICKS_CLIENT_ID und DATABRICKS_CLIENT_SECRET richtig sind. Verwenden Sie die Standardauthentifizierung (base64-codiert).
"API ist für Benutzer ohne Arbeitsbereichszugriffsberechtigung deaktiviert" Aktivieren Sie "Arbeitsbereichszugriff" für den Dienstprinzipal (Voraussetzungen).
"INVALID_PARAMETER_VALUE" / "Feld "Endpunkt" ist erforderlich" Stellen Sie sicher, dass der endpoint-Parameter im Schritt 2 im POST-Textkörper im Format projects/<id>/branches/<id>/endpoints/<id> enthalten ist.
"Rolle ist nicht vorhanden" oder Authentifizierung schlägt fehl. Erstellen einer OAuth-Rolle über SQL (Voraussetzungen).
"Verbindung verweigert" oder Timeout Die erste Verbindung nach einem Scale-to-Zero-Vorgang kann länger dauern. Implementieren Sie die Wiederholungslogik.
Token abgelaufen/ "Kennwortauthentifizierung fehlgeschlagen" Arbeitsbereichs- und Datenbanktoken laufen nach 60 Minuten ab. Implementieren sie Zwischenspeicherung mit Ablaufüberprüfungen.