Overview
Apache Polaris is an Apache Iceberg REST catalog — the service that tells a query engine which tables exist, where their metadata lives in object storage, and who may read them. It is the piece that turns a bucket of Parquet files into a lakehouse. This template completes a stack the catalog already has the other two thirds of: seaweedfs (or any S3-compatible bucket) stores the data, Polaris is the catalog, and trino runs the queries — all wired over internal GVC DNS, with no data leaving your organization. That exact path was verified end to end: Trino created schemas and tables through Polaris, inserted and read rows back, and the resulting Parquet data files and Iceberg metadata were confirmed in the SeaweedFS bucket from SeaweedFS’s own side. See Building a Lakehouse. Polaris itself is stateless. Every catalog, namespace, table pointer, principal and grant lives in a PostgreSQL metastore that the template deploys for you, so areplicas knob scales the catalog horizontally with no coordination to configure.
Architecture
- Polaris server — A
standardworkload serving the Iceberg REST API and the Polaris management API on port8181, and Quarkus health and metrics on port8182. Stateless, with areplicasknob. - Bootstrap workload — Runs the official
polaris-admin-toolimage once to create the realm schema and the root principal, then idles. Always one replica, and idempotent — a restart or upgrade re-runs it harmlessly. - Metastore — A single-instance postgres by default, or postgres-highly-available with one flag.
- Realm — Polaris isolates tenants by realm. This template ships exactly one and does not require the
Polaris-Realmheader, which is what makes Trino’s Iceberg REST connector work against it.
What Gets Created
- Standard Polaris Workload —
replicasinterchangeable replicas serving8181and8182. - Standard Bootstrap Workload — One replica, no ports, unreachable from anywhere. It initializes the realm and then sleeps.
- Bootstrap Script Secret — An opaque secret holding the shell script the bootstrap workload runs, mounted as a file.
- Two Identities & Two Policies — Split for least privilege: only the bootstrap principal can reveal your root credentials, and only the server principal can reveal the token signing key and the object-storage credentials.
- PostgreSQL Metastore — The
postgresorpostgres-highly-availablesubchart, with its own workload, volume set and config secret. - No Volume Set for Polaris — The server writes nothing to local disk that must survive a restart.
This template does not create a GVC. You must deploy it into an existing GVC.
Prerequisites
Two Control Plane secrets must exist before you install. They are referenced by name, never passed through values, and the deployment waits indefinitely on a secret that does not exist — an install that looks stuck is almost always a missing one of these.1
Create the root credentials secret
A dictionary secret with
CLIENT_ID and CLIENT_SECRET. These become the realm’s root principal at bootstrap, and are what Trino, Spark and any other Iceberg REST client authenticate with. Neither value may contain a comma.2
Create the token signing key secret
An opaque secret whose payload is a random string of 32 or more characters. Every replica signs and validates access tokens with it, so tokens survive restarts and are accepted across replicas.
helm uninstall leaves them in place.
Optional:
- Object-storage credentials for the bucket holding your Iceberg data — a dictionary secret with
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY. See Object Storage. Polaris runs without it; catalogs can be added later. - A cloud account and bucket only if you turn on the metastore’s backup pass-through. See Backing Up.
Installation
Install the template using your preferred method:UI
Browse, install, and manage templates visually
CLI
Manage templates from your terminal
Terraform
Declare templates in your Terraform configurations
Pulumi
Declare templates in your Pulumi programs
Configuration
The defaultvalues.yaml for this template:
Server and Replicas
image— The official upstream image. The chart is shipped and tested on Polaris 1.7.0.replicas— Number of Polaris replicas (default1, minimum1). Replicas are interchangeable: they share the metastore and the token signing key, so a token minted by one is accepted by every other and a catalog created through one is immediately visible on the rest. Raise it for capacity and to keep serving through a rolling restart — see Availability.resources.minCpu/maxCpu/minMemory/maxMemory— CPU and memory per replica.minMemorymay not exceedmaxMemory, andmaxCpu:minCpumay not exceed 4:1 (a Control Plane limit); the chart refuses to render otherwise, naming the value to fix.
JVM and Memory
jvm.maxRAMPercentage (default 70, allowed range 40–80) sets the JVM heap as a percentage of resources.maxMemory, so maxMemory is normally the only number you change. Capacity AI is disabled on both workloads: the JVM sizes its heap from the container limit at startup, so shrinking the container afterwards would be an out-of-memory kill with no diagnostic.
Realm
realm (default POLARIS) is the tenant namespace the bootstrap workload creates. This template ships exactly one realm and does not require the Polaris-Realm header — a header-less request resolves to this realm, which is what Trino’s Iceberg REST connector needs, since it cannot send an arbitrary header. Requests naming a different realm are rejected with 404.
Credentials
rootCredentials.secretName— Name of the prerequisite dictionary secret holdingCLIENT_IDandCLIENT_SECRET. Required.tokenSigningKey.secretName— Name of the prerequisite opaque secret whose payload is the shared HMAC signing key. Required.
replicas is above 1: Polaris’s own default generates a key per JVM process, so even a single replica would hand out tokens that its own restart rejects with 401.
Object Storage
storage.credentialsSecretName— Name of a dictionary secret withAWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY, used for Polaris’s own Iceberg metadata reads and writes. Empty by default, which is a valid install: the server runs and answers, but catalogs backed by object storage cannot read or write.storage.region— Value ofAWS_REGION. S3-compatible servers ignore it, but the AWS SDK requires one.
s3.credentialsSecretName for SeaweedFS) — there is nothing else to create. For AWS S3, create an access key scoped to the bucket:
Bootstrap
bootstrap.image is the official admin tool image; keep its tag in lockstep with image. bootstrap.resources sizes the one-shot container.
The bootstrap workload runs the admin tool against the metastore, creates the realm schema and the root principal, and then idles — it exits nothing and serves nothing, so it stays ready after its work is done. The operation is idempotent: on any restart or upgrade it logs Realm 'POLARIS' is already bootstrapped; skipping and idles again. Nothing calls it, and its internal firewall is set to none.
Access
publicAccess.enabled—falseby default. Whentrue, the Iceberg REST API and the Polaris management API are served over HTTPS on the automatically assigned*.cpln.appcanonical endpoint.internalAccess.type— Which workloads inside Control Plane may reach Polaris:
Port
8182 is never published on the public endpoint. The canonical endpoint routes to the workload’s first declared container port, which is 8181. Polaris serves the unauthenticated Quarkus health, metrics and info endpoints only on 8182, so with public access on, /q/metrics, /q/health and /q/info all return 404 from the internet while :8182/q/metrics answers normally inside the GVC. Firewall changes take up to a couple of minutes to propagate.Metastore
Exactly one ofpostgres (default) and postgresHA must be enabled — the chart enforces this at render and fails with a message naming the fix.
Switch by setting
postgres.enabled: false and postgresHA.enabled: true. Polaris is wired to whichever is active automatically — the single instance directly, or the HAProxy leader endpoint in HA mode. Change the database password before installing in either mode (postgres.config.password or postgresHA.postgres.password); the default is an obvious placeholder.
Each Polaris replica opens up to 20 JDBC connections, plus the bootstrap workload — about 21 of PostgreSQL’s default 100 at replicas: 1, and about 61 at replicas: 3.
Building a Lakehouse
Storage, catalog, and engine are three separate templates. This is the whole path, verified end to end.1
2
Deploy Polaris against that bucket
Set
storage.credentialsSecretName to that same secret, and create the two prerequisite secrets from Prerequisites first.3
Get an access token
Every API call needs a bearer token, obtained with the root credentials:
4
Create a catalog
Catalogs are a day-2 API call, not an install-time value:
pathStyleAccess: true and stsUnavailable: true are what an S3-compatible server needs. Drop endpoint, endpointInternal and pathStyleAccess for AWS S3 itself.5
Point Trino at it
Add this catalog to the trino template’s values. Trino authenticates to Polaris with the root credentials and talks to the bucket with its own S3 keys — credential vending is off, so both sides hold static credentials:
6
Query it
CREATE SCHEMA, CREATE TABLE, INSERT and SELECT now work against tables stored in the bucket:Connecting
Same-GVC clients use plain
http:// over the mesh’s mTLS; external clients use https:// with TLS terminated at the platform edge. A request with no bearer token, or a wrong client secret, is rejected with 401.
Availability
Polaris is stateless and every replica shares both the metastore and the token signing key, soreplicas is a real availability knob. Measured at replicas: 2 with an authenticated request every 0.5 s from another workload, through the service DNS name:
Catalog state survived both events. At the default
replicas: 1 a rolling upgrade replaces the only replica, so requests fail for the duration of the restart; raise replicas to keep serving through one.
The metastore is the other half of the picture: with the default single-instance postgres, a database restart takes Polaris down with it for as long as PostgreSQL takes to come back. postgresHA removes that with Patroni failover, at the cost of a larger footprint and a slower first install.
Backing Up
Metastore backups are off by default and need no cloud account. Turn them on withpostgres.backup.enabled: true (or postgresHA.backup.enabled: true) and configure a provider — the backup runs inside the PostgreSQL subchart, so this is that template’s mechanism, passed straight through.
- AWS S3
- GCP Cloud Storage
- MinIO / S3-compatible
Create the bucket, a Control Plane cloud account, and an IAM policy scoped to the bucket:Then set
provider: aws and the aws.bucket, aws.region, aws.cloudAccountName and aws.policyName values.postgresHA.backup.mode selects logical (scheduled pg_dump) or wal-g (continuous WAL archiving).
Important Notes
- Create both prerequisite secrets before installing. Without them the workloads wait on a secret that does not exist, and the install looks broken with no useful error.
- Expect a warm-up and do not interrupt it. A default install is ready in about 90 seconds, including a 2-restart, ~32-second crash loop while PostgreSQL boots. The
postgresHAmetastore takes about 6 minutes before Polaris answers. Both are normal. - Root credentials are write-once; they are applied only at first bootstrap. Rotate by creating a new principal through the management API.
- Rotating the token signing key invalidates every outstanding token — clients must request a new one.
realmis permanent. Renaming it bootstraps a new, empty realm and hides the existing catalogs.- Change the metastore password before installing (
postgres.config.passwordorpostgresHA.postgres.password) — the default is a placeholder. - No credential vending in this version. Polaris and each query engine hold their own static object-storage credentials; keep
iceberg.rest-catalog.vended-credentials-enabled=falsein Trino. - Health and metrics are in-GVC only. They are served on port
8182, which the public canonical endpoint does not route to. - Polaris does not migrate its own database schema. Treat a future Polaris version bump as an explicit schema step, not something startup handles.
- Metastore volumes survive restarts, redeploys and upgrades; uninstalling deletes them — and every catalog definition with them. The Iceberg data in your bucket is untouched, but the catalog that indexed it is gone. Use
postgresHAand/or backups for anything you care about. - Uninstall does not delete your prerequisite secrets — they are your resources, created outside the release.
External References
Apache Polaris Documentation
Official documentation for the shipped release
Configuration Reference
Every server setting and its environment-variable name
Relational JDBC Metastore
The PostgreSQL persistence backend this template uses
Admin Tool
The bootstrap tool the init workload runs
Creating a Catalog on S3
Storage configuration for S3 and S3-compatible servers
Access Control
Principals, roles, and grants beyond the root principal
Trino Iceberg REST Catalog
The connector properties used to point Trino at Polaris
Polaris Template
View the source files, default values, and chart definition