Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 194 additions & 0 deletions website/docs/streaming-lakehouse/datalake-catalogs/gravitino.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
---
title: Gravitino
sidebar_position: 3
---

# Apache Gravitino

## Introduction

[Apache Gravitino](https://gravitino.apache.org/) is a high-performance metadata management system that provides a unified metadata layer for data lake and lakehouse architectures. It offers an [Iceberg REST Catalog](https://iceberg.apache.org/rest-catalog-spec) interface with credential vending support, making tiered Iceberg tables discoverable and queryable by any Iceberg-compatible engine.

This guide explains how to configure Fluss to use Apache Gravitino as its Iceberg REST catalog. For general Iceberg integration details (table mapping, data types, limitations), see [Iceberg Integration](/docs/next/streaming-lakehouse/datalake-formats/iceberg/).

## How It Works

When Fluss is configured with Gravitino as its Iceberg REST catalog:

1. Fluss creates and manages Iceberg table metadata through Gravitino's REST API
2. The [tiering service](/docs/next/install-deploy/deploying-streaming-lakehouse/#starting-the-tiering-service) writes data to object storage and commits snapshots via Gravitino
3. Gravitino provides S3 credentials dynamically through credential vending (no static credentials needed)
4. Any Iceberg-compatible engine (Flink, Spark, Trino, StarRocks, etc.) can discover and query the tiered tables through Gravitino

## Prerequisites

### Running Gravitino Instance

You need a running Gravitino instance (version 1.3.0+). Refer to the [Gravitino Getting Started](https://gravitino.apache.org/docs/1.3.0/getting-started/index) guide for deployment instructions.

### AWS Bundle for S3 Support

Gravitino requires the AWS bundle for S3 support:

**For Docker deployments:**
The `apache/gravitino:latest` image already includes the required bundle.

**For native deployments:**
Download and place the AWS bundle in `iceberg-rest-server/libs/`:

```bash
wget -P ${GRAVITINO_HOME}/iceberg-rest-server/libs/ \
https://repo1.maven.org/maven2/org/apache/gravitino/iceberg-aws-bundle/1.3.0/iceberg-aws-bundle-1.3.0.jar
```

### Create Gravitino Catalog with Credential Vending

After deploying Gravitino, create a metalake and catalog with credential vending enabled:

```bash
# Create metalake
curl -X POST http://<gravitino-host>:8090/api/metalakes \
-H "Content-Type: application/json" \
-d '{"name": "{metalake name}", "comment": "Fluss metadata lake"}'

# Create Iceberg catalog with credential vending
curl -X POST http://<gravitino-host>:8090/api/metalakes/{metalake name}/catalogs \
-H "Content-Type: application/json" \
-d '{
"name": "fluss_iceberg_catalog",
"type": "RELATIONAL",
"provider": "lakehouse-iceberg",
"comment": "Iceberg REST catalog for Fluss",
"properties": {
"uri": "jdbc:postgresql://<postgres-host>:5432/gravitino",
"warehouse": "s3://<bucket>/iceberg-data/",
"catalog-backend": "jdbc",
"jdbc-driver": "org.postgresql.Driver",
"jdbc-user": "postgres",
"jdbc-password": "password",
"s3-endpoint": "http://<s3-endpoint>:9000",
"s3-access-key-id": "<access-key>",
"s3-secret-access-key": "<secret-key>",
"credential-providers": "s3-secret-key"
}
}'
```

> **NOTE**: The `credential-providers: s3-secret-key` property enables credential vending. Gravitino will provide temporary S3 credentials to Fluss instead of requiring static credentials in Fluss configuration.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc currently states that s3-secret-key provides temporary S3 credentials, retrieves credentials dynamically, and therefore requires no static credentials. That isn't how this provider works.

s3-secret-key vends the static access key and secret configured on the catalog. In the Gravitino implementation, S3SecretKeyCredential.expireTimeInMs() returns 0 (and asserts the expiry is 0), so the credentials are not temporary. The benefit is that Fluss doesn't need the credentials configured locally—they are retrieved from Gravitino over the REST channel—but they are still long-lived static credentials.

Only s3-token (STS AssumeRole) vends short-lived, scoped credentials.

I'd suggest either:

  • Switch the example to s3-token if the goal is to demonstrate temporary credentials.
  • Keep s3-secret-key, but reword it to something like: "Gravitino returns the S3 credentials to Fluss, so they don't need to be configured in Fluss." It would also be helpful to add a note that s3-token is the recommended option when temporary, scoped credentials are required.

I think this distinction is important, especially since readers may interpret the current wording as a security property that s3-secret-key doesn't actually provide.


## Configure Fluss with Gravitino

### Cluster Configuration

Add the following to your `server.yaml`:

```yaml
datalake.format: iceberg
datalake.iceberg.type: rest
datalake.iceberg.uri: http://<gravitino-host>:9001/iceberg/
datalake.iceberg.warehouse: fluss_iceberg_catalog
datalake.iceberg.header.X-Iceberg-Access-Delegation: vended-credentials
```

Fluss strips the `datalake.iceberg.` prefix and passes the remaining properties to the Iceberg REST catalog client. You can add any additional [Iceberg REST catalog properties](https://iceberg.apache.org/docs/1.10.1/configuration/#catalog-properties) using the same prefix. For example:

```yaml
# Optional: pass additional REST catalog properties
datalake.iceberg.header.Authorization: Bearer <token>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example config points to http://<host>:9001/iceberg/, and authentication is only mentioned as an optional Authorization: Bearer header.

It would be helpful to explicitly call out the default security posture. Out of the box, the Iceberg REST service does not enforce authentication, so the endpoint is accessible unless server-side authentication is configured. A short note (or a link to the relevant documentation) on securing the endpoint would help prevent users from unintentionally exposing it.

This is separate from credential vending, but the two are easy to conflate, so making the distinction explicit would improve the documentation.

```

**Key Properties:**

- `datalake.iceberg.uri`: Gravitino's Iceberg REST API endpoint (port 9001)
- `datalake.iceberg.warehouse`: The catalog name created in Gravitino (not `metalake.catalog`, just `catalog`)
- `datalake.iceberg.header.X-Iceberg-Access-Delegation: vended-credentials`: Enables credential vending

With credential vending enabled, you do **not** need to specify `s3-access-key-id` or `s3-secret-access-key` in Fluss configuration. However, you still need S3 endpoint configuration:

```yaml
# S3 endpoint configuration (required)
datalake.iceberg.s3.endpoint: http://<s3-endpoint>:9000
datalake.iceberg.s3.path-style-access: true
datalake.iceberg.s3.region: us-east-1
```

#### Hadoop Dependencies

Some FileIO implementations require Hadoop classes. Place the pre-bundled Hadoop JAR into `FLUSS_HOME/plugins/iceberg/`:

```bash
wget -P ${FLUSS_HOME}/plugins/iceberg/ \
https://repo1.maven.org/maven2/io/trino/hadoop/hadoop-apache/3.3.5-2/hadoop-apache-3.3.5-2.jar
```

See [Iceberg - Hadoop Dependencies](/docs/next/streaming-lakehouse/datalake-formats/iceberg/#1-hadoop-dependencies-configuration) for alternative approaches.

### Start Tiering Service

Follow the [Iceberg tiering service setup](/docs/next/streaming-lakehouse/datalake-formats/iceberg/#start-tiering-service-to-iceberg) to prepare the required JARs and start the tiering service. Use REST catalog parameters with credential vending when launching the Flink tiering job:

```bash
${FLINK_HOME}/bin/flink run /path/to/fluss-flink-tiering-*.jar \
--fluss.bootstrap.servers <coordinator-host>:9123 \
--datalake.format iceberg \
--datalake.iceberg.type rest \
--datalake.iceberg.uri http://<gravitino-host>:9001/iceberg/ \
--datalake.iceberg.warehouse fluss_iceberg_catalog \
--datalake.iceberg.header.X-Iceberg-Access-Delegation vended-credentials \
--datalake.iceberg.s3.endpoint http://<s3-endpoint>:9000 \
--datalake.iceberg.s3.path-style-access true
```

> **NOTE**: Credential vending secures the Fluss-to-Iceberg communication but doesn't affect Flink-to-S3 reads. Flink requires AWS SDK credentials for direct S3 access.

## Metalake Configuration

The metalake is **not** specified in Fluss configuration. Instead, it's configured on the Gravitino server side in `gravitino.conf`:

```properties
gravitino.iceberg-rest.catalog-config-provider = dynamic-config-provider
gravitino.iceberg-rest.gravitino-uri = http://localhost:8090

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc correctly uses :8090 for the Gravitino server API (where the metalake and catalog are created) and :9001 for the Iceberg REST service (which Fluss connects to). It also correctly relies on the metalake being configured server-side in gravitino.conf rather than in Fluss.

That said, the flow isn't immediately obvious because these details are introduced in different places. It would help to add a brief sentence up front, for example:

"You create the catalog through the Gravitino server API on :8090. Fluss then communicates only with the Iceberg REST service on :9001, which resolves the catalog using the metalake configured in gravitino.conf."

A small clarification like this would make the overall request flow much easier to follow before readers get into the configuration examples.

gravitino.iceberg-rest.gravitino-metalake = {metalake name}
```

When Fluss requests a catalog by name (e.g., `fluss_iceberg_catalog`), Gravitino's REST service automatically looks it up in the configured metalake (`{metalake name}`). This allows centralized management without requiring clients to know about metalakes.

## Usage Example

### Create a Datalake-Enabled Table

```sql
USE CATALOG fluss_catalog;

CREATE TABLE orders (
`order_id` BIGINT,
`customer_id` INT NOT NULL,
`total_price` DECIMAL(15, 2),
`order_date` DATE,
`status` STRING,
PRIMARY KEY (`order_id`) NOT ENFORCED
) WITH (
'table.datalake.enabled' = 'true',
'table.datalake.freshness' = '30s'
);
```

Once the tiering service is running, Fluss automatically creates the corresponding Iceberg table in Gravitino and begins tiering data.

### Query Data

```sql
SET 'execution.runtime-mode' = 'batch';

-- Union read: combines fresh data in Fluss with historical data in Iceberg
SELECT COUNT(*) FROM orders;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add example of how we can assure data is tiered to lake, by only querying the data from lake?

```

For details on union reads, streaming reads, and reading with other engines, see [Iceberg - Read Tables](/docs/next/streaming-lakehouse/datalake-formats/iceberg/#read-tables).

## Further Reading

- [Iceberg Integration](/docs/next/streaming-lakehouse/datalake-formats/iceberg/) - Table mapping, data types, supported catalog types, and limitations
- [Lakehouse Storage](/docs/next/maintenance/tiered-storage/lakehouse-storage/) - General tiered storage setup
- [Gravitino Documentation](https://gravitino.apache.org/docs/latest/) - Deploying and managing Gravitino
- [Gravitino Iceberg REST Service](https://gravitino.apache.org/docs/latest/iceberg-rest-service/) - REST catalog configuration reference