Apache Polarisは、Apache Icebergテーブルの「どこにあるか」と「誰が触ってよいか」を1か所で管理するオープンソースのRESTカタログです。2026年2月にApacheソフトウェア財団のトップレベルプロジェクトへ昇格し、最新版は2026年9月28日公開の1.8.0です。この記事では、1.8.0の公式Dockerイメージを実際に起動して確かめた応答をもとに、Polarisの役割、Docker Composeでの起動、SparkとTrinoからの接続、RBACの権限粒度、credential vending(一時資格情報の払い出し)、PostgreSQLでの本番構成を解説します。
まとめ:Apache Polaris 1.8.0の要点
- PolarisはIceberg REST仕様を実装したカタログサーバーで、テーブルの所在(メタデータの位置)と権限を持ちます。データファイルそのものは持ちません。
- 最新は1.8.0(2026年9月28日公開)です。1.4.0以降は版名から
incubatingが外れています。 - 評価用ならDocker Composeの1行で起動し、カタログとプリンシパルまで自動で作られます。ただしメタストアはインメモリで、停止すると消えます。
- 認可はプリンシパル、プリンシパルロール、カタログロール、権限の4層です。データ本体の読み書き権限はメタデータ管理権限と分かれています。
- 1.8.0からPostgreSQLへのbootstrapは、先に
CREATE SCHEMAが必要です。1.7.0の手順のままだと空のDBで失敗します。 - Web UIはサーバー本体に同梱されず、別リポジトリのPolaris Consoleを立てる構成です。
Icebergテーブルの所在と権限を担うRESTカタログ
Icebergが決める範囲とPolarisが決める範囲
Icebergはテーブルフォーマットの仕様で、スキーマ、パーティション、スナップショットの表現方法を定めます。「そのテーブルの現在のメタデータファイルはどれか」を指し示すのはカタログの役割です。Apache IcebergにもHiveCatalogやRESTCatalogなどのカタログ実装(クライアント側)は含まれますが、Polarisはその接続先となる独立したRESTカタログサーバーで、Iceberg REST仕様を実装しています。ファイル形式との層の違いはApache IcebergとParquetの違い|テーブル形式とファイル形式の関係を整理で整理しています。
Polarisが独自に足しているのは認可です。Hive MetastoreやAWS Glueをカタログに使う構成では、権限をエンジン側やストレージ側のIAMで別に組む必要がありました。Polarisはカタログ自身がRBACを持ち、認可の結果として一時的なストレージ資格情報をクライアントへ払い出します。権限をストレージ側に寄せる代表例はAWS Lake Formationとは?データレイクの権限管理・使い方・料金と実装判断を解説【2026年版】です。
カタログには2種類あります。1.8.0の公式ドキュメントの定義では、Internalカタログは読み書きともPolarisが管理し、Externalカタログは別のカタログが管理するテーブルをPolaris側に同期して読み取り専用で見せます。同じページはExternalの例にSnowflake、Glue、Dremio Arcticを挙げていますが、これは概念の説明です。同じドキュメントが個別の導入ガイドを用意しているのはIceberg REST、Hive Metastore、BigQuery Metastoreの3系統で(管理APIの仕様には接続型としてHADOOPも定義されています)、使える条件は後述の判断基準の章にまとめました。
Snowflake Open Catalogとの関係
Snowflake Open Catalogは、SnowflakeのドキュメントにSnowflake Open Catalog is a managed service for Apache Polaris™.とあるとおり、Polarisのマネージドサービスです。違いはサーバーを自分で運用するかSnowflakeに預けるかで、クライアントから見えるプロトコルはどちらもIceberg RESTです。
ただし新規に選べる選択肢ではありません。同じページにCustomers who haven’t previously created a Snowflake Open Catalog account can’t sign up for their first Open Catalog account.とあり、新規顧客の案内先はSnowflake Horizon Catalogとは?機能と設定SQLを解説で扱うHorizon Catalogです。既存アカウントが無い組織がマネージドを検討するなら、比較対象はOpen CatalogではなくHorizon Catalogになります。Databricks側の同種レイヤーとの比較軸はUnity Catalogとは?3レベル名前空間と権限継承・移行判断を実装視点で解説【2026年版】で扱っています。
トップレベルプロジェクト昇格から1.8.0までのリリース推移
Polarisは2024年7月にSnowflakeがオープンソースとして公開し、その後Apacheのインキュベーターに入りました。卒業日と告知の公開日は別で、ASFインキュベーターのステータスページは2026-02-15 Graduation as TLP.、プロジェクトの告知ブログは2026年2月19日付です。実務上は2026年2月の卒業と押さえれば足ります。版名の-incubating接尾辞を見れば、参照している解説がどの時点の情報かを判別できます。日付は公式ダウンロードページの記載です。
| 版 | 公開日 | 版名の接尾辞 |
|---|---|---|
| 0.9.0 | 2025-03-11 | incubating |
| 1.0.0 | 2025-07-09 | incubating |
| 1.0.1 | 2025-08-16 | incubating |
| 1.1.0 | 2025-09-19 | incubating |
| 1.2.0 | 2025-10-23 | incubating |
| 1.3.0 | 2026-01-16 | incubating |
| 1.4.0 | 2026-04-21 | なし(TLP昇格後) |
| 1.4.1 | 2026-05-01 | なし |
| 1.5.0 | 2026-05-18 | なし |
| 1.6.0 | 2026-07-08 | なし |
| 1.7.0 | 2026-08-02 | なし |
| 1.8.0 | 2026-09-28 | なし |
1.8.0の破壊的変更と運用への影響
1.8.0のCHANGELOGがBreaking changesに挙げる項目のうち、運用者が手を動かす必要があるのは次の4つです。
- JDBCのbootstrapがスキーマを作らなくなった:新規環境では
CREATE SCHEMA polaris_schema;を先に実行します(実測は本番構成の章)。JDBC URLにcurrentSchemaを書いている既存環境は、Polarisが別スキーマを見に行かないか確認してから上げます。 - 同時コミットの競合が
409になった:古いシーケンス番号でのコミットは、これまでの致命的な400ではなく再試行できる409を返します。 - OPAへの問い合わせがintent単位に分かれた:複数のintentを1回で評価していたRegoポリシーは書き直しが要る場合があります。
- ローリングアップグレード中のトークン交換:
polaris-cvクレームを持たない旧トークンはtoken exchangeに使えず、旧ノードが残っている間はinvalid_grantが断続的に出ます。
このほか、既定設定のままではビューの削除がHTTP 403で失敗していた不具合が直りました。1.8.0を起動すると、/config応答のエンドポイント一覧にPOST /api/openlineage/v1/lineageが並びます。ただしCHANGELOG上はno-op(受け取るだけ)の取り込み口なので、リネージ収集の機能として当てにする段階ではありません。
Docker Composeでの起動とトークン取得の手順
評価目的なら、公式のQuickstartがdocker-compose.ymlを標準入力へ流し込む1行で完結します。PolarisとS3互換ストレージのRustFSが起動し、quickstart_catalogというカタログとquickstart_userというプリンシパルが自動で作られます。
curl -s https://raw.githubusercontent.com/apache/polaris/refs/heads/main/site/content/guides/quickstart/docker-compose.yml | docker compose -p polaris-quickstart -f - up -d
# 自動生成された資格情報とサンプルコマンドはセットアップ用コンテナのログに出る
docker compose -p polaris-quickstart logs polaris-setup
# 停止
docker compose -p polaris-quickstart down
compose内のイメージ指定はapache/polaris:latestなので、2026年10月18日時点では1.8.0が起動します。版を固定したい場合はcomposeファイルを保存してapache/polaris:1.8.0に書き換えてください。
起動後に使えるAPIと資格情報
1.8.0のQuickstartを起動すると、セットアップ用コンテナのログに次の情報が出ます。
| 用途 | URL・値 |
|---|---|
| Iceberg REST API | http://localhost:8181/api/catalog/v1 |
| 管理API | http://localhost:8181/api/management/v1 |
| Generic Tables API | http://localhost:8181/api/polaris/v1 |
| ヘルスチェック | http://localhost:8182/q/health |
| メトリクス | http://localhost:8182/q/metrics |
| RustFSのコンソール | http://localhost:9001 |
| rootの資格情報 | root / s3cr3t(固定値) |
| quickstart_userの資格情報 | 起動ごとにランダム生成 |
2つのプリンシパルは権限がまったく違います。quickstart_userに付くのはカタログロール経由のCATALOG_MANAGE_CONTENT1件だけで、名前空間やテーブルの作成・削除はできますが、管理APIは使えません。実際にquickstart_userのトークンでカタログ一覧を取ると、HTTP 403とis not authorized for op LIST_CATALOGSが返りました。カタログやプリンシパルを作る操作はrootで行います。
APIを直接叩くときは、OAuth2のclient credentialsフローでアクセストークンを取ります。
curl -X POST http://localhost:8181/api/catalog/v1/oauth/tokens \
-H "Polaris-Realm: POLARIS" \
-d "grant_type=client_credentials" \
-d "client_id=root" \
-d "client_secret=s3cr3t" \
-d "scope=PRINCIPAL_ROLE:ALL"
{"access_token":"...","token_type":"bearer","issued_token_type":"urn:ietf:params:oauth:token-type:access_token","expires_in":3600}
realmヘッダーは、Quickstartの既定(require-header=false)では省略しても通ります。実測では、ヘッダー無しのリクエストは既定realmのPOLARISとして200を返し、存在しないrealm名を送ると404とMissing or invalid realmが返りました。realmが1つだけの評価環境なら省略して構いません。
トークンエンドポイントの非推奨と外部IdPへの移行
このトークンエンドポイントを恒久的な認証基盤にしてはいけません。1.8.0のAPI仕様(oauth-tokens-api.yaml)はGet a token using an OAuth2 flow (DEPRECATED for REMOVAL)と題してdeprecated: trueを明示し、Iceberg(Java)2.0で仕様から削除すると書いています。
移行先は外部のOIDCプロバイダーです。外部IdPのドキュメントによると、認証方式はinternal(既定)、external、mixedの3つで、realmごとに切り替えられます。externalにすると内部のトークンエンドポイントはHTTP 501を返すようになり、mixedは内部認証を試してから失敗時にOIDCへ回します。既存クライアントを止めずに移すならmixedで並走させ、クライアント側にoauth2-server-uriを明示してからexternalへ切り替える順になります。公式にはKeycloakを使う手順があり、Keycloak自体の構成はKeycloakとは?Oktaとの違いと連携手順|Auth0・Cognito比較で導入を判断【2026年10月】で扱っています。
Python CLIでの管理操作
管理操作をコマンドラインで行うなら、PyPIのapache-polarisが使えます。1.8.0は2026年9月28日に公開され、対応Pythonは3.10以上3.15未満です(macOS標準の3.9では入りません)。Quickstartに対してrootで実行すると、カタログの設定がJSONで返りました。
pip install apache-polaris==1.8.0
polaris --client-id root --client-secret s3cr3t catalogs list
polaris --client-id root --client-secret s3cr3t principals list
quickstart_userの資格情報で同じコマンドを実行すると、前述の403がForbiddenExceptionとして表示されます。
SparkとTrinoからの接続設定
Sparkのtype=restとcatalog-implの使い分け
Icebergのクライアント設定では、カタログの実装をtypeとcatalog-implのどちらで指定するかで迷いがちです。Iceberg公式のSpark設定リファレンスはcatalog-implをThe custom Iceberg catalog implementation. If type is null, catalog-impl must not be null.と定義しています。typeにrestを指定するならcatalog-implは不要で、Quickstartが出力するSparkの起動例もtype=restです。
from pyspark.sql import SparkSession
spark = (SparkSession.builder
.config("spark.jars.packages",
"org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.10.1,org.apache.iceberg:iceberg-aws-bundle:1.10.1")
.config("spark.sql.extensions", "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions")
.config("spark.sql.catalog.polaris", "org.apache.iceberg.spark.SparkCatalog")
.config("spark.sql.catalog.polaris.type", "rest")
.config("spark.sql.catalog.polaris.uri", "http://localhost:8181/api/catalog")
.config("spark.sql.catalog.polaris.warehouse", "quickstart_catalog")
.config("spark.sql.catalog.polaris.credential", "<client-id>:<client-secret>")
.config("spark.sql.catalog.polaris.scope", "PRINCIPAL_ROLE:ALL")
.config("spark.redaction.regex", "(?i)secret|password|token|access[.]?key|credential")
.config("spark.sql.catalog.polaris.header.X-Iceberg-Access-Delegation", "vended-credentials")
.config("spark.sql.defaultCatalog", "polaris")
).getOrCreate()
Icebergの版は、1.8.0のQuickstartが出力する起動例(Spark 3.5、Iceberg 1.10.1)に合わせています。Iceberg本体は2026年9月29日に1.12.0が出ており、Spark 4.0/4.1向けのランタイム(Scala 2.13)もあるので、実運用ではSparkの版との対応表を見て上げてください。warehouseにはPolaris側のカタログ名を渡します。header.X-Iceberg-Access-Delegationにvended-credentialsを指定すると、ストレージのアクセスキーをSpark側に置かずに済みます。
Polaris Spark Clientの守備範囲と制限
Polarisは上記のIceberg標準クライアントとは別に、独自のSparkクライアント(org.apache.polaris.spark.SparkCatalog)も配布しています。Iceberg以外のテーブルをGeneric Tablesとして扱うためのもので、Icebergテーブルしか使わないなら不要で、Deltaも同じカタログに載せたいときだけ検討します。1.8.0のドキュメントが挙げる制限は次のとおりです。
- 対応形式はIcebergとDeltaのみで、CSVやJSONは対象外。
- Generic Tables APIはcredential vendingに未対応。
- Deltaテーブルに対してCTASが使えず、これに依存する
saveAsTableも使えない。 - Deltaテーブルは明示的なlocationなしでは作成できず、リネームと
ALTER TABLE ... SET LOCATIONも非対応。
フォーマット側の性質はDelta Lakeとは?データレイクに信頼性を与えるオープンテーブルフォーマットを実装視点で解説を参照してください。
Trinoのカタログプロパティ
Trinoからは、Icebergコネクタのカタログ定義ファイルでPolarisをRESTカタログとして指定します。公式のTrinoガイドが使う定義ファイル(1.8.0タグのpolaris.properties)の中身は次のとおりです。
| プロパティ | 値の例 |
|---|---|
| connector.name | iceberg |
| iceberg.catalog.type | rest |
| iceberg.rest-catalog.uri | http://polaris:8181/api/catalog |
| iceberg.rest-catalog.warehouse | quickstart_catalog |
| iceberg.rest-catalog.security | OAUTH2 |
| iceberg.rest-catalog.oauth2.credential | ${ENV:CLIENT_ID}:${ENV:CLIENT_SECRET} |
| iceberg.rest-catalog.oauth2.scope | PRINCIPAL_ROLE:ALL |
| iceberg.rest-catalog.http-headers | Polaris-Realm: POLARIS |
| iceberg.rest-catalog.vended-credentials-enabled | true |
| fs.s3.enabled | true |
| s3.endpoint | http://rustfs:9000 |
| s3.path-style-access | true |
| s3.region | us-west-2 |
security=OAUTH2を指定する場合は、oauth2.credentialまたはoauth2.tokenのいずれかが必要です。この例では前者を使います。http-headersでrealmヘッダーを送っている点も要注意です。本番推奨のpolaris.realm-context.require-header=trueを入れた環境では、このヘッダーが無いリクエストをPolarisが拒否します。s3.endpointとs3.path-style-accessはRustFSやMinIOのようなS3互換ストレージ向けの値で、AWSのS3なら不要です。Trino自体の役割はTrinoとは?分散SQLクエリエンジンの仕組みとPresto・Sparkとの違い【Trino 484対応】にまとめています。
RBACの4層モデルと権限の粒度
Polarisの認可は、権限を直接ユーザーへ与えない設計です。権限はカタログロールに付与し、カタログロールをプリンシパルロールへ、プリンシパルロールをプリンシパルへ付与します。プリンシパルとプリンシパルロール、プリンシパルロールとカタログロールはいずれも多対多です。カタログロールは特定のカタログに属するため、カタログをまたぐ権限は「カタログごとのカタログロール」を1つのプリンシパルロールに束ねて表現します。Quickstartが作るquickstart_user→quickstart_user_role→quickstart_catalog_role→CATALOG_MANAGE_CONTENTの連鎖が、この4層の最小構成です。
保護対象(securable object)はカタログ、名前空間、Icebergテーブル、ビュー、ポリシーで、権限はそれぞれの系統で定義されています。主要なものは次のとおりです。
| 権限 | 意味 |
|---|---|
| TABLE_READ_DATA | 読み取り専用の一時資格情報を受け取る |
| TABLE_WRITE_DATA | 読み書き可能な一時資格情報を受け取る |
| TABLE_FULL_METADATA | 上記2つを除くテーブル権限の一括付与 |
| NAMESPACE_FULL_METADATA | 名前空間権限の一括付与 |
| CATALOG_MANAGE_CONTENT | メタデータ管理とデータ読み書きを含む包括権限 |
| CATALOG_MANAGE_ACCESS | 権限とロールの付与・剥奪 |
| POLICY_ATTACH / POLICY_DETACH | ポリシーの付け外し |
設計上の要点は、データ本体への到達権であるTABLE_READ_DATAとTABLE_WRITE_DATAがTABLE_FULL_METADATAに含まれないことです。メタデータの完全管理権を渡してもデータは読めないので、「テーブル定義は触れるがデータは見せない」役割を素直に表現できます。逆にCATALOG_MANAGE_CONTENTはこの2つを内包するカタログ管理者向けの強い権限で、Quickstartのquickstart_userがテーブルを削除できるのもこのためです。1.8.0ではセマンティックモデル(OSI)の一覧・作成・参照・更新・削除にも専用の権限が加わりました。
テーブルプロパティの扱いにも注意が要ります。TABLE_READ_PROPERTIESやVIEW_READ_PROPERTIESを持つプリンシパルはプロパティを読めるため、パスワードやアクセスキーをテーブルプロパティに置いてはいけません。カタログプロパティもIceberg RESTの/config応答としてクライアントに返るので、機密を置く場所ではありません。
credential vendingで払い出される資格情報の中身
クライアントがX-Iceberg-Access-Delegation: vended-credentialsを付けてテーブルを作成・ロードすると、Polarisは呼び出し元が認可された範囲だけにスコープした短命の資格情報を返します。S3ならAWS STSのAssumeRoleをインラインセッションポリシー付きで実行した結果、Azureならコンテナとパス接頭辞に限定したUser Delegation SASトークン、GCSならCredential Access Boundaryで権限を絞ったアクセストークンです。
Polaris 1.8.0のテーブル作成応答と資格情報
1.8.0のQuickstart(ストレージはRustFS)で、quickstart_userのトークンとこのヘッダーを付けてテーブルを作成したところ、応答のconfigには次のキーが入っていました(値は伏せています)。
client.refresh-credentials-endpoint = v1/quickstart_catalog/namespaces/demo/tables/t1/credentials
client.region = us-west-2
s3.access-key-id = ...
s3.secret-access-key = ...
s3.session-token = ...
s3.session-token-expires-at-ms = ...
s3.endpoint = http://localhost:9000
s3.path-style-access = true
storage-credentials[0].prefix = s3://bucket123/demo/t1
読み取れることは3つです。1つ目に、storage-credentialsのprefixはバケット全体ではなく、そのテーブルのパス(s3://bucket123/demo/t1)でした。2つ目に、有効期限は発行からちょうど1時間で、これは設定リファレンスのSTORAGE_CREDENTIAL_DURATION_SECONDSの既定値3600と一致します(同じ説明に、GCSはこの値を尊重しないとあります)。3つ目に、ヘッダーを付けずに同じテーブルをロードすると、返るのはclient.region、s3.endpoint、s3.path-style-accessだけで、資格情報は含まれません。長時間のジョブはclient.refresh-credentials-endpointで期限前に取り直す前提で組みます。
なお、ヘッダーにremote-signingを指定すると、1.8.0ではThis catalog cannot vend credentials or sign requests; request without X-Iceberg-Access-Delegation and configure storage credentials on the clientというHTTP 400が返ります。リモート署名はPolarisに実装されていないので、選択肢はvended-credentialsか、クライアント側にストレージ資格情報を置くかの2つです。
ストレージ別のプロパティ名
Vended Credentialsのリファレンスに載っているキー名は次のとおりです。
| ストレージ | 主なプロパティ名 | 備考 |
|---|---|---|
| S3 | s3.access-key-id / s3.secret-access-key / s3.session-token | client.regionも同時に返る |
| Azure ADLS | adls.sas-token.<account-host> | Iceberg 1.8以降のSpark向け |
| Azure ADLS | adls.sas-token.<account-name> | Iceberg 1.7.x向け |
| Azure ADLS | adls.sas-token / adls.account-name | PyIceberg(adlfs)向け |
| GCS | gcs.oauth2.token | サービスアカウント借用に対応 |
Azureのキー名が3系統あるのは、クライアントのIceberg SDKの世代によって期待するキーが違うためです。Polarisは全形式を同時に返すので、クライアントごとにサーバー設定を切り替える必要はありません。AzureのUser Delegation SASは有効期間の上限が7日と決まっています。MinIOのようなS3互換ストレージで組む前提はMinIOとは?S3互換オブジェクトストレージの仕組みとOSS版アーカイブ後の採用判断【2026年8月時点】にまとめています。
本番構成で既定値から変更する点
本番構成のドキュメントは既定構成を開発・テスト向けと明言し、OAuth2鍵の設定、realmヘッダーの必須化、耐久性のあるメタストア(JDBC+PostgreSQL)、realmのbootstrap、FILEストレージの無効化をチェックリストに挙げています。
RSA鍵の固定とrealmヘッダーの必須化
既定のrsa-key-pairは起動のたびにランダム生成されるため、レプリカを複数立てるとノードごとに鍵が変わり、トークンを発行したノードと別のノードに振られた時点で検証に失敗します。事前に作った鍵をファイルで渡してください。
openssl genpkey -algorithm RSA -out private.key -pkeyopt rsa_keygen_bits:2048
openssl rsa -in private.key -pubout -out public.key
polaris.authentication.token-broker.type=rsa-key-pair
polaris.authentication.token-broker.rsa-key-pair.public-key-file=/tmp/public.key
polaris.authentication.token-broker.rsa-key-pair.private-key-file=/tmp/private.key
polaris.realm-context.require-header=true
FILEストレージについては、チェックリストの説明(「既定でFILEを使える」)と1.8.0の実際の挙動が食い違っています。既定の設定ファイルはSUPPORTED_CATALOG_STORAGE_TYPESを["S3","GCS","AZURE"]としており、1.8.0の公式イメージでFILE型のカタログを作るとUnsupported storage type: FILEのHTTP 400で拒否されました。この既定値は1.0.0から変わっていません。本番で確認すべきなのは、検証のためにFILEを足した設定ファイルや環境変数をそのまま本番へ持ち込んでいないかどうかです。
PostgreSQLへのbootstrap(1.8.0で手順が変わった点)
永続化のバックエンドで本番に使える段階なのはRelational JDBC(relational-jdbc)で、メタストアのドキュメントが本番向けに推奨するのはPostgreSQLです(CHANGELOGにはCockroachDB向けのスキーマ修正も載っています)。MongoDBを使うnosqlはExperimental扱いです。既定のインメモリでは再起動でデータが消え、複数レプリカも成立しません。バックエンドを設定したうえで、realmごとに1回、管理ツールでbootstrapを実行します。
1.8.0からは、その前にスキーマの作成が必要です。管理ツールのドキュメントはPolaris does not create the database schema.と書き、スキーマ作成をDB管理者の作業と位置づけています。空のPostgreSQL 18に対して管理ツールの1.7.0と1.8.0を実行して比べた結果は次のとおりです。
| 条件 | 結果 | スキーマ版 |
|---|---|---|
| 1.7.0・空のDB | 成功(polaris_schemaも自動作成) | 5 |
| 1.8.0・空のDB | 失敗(終了コード3) | なし |
| 1.8.0・CREATE SCHEMA後 | 成功 | 6 |
| 1.8.0・別ロールでGRANT無し | 失敗(終了コード3) | なし |
| 1.8.0・同じrealmで再実行 | already bootstrapped; skipping(終了コード0) | 6のまま |
1.8.0で空のDBへ実行したときのエラーはERROR: no schema has been selected to create inとBootstrap encountered errors during operation.です。スキーマを作ったあとでも、Polarisが使うロールにスキーマの権限が無いと同じエラーになりました。メッセージからは原因を読み取りにくいので、このエラーが出たら「スキーマが無い」と「権限が無い」の両方を疑ってください。手順は次の2段です。<user>には、後段のquarkus.datasource.usernameと同じDBロールを指定します(別ロールでもGRANT後は成功しました)。
psql -h <host> -U <admin-user> -d polaris -c "CREATE SCHEMA polaris_schema; GRANT USAGE, CREATE ON SCHEMA polaris_schema TO <user>;"
docker run --rm -it \
--env="polaris.persistence.type=relational-jdbc" \
--env="quarkus.datasource.username=<user>" \
--env="quarkus.datasource.password=<password>" \
--env="quarkus.datasource.jdbc.url=jdbc:postgresql://<host>:5432/polaris" \
apache/polaris-admin-tool:1.8.0 bootstrap -r POLARIS -c POLARIS,<client-id>,<client-secret>
イメージ名にも注意が要ります。1.8.0のGitHubリリースノートは管理ツールをapache/polaris-admin:1.8.0と書いていますが、Docker Hubに実在するのはapache/polaris-admin-toolで、apache/polaris-adminは2026年10月18日時点で存在しません。1.7.0のリリースノートから続く誤記で、コピーするとpullで失敗します。タグはドキュメントのlatestではなく、再現性のために版で固定しています。
スキーマv5からv6への手動移行
Polarisは自動マイグレーションを持ちません。1.7.0でbootstrapしたスキーマv5のDBに1.8.0のサーバーを載せたところ、起動もカタログ作成も成功し、スキーマ版は5のままでした。動くからこそ移行漏れに気づきにくい点が運用上の落とし穴です。
v5とv6の差はidx_locations索引です。実測したDBでは、v5が(realm_id, parent_id, location_without_scheme)、v6が(realm_id, catalog_id, location_without_scheme)でした。CHANGELOGによると、v5の索引は重なり判定のクエリと列が合っておらず、OPTIMIZED_SIBLING_CHECKを有効にしているとテーブルや名前空間の作成のたびにrealm全体を走査します。既存のPostgreSQL環境は次のSQLで作り直します(H2は対象外です)。
DROP INDEX polaris_schema.idx_locations;
CREATE INDEX idx_locations ON polaris_schema.entities USING btree (realm_id, catalog_id, location_without_scheme)
WHERE location_without_scheme IS NOT NULL;
CockroachDBは、これに加えてv4以降のPostgreSQLにある3つの索引(idx_grants_realm_granteeほか)を手で作る必要があります。1.7.0で入ったv5への移行SQLも手作業でした。Polarisを本番で使うなら、アップグレード手順書に「CHANGELOGのUpgrade notesを読み、移行SQLの要否を判断する」工程を毎回入れてください。ここを軽く見積もると、マネージドサービスとの運用コストの差が想定より大きく出ます。
Kubernetes(Helm)での配置
Kubernetesへ載せる場合は公式Helmリポジトリが使えます。チャートの索引には1.8.0が登録されています。
helm repo add polaris https://downloads.apache.org/polaris/helm-chart
helm repo update
helm upgrade --install polaris polaris/polaris --namespace polaris --create-namespace --version 1.8.0
Web UI(Polaris Console)と周辺ツールの現在地
「Polarisの管理画面はどこか」はよく検索される疑問ですが、サーバー本体にWeb UIは同梱されません。1.8.0のQuickstartでhttp://localhost:8181/を開くと404が返り、セットアップのログが案内するのもREST APIとRustFSのコンソールだけです。GUIが必要なら、apache/polaris-toolsリポジトリのPolaris Consoleを別途デプロイします。React、TypeScript、TanStack Query、Tailwind CSSで作られた単体のフロントエンドで、Node.js 20.19以上(または22.13以上)が前提です。ログインは内部のトークンエンドポイントのほか、VITE_OIDC_*の環境変数でOIDCにも対応しています。
VITE_POLARIS_API_URL=http://localhost:8181
VITE_POLARIS_REALM=POLARIS
VITE_POLARIS_PRINCIPAL_SCOPE=PRINCIPAL_ROLE:ALL
ConsoleはブラウザからPolarisのAPIを直接呼ぶため、サーバー側でCORSを開けないと動きません。Quarkusベースなのでapplication.propertiesか環境変数、Helmならvalues.yamlのcorsセクションで設定します。許可ヘッダーにPolaris-Realmを含め忘れると、realmヘッダー付きのリクエストがプリフライトで弾かれます。
quarkus.http.cors.enabled=true
quarkus.http.cors.origins=https://console.polaris.service
quarkus.http.cors.methods=GET,POST,PUT,DELETE,PATCH,OPTIONS
quarkus.http.cors.headers=Content-Type,Authorization,Polaris-Realm
同じリポジトリには、他カタログからの移行に使うIceberg Catalog Migrator、カタログ間の同期を行うPolaris Synchronizer、性能計測用のBenchmarks、MCP対応クライアントからPolarisのREST APIを操作するMCP Serverもあります。
Polarisを採用しない判断基準
Polarisが効くのは、複数のエンジンが同じIcebergテーブルを読み書きし、その権限を1か所で統制したい場合です。次の条件に当てはまるなら、導入しない方が総コストは下がります。
最も分かりやすいのは、使うエンジンが1つだけのケースです。SparkだけあるいはTrinoだけで完結し、既存のGlueやHive Metastoreで必要な権限管理も満たせるなら、Polarisの追加は見送れます。Polarisを足した瞬間に、サーバー、PostgreSQL、鍵、realm、RBACの設計と運用が丸ごと増えます。AWSの中で閉じるなら、Glue Data CatalogのIceberg RESTエンドポイントを使うSageMaker Lakehouseとは?構成・料金とIceberg REST接続の手順【2026年版】の構成と比べてから決めてください。
スキーマ移行を手作業で回す体制が無いときも見送りです。前章のとおり、版を上げるたびに移行SQLの要否を判断できる担当が要ります。その体制が組めないなら、マネージドのHorizon Catalogと比べてください。
Icebergそのものの採用が決まっていない段階も同様です。テーブルフォーマットの選定が済まないうちにカタログ層を固めると、後戻りのコストが大きくなります。選定軸はオープンテーブルフォーマットとは?Iceberg・Delta Lake・Hudiの違いと選び方を実装視点で解説【2026年版】を先に読んでください。カタログを含むデータ基盤全体の設計から相談したい場合は、データ分析基盤構築・MLOps構築支援で承っています。
外部カタログとの連携(フェデレーション)を当てにする場合は、公式イメージのままでは足りない点を先に確認してください。機能自体がpolaris.features."ENABLE_CATALOG_FEDERATION"で既定オフで、SUPPORTED_CATALOG_CONNECTION_TYPESの既定値も[ICEBERG_REST]だけです。決定的なのはビルドで、Hive MetastoreフェデレーションのドキュメントはHiveのファクトリをpackaged as an optional extension and is not baked into default server buildsとしており、-PNonRESTCatalogs=HIVEを付けて自前ビルドしないと使えません。apache/polarisの公式イメージをpullしてHive連携を前提に計画すると、この時点で止まります。Iceberg RESTフェデレーションもIcebergテーブルだけが対象です。
よくある質問
Apache Polarisのライセンスと費用は?
Apache License 2.0のオープンソースソフトウェアで、ソフトウェア自体の利用料はかかりません。費用が発生するのは、Polarisサーバーを動かす計算資源、メタストアに使うPostgreSQL、マネージド提供を選んだ場合のサービス利用料です。
spark.sql.catalog.polaris.catalog-implには何を指定しますか?
Polarisへ接続する標準的な構成では使いません。typeにrestを指定するのが公式の構成です。両方を書くと動きません。Iceberg本体のCatalogUtilはtypeとcatalog-implが同時に設定されているとCannot create catalog %s, both type and catalog-impl are setで例外を投げます。catalog-implを使うのは、typeを空にして独自のカタログ実装クラスを読ませる場合だけです。
Docker Composeで作ったカタログは再起動後も残りますか?
残りません。Quickstartはインメモリのメタストアで動くため、コンテナを落とした時点でカタログも権限設定も消えます。残すにはPostgreSQLをメタストアにしてbootstrapします。1.8.0では先にCREATE SCHEMAが必要です。
Snowflake Open Catalogとの違いは何ですか?
違いは運用責任の所在です。サーバーの可用性、鍵やrealmの管理、スキーマ移行や版の追随を自分で持つのがセルフホストのPolaris、Snowflakeに預けるのがOpen Catalogです。ただしOpen Catalogは既存アカウントを持たない顧客の新規申込を受け付けていないため、これから契約する場合の比較対象はHorizon Catalogです。
「Polaris」という名前の他の製品と混同しないためには?
Polarisは北極星を指す一般名詞で、同名のOSSや業務システム、車両ブランドが複数あります。Icebergのカタログを指すときは「Apache Polaris」または「Polaris Catalog」と書き、リポジトリがgithub.com/apache/polaris、公式サイトがpolaris.apache.orgであることを確かめるのが確実です。