Apache Polaris权威指南——使用 Apache Polaris 开源版

206 阅读17分钟

在前面的章节中,我们深入探讨了 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_ENABLEDALLOW_INSECURE_STORAGE_TYPES 等特性。

Spark 服务

  • 作用:作为对接 Iceberg Catalog 的计算与交互环境。

  • 镜像alexmerced/spark35nb:latest,包含 Spark 3.5、Iceberg、PySpark、JupyterLab 及其他数据工具。

  • 端口

    • 8080:8080 Spark Master Web UI;
    • 7077:7077 Spark Master 端口;
    • 8888:8888 Jupyter Notebook。
  • :与 Polaris 共享 ./icebergdata,在使用本地 FILE 存储时,两者读写同一路径至关重要。

  • 环境变量:设置 AWS 区域与凭证(如需访问对象存储)。

  • 平台linux/x86_64 标注用于在某些需要特定架构的环境中保证兼容性。

共享网络

两个服务均加入 polaris-quickstart Docker 网络,可通过服务名(polarisspark)进行内部通信。

第 3 步小结

该配置让 Apache Polaris 作为基于 REST 的 Iceberg 目录运行,而 Spark 充当计算引擎。两者共享标准文件系统(./icebergdata),便于在一个自包含的环境中试验 Iceberg 表。此配置面向教学与开发使用;在生产或云环境中,建议改为使用安全的对象存储(如 S3、GCS)与托管的认证机制。

第 4 步:启动环境

在包含 docker-compose.yml 的目录中,通过以下命令启动服务:

docker compose up

docker compose up 将:

  • 构建并启动 polarisspark
  • 将容器日志输出到当前终端。

启动后可通过以下命令确认服务是否运行:

docker ps

你会在列表中看到 polarisspark

第 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 内演进 namespacerole——后者通常更易管理。

通过审慎设计 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_PRIVILEGESTABLE_DELETE 等高危权限。

复用与泛化

避免为一次性场景创建过于特定的 Catalog 角色。如果几乎每个用户或数据集都有独一无二的角色,治理模型会难以管理与审计。建议:

  • 典型访问模式创建可复用的角色;
  • 通过 namespace 级的权限授予来限制访问范围,而不是新建角色;
  • 给角色添加属性标签(如 env=prodpurpose=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_a
  • analytics_readonly
  • etl_jobs
  • third_party_integration_salesforce

采用能体现职能或所有权的命名约定,便于长期审计与管理。

跨环境复用角色

不要为 dev、staging、prod 各拷贝一套角色。优先设计与环境无关的角色,再通过按环境划分的 catalog 来限定访问范围。这样既简化治理,又保持环境之间的隔离。

保持角色可管理

避免角色泛滥。如果为每个 principal 都定制一个独有角色,抽象层的价值就会丧失。建议:

  • 围绕共享访问模式创建可复用角色;
  • 使用元数据标签(如 --property team=finance--property env=prod)记录更多信息;
  • 定期回顾,按需要合并或废弃角色。

审计与评审

把 principal 角色管理纳入常规安全与治理流程:

  • 定期审查“谁拥有哪些角色”;
  • 跟踪使用情况并按需轮换凭证;
  • 撤销不再需要的角色。

维护良好的 principal 角色集合,是在 Polaris 中保障与扩展访问控制的有力工具。随着用户、服务与 catalog 的增长,遵循这些最佳实践能确保你的权限模型始终清晰、一致且合规。

将 Catalog 角色分配给 Principal 角色并在 Catalog 上设置权限

当你已经创建了 catalog、catalog role、principalprincipal 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 在真实场景中的强大能力。