在前面的章节中,我们深入探讨了 Apache Polaris、其关键特性以及 API。现在,是时候走出理论,动手在本地部署并使用 Apache Polaris 了。通过实操,你将理解各组件如何协同工作,从而把这些概念应用到真实场景中。
虽然像 Snowflake Open Catalog 和 Dremio Catalog 这样的托管 Polaris 产品,在生产环境中能带来更顺畅的体验——免去了自建与运维 Polaris 基础设施的负担——但对其工作机制进行动手实践仍然极有价值。通过在本地部署 Apache Polaris,你将直观了解目录(catalog)、角色(role)和访问管理如何组合在一起,为你充分理解并优化托管方案打下坚实基础。
本章将带你用 Docker 部署 Apache Polaris,完成目录的初始化、角色创建与访问控制配置。无论你是在评估 Polaris 是否适合你的组织,还是想进一步理解其内部原理,这份指南都能让你自信地探索其潜力。
使用 Docker 本地部署
在开始本地部署 Apache Polaris 前,先澄清开发与生产环境的区别。本章聚焦于通过 Docker 快速启动 Polaris 进行动手学习与试验——这是了解 Polaris 底层工作方式的绝佳路径。但当你真正将 Polaris 投入生产时,还需额外考虑:使用 OAuth2 的安全认证、持久化的元数据存储、以及服务凭证的正确引导(bootstrap)。本地部署通常依赖简化的默认值,比如内存存储和测试认证器;而生产环境应遵循 Polaris 部署文档中的最佳实践,以确保稳定性、安全性和可扩展性。可以把本地部署视作你的 “Polaris 实验室”——是真正上线之前的关键一步。
先决条件
在继续之前,请确保你的系统已安装以下工具:
- Docker:容器化平台
- Docker Compose:用于定义并运行多容器应用
- Git:用于克隆包含部署配置的仓库
第 1 步:克隆仓库
首先克隆 Apache Polaris 教学环境(Educational Environment)仓库,其中包含所需的 Docker Compose 文件和部署说明。
git clone https://github.com/AlexMercedCoder/quick-test-polaris-environment
进入克隆的目录:
cd quick-test-polaris-environment
该仓库提供了在本地部署 Polaris 与 Spark 所需的一切,包括 docker-compose.yml。
第 2 步:配置环境变量
部署过程可以按需使用 AWS 凭证以及其他与环境相关的配置。这些设置通过宿主机上的环境变量提供;如果你使用 S3 作为存储,请确保相应变量已设置。
# Bash/ZSH
export AWS_REGION=us-east-1
export AWS_ACCESS_KEY_ID=your-aws-access-key
export AWS_SECRET_ACCESS_KEY=your-aws-secret-key
# CMD/Windows
set AWS_REGION=us-east-1
set AWS_ACCESS_KEY_ID=your-aws-access-key
set AWS_SECRET_ACCESS_KEY=your-aws-secret-key
# PowerShell/Windows
$env:AWS_REGION = "us-east-1"
$env:AWS_ACCESS_KEY_ID = "your-aws-access-key"
$env:AWS_SECRET_ACCESS_KEY = "your-aws-secret-key"
如果你不使用 S3 存储,可以跳过本步骤。首次体验建议先用本地文件系统完成流程,再尝试接入 S3。
第 3 步:理解 Docker Compose 文件
仓库中的 docker-compose.yml 定义了在本地运行 Apache Polaris 与 Spark 所需的服务。它确保两者能够顺畅通信,并通过公共卷共享数据。
以下是 docker-compose.yml 的完整内容:
services:
polaris:
image: apache/polaris:1.1.0-incubating-SNAPSHOT
container_name: polaris
ports:
- "8181:8181"
- "8182"
networks:
polaris-quickstart:
volumes:
- ./icebergdata:/data
environment:
AWS_REGION: $AWS_REGION
AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
POLARIS_BOOTSTRAP_CREDENTIALS: POLARIS,root_user,my_secret_id
polaris.realm-context.realms: POLARIS
quarkus.log.file.enable: "false"
quarkus.otel.sdk.disabled: "true"
polaris.features."DROP_WITH_PURGE_ENABLED": "true"
polaris.features."ALLOW_INSECURE_STORAGE_TYPES": "true"
polaris.features."SUPPORTED_CATALOG_STORAGE_TYPES": "["FILE","S3",
"GCS","AZURE"]"
polaris.readiness.ignore-severe-issues: "true"
spark:
platform: linux/x86_64
image: alexmerced/spark35nb:latest
ports:
- "8080:8080" # Master Web UI
- "7077:7077" # Master Port
- "8888:8888" # Jupyter Notebook
volumes:
- ./icebergdata:/data
environment:
- AWS_REGION=us-east-1
- AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
container_name: spark
networks:
polaris-quickstart:
networks:
polaris-quickstart:
该文件定义了两个服务(Polaris 与 Spark),它们连接到同一 Docker 网络,并复用同一个数据卷以实现互操作。
Polaris 服务
-
作用:充当 Iceberg Catalog。
-
镜像:
apache/polaris:1.1.0-incubating-SNAPSHOT(Apache 官方快照构建)。 -
端口:
8181:8181暴露 Polaris 主 REST API;8182为 Polaris 内部端口,无需外部映射。
-
卷:将本地
./icebergdata挂载到容器内/data,作为目录数据与元数据的共享位置。 -
环境变量:从宿主(或
.env文件)读取 AWS 区域与凭证;配置 Polaris 的引导凭证;启用对多种存储后端(含 FILE)的支持;关闭遥测与文件日志。 -
配置:使用
POLARIS_BOOTSTRAP_CREDENTIALS引导,采用默认内部配置;为便于在 FILE 存储上进行本地实验,显式启用DROP_WITH_PURGE_ENABLED与ALLOW_INSECURE_STORAGE_TYPES等特性。
Spark 服务
-
作用:作为对接 Iceberg Catalog 的计算与交互环境。
-
镜像:
alexmerced/spark35nb:latest,包含 Spark 3.5、Iceberg、PySpark、JupyterLab 及其他数据工具。 -
端口:
8080:8080Spark Master Web UI;7077:7077Spark Master 端口;8888:8888Jupyter Notebook。
-
卷:与 Polaris 共享
./icebergdata,在使用本地 FILE 存储时,两者读写同一路径至关重要。 -
环境变量:设置 AWS 区域与凭证(如需访问对象存储)。
-
平台:
linux/x86_64标注用于在某些需要特定架构的环境中保证兼容性。
共享网络
两个服务均加入 polaris-quickstart Docker 网络,可通过服务名(polaris 与 spark)进行内部通信。
第 3 步小结
该配置让 Apache Polaris 作为基于 REST 的 Iceberg 目录运行,而 Spark 充当计算引擎。两者共享标准文件系统(./icebergdata),便于在一个自包含的环境中试验 Iceberg 表。此配置面向教学与开发使用;在生产或云环境中,建议改为使用安全的对象存储(如 S3、GCS)与托管的认证机制。
第 4 步:启动环境
在包含 docker-compose.yml 的目录中,通过以下命令启动服务:
docker compose up
docker compose up 将:
- 构建并启动
polaris与spark; - 将容器日志输出到当前终端。
启动后可通过以下命令确认服务是否运行:
docker ps
你会在列表中看到 polaris 与 spark。
第 5 步:停止环境
完成实验后,请停止并清理正在运行的容器以释放系统资源。
- 仅停止(保留容器状态) :
docker compose stop
该命令会暂停容器,之后可通过 docker compose start 快速恢复。
- 停止并移除容器与网络等资源:
docker compose down
- 连同卷一并删除(包括
./icebergdata) :
docker compose down --volumes
请谨慎使用 --volumes,它会删除所有持久化数据。
下表给出了常见 Docker Compose 启停命令:
表 6-1. 管理 Docker Compose 环境的常用命令
| 命令 | 动作说明 |
|---|---|
docker compose up | 启动服务并在终端输出日志 |
docker compose up -d | 以守护(后台)模式启动服务 |
docker compose stop | 停止容器但保留其状态,便于快速再次启动 |
docker compose down | 停止并移除 docker-compose.yml 定义的容器、网络及其他资源 |
docker compose down --volumes | 停止并移除容器及其卷,同时删除存储在卷中的数据(不可恢复) |
创建 Catalog(目录)
现在 Polaris 环境已经就绪,第一步就是创建一个 catalog。Catalog 是 Polaris 的基石,用于存储关于表以及其他资源的元数据。我们将为本章中的 catalog、principal(主体) 和 role(角色) 使用固定的示例名称。你当然可以自定义名称,但为了与下一章的 Apache Spark 代码片段相匹配,这里采用统一命名。
本环境通过环境变量预置了 root 凭证:
POLARIS_BOOTSTRAP_CREDENTIALS: POLARIS,root_user,my_secret_id
对 “POLARIS” 这个 Realm(领域) 而言,root 用户的 ID 为 root_user,密钥为 my_secret_id。在该环境中,提供了一个 Python 文件可一次性跑完所有引导(bootstrapping)请求;在 Polaris 仓库中也有可用的 CLI。为了熟悉 Polaris 的 Catalog 管理 API,下面我们直接向 Polaris 服务器发送原始请求(raw requests)。
首先,使用容器日志中提供的 root 凭证去生成 bearer token:
curl -i -X POST \
http://localhost:8181/api/catalog/v1/oauth/tokens \
-d 'grant_type=client_credentials&client_id=<ID>&client_secret=<SECRET>&scope=PRINCIPAL_ROLE:ALL'
响应中会包含一个 bearer token。复制该 token,以便在后续请求中使用。接着,用该 bearer token 发送 POST 请求来创建 catalog。你可以选择使用本地文件系统或 S3 存储。若你首次体验 Polaris,出于教学与演示的目的,建议先选择 本地文件系统:
curl -i -X POST -H "Authorization: Bearer <YOUR_TOKEN>" \
-H 'Accept: application/json' -H 'Content-Type: application/json' \
http://localhost:8181/api/management/v1/catalogs \
-d '{"name": "polariscatalog", "type": "INTERNAL", "properties": {
"default-base-location": "file:///data"
},"storageConfigInfo": {
"storageType": "FILE",
"allowedLocations": [
"file:///data"
]
} }'
如果使用 S3,请将占位符替换为你的 AWS 配置:
curl -i -X POST -H "Authorization: Bearer <YOUR_TOKEN>" \
-H 'Accept: application/json' -H 'Content-Type: application/json' \
http://localhost:8181/api/management/v1/catalogs \
-d '{"name": "polariscatalog", "type": "INTERNAL", "properties": {
"default-base-location": "s3://my/s3/path"
},"storageConfigInfo": {
"roleArn": "arn:aws:iam::xxxxxxxxx:role/polaris-storage",
"storageType": "S3",
"allowedLocations": [
"s3://my/s3/path"
]
} }'
如果使用 AWS,请务必将 “xxxxxxxxx” 替换为你实际的 AWS 账号编号。
验证 catalog 是否创建成功:
curl -X GET "http://localhost:8181/api/management/v1/catalogs" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json"
何时创建 Catalog
在 Polaris 中创建 catalog 的操作本身很直接,但何时创建以及如何在多个 catalog 之间组织数据集则需要更具策略性的思考。Catalog 是 Polaris Realm 内部最高级别的隔离边界。每个 catalog 都有自己的一组 namespace、table、view 以及配套的安全控制。及早做出明智的 catalog 边界决策,有助于在规模化时获得更好的性能、更有效的治理以及更易操作的运维体验。
需要创建新 catalog 的场景
- 需要在数据集或团队之间建立硬隔离边界。
Catalog 级别的访问控制可以阻止未经授权的用户甚至列出某个 catalog 中的对象,除非明确授予权限。 - 在同一 Polaris 部署中同时管理 staging 与 production 等环境。
为每个环境单独创建 catalog,可以降低误访问或权限提升的风险。 - 需要强制使用不同的存储后端或 IAM 角色。
每个 catalog 都可定义自己的存储配置,因此当文件系统或认证模型不同,catalog 是恰当的边界。
不适合创建新 catalog 的场景
- 只是想对相关表做分组。
用 namespace 即可。Namespace 在 catalog 内提供更轻量的逻辑组织方式。 - 多个数据集共享相同的治理与存储策略。
过度创建 catalog 会引入管理开销,而收益有限。
推荐的 catalog 规划策略
- 按部门或业务单元(BU)划分
在大型企业中,将一个 catalog 映射给一个 BU(如销售、市场)常常更合理,治理边界与组织结构保持一致。 - 按环境划分
为 dev / staging / prod 分别创建 catalog,用于隔离不同负载并简化部署流水线。 - 按使用场景划分
对同时服务多类用户画像的数据平台,可将 analytics(分析)/ data science(数据科学)/ ML feature store(特征库) 分设不同 catalog,以明确所有权与策略模型。
长期考量
Catalog 相对稳定,并非为频繁创建与删除而设计。因此,catalog 设计应当是深思熟虑的架构决策,而不是为短期组织便利而作的权宜之计。与其在 catalog 之间迁移实体,不如在单个 catalog 内演进 namespace 与 role——后者通常更易管理。
通过审慎设计 catalog,你可以确保在数据湖仓规模增长的同时,Polaris 依然保持可扩展、安全且易治理。
创建 Catalog 角色(Catalog Roles)
Catalog 角色用于控制对 catalog 及其内容的访问。使用前面获取的 bearer token,在先前创建的 catalog 中创建一个 catalog 角色:
curl -X POST "http://localhost:8181/api/management/v1/catalogs/polariscatalog/catalog-roles" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"catalogRole": {"name": "polariscatalogrole"}}'
列出 catalog 角色以确认已经创建成功:
curl -X GET "http://localhost:8181/api/management/v1/catalogs/polariscatalog/catalog-roles" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json"
何时创建 Catalog 角色
在 Polaris 中,Catalog 角色是 catalog 内的主要访问控制单元,用于决定用户与服务可执行的操作。虽然创建角色在技术上很直接,但若能以长期可用性与治理为导向来设计,将显著提升权限模型的可扩展性、安全性与可理解性。
本节给出创建与管理 Catalog 角色的最佳实践,重点关注清晰性、安全性与可维护性。
用角色映射真实职责
最有效的 Catalog 角色应当反映组织内真实人物画像(persona)的职责。与其将权限直接授予用户(principal),不如先定义能描述“该用户应该能做什么”的 Catalog 角色——然后把这些角色授予到 principal 角色 上。这样可以保持权限模型的模块化,且更易审计。例如:
data_reader角色:被授予对表与视图的读取权限。data_engineer角色:拥有更广的权限,包括表的创建、更新与删除。catalog_admin角色:包含管理 schema、view 以及 catalog 级配置的权限。
当团队职责变化或扩张时,只需在角色层面集中调整权限,而无需逐个修改用户的单独权限。
坚持最小权限原则
拿不准时,就少给权限。Catalog 角色应只包含完成任务所需的精确操作集合,从而降低误改、数据暴露或滥用的风险。
从最小角色(例如只读)开始,按需叠加其他权限。避免在非必要时授予 CATALOG_MANAGE_PRIVILEGES 或 TABLE_DELETE 等高危权限。
复用与泛化
避免为一次性场景创建过于特定的 Catalog 角色。如果几乎每个用户或数据集都有独一无二的角色,治理模型会难以管理与审计。建议:
- 为典型访问模式创建可复用的角色;
- 通过 namespace 级的权限授予来限制访问范围,而不是新建角色;
- 给角色添加属性标签(如
env=prod、purpose=analytics),以便长期识别其意图与范围。
用作用域与策略限制角色
尽管 Catalog 角色是按 catalog 定义的,但它们不必自动拥有对该 catalog 内一切对象的访问。应结合 namespace / table / view 级的权限授予来约束角色可见或可修改的对象。
记录所有权与用途
利用角色属性为每个角色存储元数据,例如:
--property owner=finance_team
--property sensitivity=internal_only
这有助于自动化治理流程、提升可发现性,并支持内部审计与评审。
定期审查与轮换
Catalog 角色并非一成不变。随着时间推移,它们可能会过时、过度授权或重复。将定期的访问审查纳入治理流程:
- 识别不再使用的角色;
- 审计哪些 principal 角色 绑定了高权限的 Catalog 角色;
- 移除或重构过于宽泛或重复的角色。
遵循以上最佳实践,你的访问模型将更健壮、可理解且安全,同时不会拖慢 Polaris 期望提供的敏捷性。
下面是通顺、专业的中文译文(保留技术名词与命令;“principal”指安全主体):
创建 Principals(主体)
principal 表示能够访问 Polaris 资源的用户或服务账号。使用前面获得的 bearer token 创建一个 principal:
curl -X POST "http://localhost:8181/api/management/v1/principals" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"name": "polarisuser", "type": "user"}'
确认 principal 已创建:
curl -X GET "http://localhost:8181/api/management/v1/principals" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json"
创建 Principal Roles(主体角色)
principal role 用于定义授予某个 principal 的访问权限。
为 polarisuser 创建一个主体角色:
curl -X POST "http://localhost:8181/api/management/v1/principal-roles" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"principalRole": {"name": "polarisuserrole"}}'
将该主体角色分配给该 principal:
curl -X PUT "http://localhost:8181/api/management/v1/principals/polarisuser/principal-roles" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"principalRole": {"name": "polarisuserrole"}}'
验证角色分配情况:
curl -X GET "http://localhost:8181/api/management/v1/principals/polarisuser/principal-roles" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json"
何时创建 Principal 角色
在 Polaris 中,principal 角色 是跨用户、服务账号与自动化流程进行访问管理的可扩展机制。与其把 catalog 角色或细粒度权限直接赋给每个 principal,不如先把它们赋给 principal 角色,由此形成一个可复用、可审计的抽象层。
良好的 principal 角色设计能让你的访问模型更易管理、更安全,也更能适应团队与架构的演进。
何时应创建新的 principal 角色
在以下情形应创建新角色:
- 一组用户或服务在一个或多个 catalog 中需要同一组权限;
- 需要按岗位职能分离职责(如分析师 vs. 数据工程师);
- 某个团队/部门/业务单元独立运作,需要清晰限定的访问范围;
- 引入自动化或第三方集成,需要在既定安全约束下进行编程式访问;
- 合规或治理要求按职能或区域进行明确的访问追踪。
每个 principal 角色都成为该群体可访问内容的“单一事实来源”,便于轮换凭证、撤销访问,或评估权限变更的影响范围(blast radius)。
将角色映射到真实组织单元
让 principal 角色与组织中的实际团队或职责对齐,有助于提升清晰度并简化入职流程。例如:
data_engineers_team_aanalytics_readonlyetl_jobsthird_party_integration_salesforce
采用能体现职能或所有权的命名约定,便于长期审计与管理。
跨环境复用角色
不要为 dev、staging、prod 各拷贝一套角色。优先设计与环境无关的角色,再通过按环境划分的 catalog 来限定访问范围。这样既简化治理,又保持环境之间的隔离。
保持角色可管理
避免角色泛滥。如果为每个 principal 都定制一个独有角色,抽象层的价值就会丧失。建议:
- 围绕共享访问模式创建可复用角色;
- 使用元数据标签(如
--property team=finance、--property env=prod)记录更多信息; - 定期回顾,按需要合并或废弃角色。
审计与评审
把 principal 角色管理纳入常规安全与治理流程:
- 定期审查“谁拥有哪些角色”;
- 跟踪使用情况并按需轮换凭证;
- 撤销不再需要的角色。
维护良好的 principal 角色集合,是在 Polaris 中保障与扩展访问控制的有力工具。随着用户、服务与 catalog 的增长,遵循这些最佳实践能确保你的权限模型始终清晰、一致且合规。
将 Catalog 角色分配给 Principal 角色并在 Catalog 上设置权限
当你已经创建了 catalog、catalog role、principal 和 principal role 之后,下一步就是把 catalog 角色 分配给 principal 角色。这样可以确保该 principal 能与该 catalog 交互。接下来,还需要在 catalog 角色上设置必要的权限,以限定被分配的 principal 可以执行的操作。
使用 bearer token 将 catalog 角色分配给 principal 角色:
curl -X PUT "http://localhost:8181/api/management/v1/principal-roles/polarisuserrole/catalog-roles/polariscatalog" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"catalogRole": {"name": "polariscatalogrole"}}'
为 catalog 角色授予权限。定义该 catalog 角色在该 catalog 上拥有的权限。例如,授予 CATALOG_MANAGE_CONTENT 权限:
curl -X PUT "http://localhost:8181/api/management/v1/catalogs/polariscatalog/catalog-roles/polariscatalogrole/grants" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"grant": {"type": "catalog", "privilege": "CATALOG_MANAGE_CONTENT"}}'
验证已授予的权限,检查这些权限是否成功应用到该 catalog 角色:
curl -X GET "http://localhost:8181/api/management/v1/catalogs/polariscatalog/catalog-roles/polariscatalogrole/grants" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json"
小结
通过将 catalog 角色 分配给 principal 角色 并设置相应权限,你已经完成了 Polaris 中基础的访问层级搭建。该配置确保了对 catalog 与资源的安全且有序的管理,为协作与数据治理提供了稳固框架。至此环境已就绪,你可以从“搭建”迈向“应用”。下一章我们将把该 Polaris 环境与 Python Spark 环境集成,以编程方式查询与交互数据。通过动手实践,你将把所有环节串联起来,直观感受 Polaris 在真实场景中的强大能力。