配置 Azure Blob 云存储
配置 Azure Blob 云存储
本页介绍如何将 Azure Blob Storage 和 Azure Data Lake Storage Gen2 (ADLS Gen2) 配置为 Polaris 目录的存储后端。Polaris 使用具有目标存储账户数据平面访问权限的服务主体(service principal)的凭据对 Azure 进行身份验证,并在每次表加载请求时向客户端签发短期 SAS 令牌。
服务主体与 Polaris 凭据
Polaris 使用 Azure SDK 的 DefaultAzureCredential 凭据链,默认情况下会从环境变量中读取服务主体凭据。请创建一个对存储账户具有数据访问权限的服务主体,并将其凭据传递给 Polaris 进程:
# Replace <subscription>, <resource-group>, <storage-account> with your values.
az ad sp create-for-rbac \
--name polaris-storage \
--role "Storage Blob Data Contributor" \
--scopes "/subscriptions/<subscription>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>"该命令会打印出 appId、password 和 tenant。请在 Polaris 服务端设置这些值:
export AZURE_TENANT_ID=<tenant>
export AZURE_CLIENT_ID=<appId>
export AZURE_CLIENT_SECRET=<password>在 Kubernetes 部署中,不要以明文形式将 AZURE_CLIENT_SECRET 写入 Pod 规范。应将客户端密钥存放在 Kubernetes Secret(或由 Azure Key Vault 提供程序等 Operator 引用的外部密钥存储)中,并通过 envFrom/valueFrom: secretKeyRef 将其注入 Polaris 容器。POLARIS_BOOTSTRAP_CREDENTIALS 中的引导凭据也同理。
在存储帐户范围内授予 Storage Blob Data Contributor 角色后,Polaris 可以为该帐户下的任意容器签发 SAS 令牌;如果想将单个 Polaris 目录限制在一个容器内,应将该角色的作用域收窄(仅限单个容器)。
存储帐户要求
支撑目录的存储帐户应进行如下配置:
- 分层命名空间(HNS) 并非 Polaris 或 Iceberg 执行表操作本身的硬性要求。它的主要作用在于决定 Polaris 能将签发的 SAS 令牌的作用域收窄到何种程度:启用 HNS 后,Polaris 可以将令牌的作用域收缩到支撑所请求命名空间或表的目录(文件夹);未启用 HNS 时,令牌只能限定在容器级别。需要按命名空间隔离的生产部署应启用 HNS。
storageConfigInfo中的hierarchical字段必须与存储帐户的实际状态一致。若两者不匹配,签发的令牌会依据存储端并不存在的目录 ACL 进行作用域限定,从而导致运行时访问错误。- 一个用于存放目录中各命名空间和表的容器(例如
warehouse)。Polaris 不会自行创建该容器。 - 防火墙规则需放行来自 Polaris 控制平面以及将要读取数据的引擎的流量。SAS 令牌无法绕过存储帐户防火墙。
目录存储配置
在服务器上准备好服务主体后,使用存储帐户的租户 ID 和 abfss:// 位置创建目录:
curl -X POST https://<polaris-host>/management/v1/catalogs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"catalog": {
"type": "INTERNAL",
"name": "warehouse_azure",
"properties": {
"default-base-location": "abfss://warehouse@example.dfs.core.windows.net/prod/"
},
"storageConfigInfo": {
"storageType": "AZURE",
"tenantId": "00000000-0000-0000-0000-000000000000",
"hierarchical": true,
"allowedLocations": [
"abfss://warehouse@example.dfs.core.windows.net/"
]
}
}
}'default-base-location 必须使用 abfss:// 协议,并配合 ADLS Gen2 端点(<account>.dfs.core.windows.net)使用。不支持 wasbs:// 协议。
AzureStorageConfigurationInfo 还接受 multiTenantAppName 和 consentUrl 两个字段。当前 Apache Polaris 代码在与 Azure API 通信时并不使用这些字段;它们仅作为参考信息,按照上文使用服务主体进行身份验证的自托管部署可以省略。
SAS 令牌的作用域与 HNS ACL
启用 HNS(hierarchical: true)时,Polaris 会将每个签发的 SAS 令牌的作用域缩小到支撑所请求命名空间或表的目录。该目录上的 ADLS Gen2 ACL 必须包含服务主体,以及任何需要通过签发凭据之外的方式读取数据的额外主体。
一种常见的故障模式是:令牌授予了对象级别的权限,却被目录级别的 ACL 拒绝。ADLS 返回的 403 错误中包含被拒绝的路径;将该精确前缀上的 ACL 调整一致即可恢复。
未启用 HNS 时,请设置 hierarchical: false。此时 Polaris 会签发作用域为存储容器级别(而非按目录)的 SAS 令牌;这种做法适用于小型部署,但无法限制跨命名空间访问。
客户端配置
各引擎通过 Iceberg REST API 调用 Polaris,并在加载表时接收 SAS 令牌属性;客户端无需配置静态 Azure 凭据。
以下为 Spark 示例,其属性名称与现有 MinIO / RustFS 指南中使用的保持一致:
bin/spark-sql \
--packages org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.10.1,org.apache.iceberg:iceberg-azure-bundle:1.10.1 \
--conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
--conf spark.sql.catalog.polaris=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.polaris.type=rest \
--conf spark.sql.catalog.polaris.uri=https://<polaris-host>/api/catalog \
--conf spark.sql.catalog.polaris.oauth2-server-uri=https://<polaris-host>/api/catalog/v1/oauth/tokens \
--conf spark.sql.catalog.polaris.token-refresh-enabled=false \
--conf spark.sql.catalog.polaris.warehouse=warehouse_azure \
--conf spark.sql.catalog.polaris.scope=PRINCIPAL_ROLE:ALL \
--conf spark.sql.catalog.polaris.credential=<client-id>:<client-secret> \
--conf spark.sql.catalog.polaris.header.X-Iceberg-Access-Delegation=vended-credentials \
--conf spark.sql.catalog.polaris.io-impl=org.apache.iceberg.azure.adlsv2.ADLSFileIO推荐配置 oauth2-server-uri:若不配置,Iceberg REST 客户端会回退到硬编码的 /v1/oauth/tokens 路径,并记录一条弃用警告,因为这种自动回退行为计划在未来某个 Iceberg 版本中移除。
Spark 应用必须在 classpath 中包含 Iceberg Azure bundle(或 iceberg-azure 以及相应的 Hadoop / Azure jar);Polaris 不会将这些 jar 分发给计算引擎。
对于 Trino,请使用 Iceberg 连接器配合 REST catalog,其配置形式与同级页面上的 AWS S3 示例相同:
connector.name=iceberg
iceberg.catalog.type=rest
iceberg.rest-catalog.uri=https://<polaris-host>/api/catalog
iceberg.rest-catalog.warehouse=warehouse_azure
iceberg.rest-catalog.security=OAUTH2
iceberg.rest-catalog.oauth2.credential=<client-id>:<client-secret>
iceberg.rest-catalog.oauth2.scope=PRINCIPAL_ROLE:ALL
iceberg.rest-catalog.oauth2.server-uri=https://<polaris-host>/api/catalog/v1/oauth/tokens对于 PyIceberg,使用 rest 目录类型,并将凭证分发请求头作为 REST 请求头转发:
from pyiceberg.catalog.rest import RestCatalog
cat = RestCatalog(
name="polaris",
**{
"uri": "https://<polaris-host>/api/catalog",
"warehouse": "warehouse_azure",
"credential": "<client-id>:<client-secret>",
"scope": "PRINCIPAL_ROLE:ALL",
"oauth2-server-uri": "https://<polaris-host>/api/catalog/v1/oauth/tokens",
"header.X-Iceberg-Access-Delegation": "vended-credentials",
},
)Polaris 会在加载表时向 FileIO 按账号发放 SAS 令牌。这些凭据以 adls.sas-token.<storage-account> 形式的键名返回(在需要限定作用域时,可附带 dfs.core.windows.net / blob.core.windows.net 后缀),具体定义见 StorageAccessProperty。PyIceberg 客户端可直接获取这些凭据,无需配置任何静态账户密钥或 SAS 令牌。
验证配置
CREATE NAMESPACE warehouse_azure.demo;
CREATE TABLE warehouse_azure.demo.t (id BIGINT, name STRING) USING iceberg;
INSERT INTO warehouse_azure.demo.t VALUES (1, 'hello');
SELECT * FROM warehouse_azure.demo.t;如果任何操作失败:
- 来自 Azure AD(
AADSTS*)的错误通常表示AZURE_CLIENT_ID/AZURE_CLIENT_SECRET/AZURE_TENANT_ID中的服务主体凭据有误、密钥已过期,或该主体在存储账户上没有角色分配。 Failed to get subscoped credentials伴随Status code 403和AuthorizationPermissionMismatch的 Azure 错误响应体,意味着服务主体在覆盖所访问路径的范围内没有数据平面角色(Storage Blob Data Contributor或等效角色)。在存储账户(或特定容器)上授予该角色并等待 RBAC 生效即可解决。- 来自
dfs.core.windows.net路径的 403 且没有 Azure 错误码,通常说明在启用 HNS 并且目录上设置了较严格 ACL 的情况下,基本位置上的 HNS ACL 不匹配。 - 容器级别操作返回 404 表明容器尚不存在;Polaris 不会创建容器,只会创建其下的目录和 Blob。
评论
登录后参与评论
KnowForge