主题
文件存储是 LlamaCloud 不可分割的一部分 —— 没有它,许多关键功能都无从谈起。本页说明如何为你的部署配置文件存储:你需要建哪些桶,以及在非 AWS 的部署上如何配置 S3 Proxy 去对接它们。
要求
一个可用的对象存储服务。我们推荐下列选项:
由于 LlamaCloud 高度依赖文件存储,你需要创建下列这些桶:
llama-platform-parsed-documentsllama-platform-etlllama-platform-external-componentsllama-platform-file-parsingllama-platform-raw-filesllama-cloud-parse-outputllama-platform-file-screenshotsllama-platform-extract-output(供LlamaExtract使用)
注意
Amazon S3 的桶名是全局唯一的,所以上面这些默认名几乎肯定已被占用,aws s3 mb 会失败。实践中你必须另取名字(例如加上你的组织名或部署名作前缀),再用下文覆盖默认桶名一节做映射。在 Azure Blob 与 GCS 上,名字只要在你账号内唯一即可,但仍然建议加前缀。
留存与桶生命周期
LlamaCloud 自己从不删除 parse 或 extract 的输出。 解析结果没有删除端点,因此对象过期是唯一的删除路径。没有生命周期规则的部署会把每个解析过的文档、每次抽取以及每个中间产物无限留存 —— 这既是存储成本问题,也是数据留存问题。配好下面这些规则,才能让你的部署与托管服务所强制的留存策略对齐。
解析缓存:多数部署都缺的那条规则
Parse 会把每个结果都写进缓存,以便在缓存窗口内重复解析同一文件是免费的(见缓存控制)。没有任何机制会清除这些对象,所以缓存会随部署的整个生命周期不断膨胀,直到你让它们过期。
缓存键由文件内容与那些会影响输出的解析选项共同导出,因此同一份文档用不同设置解析会存成不同条目。一次部署大致会为每一种「文件与设置组合」各累积一个条目 —— 这正是总量不会封顶、只会一路上涨的原因。
缓存住在 parseFileOutput 所指桶的 cache/ 前缀下(该键默认与 parsedFileParsing 同桶,即 llama-platform-file-parsing):
s3://<parseFileOutput-bucket>/cache/<cache-key>/ # Parse v1 entries
s3://<parseFileOutput-bucket>/cache/<cache-key>/v2/ # Parse v2 entries两个 API 版本都缓存到同一个前缀,所以一条作用在 cache/ 上的规则就能同时覆盖 v1 与 v2。设成 2 天即可对齐文档所述的 48 小时缓存窗口:
{
"Rules": [{
"ID": "parse-cache-expiry",
"Status": "Enabled",
"Filter": { "Prefix": "cache/" },
"Expiration": { "Days": 2 },
"NoncurrentVersionExpiration": { "NoncurrentDays": 2 },
"AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
}]
}注意
在开了版本控制的桶上,单靠 Expiration 规则回收不了任何空间。 S3 不会因版本化对象过期就删除它,而是写一个 delete marker、把旧版本留作 non-current,于是桶一直在涨、清单却看着在缩小。只有 NoncurrentVersionExpiration 能释放这部分空间,所以上面的策略里两条规则都在。缓存内容可以通过重新解析复现,因此可以考虑在这个桶上直接停用版本控制。
其他存放临时输出的桶
| 桶键 | 存放内容 | 是否过期? |
|---|---|---|
parseOutput | 经结果 API 提供的解析任务输出 | 是(2 天) |
extractOutput | LlamaExtract 的输出 | 是(2 天) |
parseFileUpload / parsedFileParsing | 解析任务的输入与工作数据 | 是,但请先看下面的警告 |
注意
在给整桶规则之前,先看这个桶还放了哪些别的前缀。 parsedFileParsing 装的不只是解析工作数据:电子表格的区域数据住在 spreadsheet-regions/ 下,它在来源被删除时由平台一并清掉,且本应活到来源那么久。给整桶加一条泛用过期规则会把它提前删掉。请按前缀(cache/ 以及你的任务数据前缀)来划定规则范围,而不要一条规则盖住整桶;或者先列一遍桶,确认它到底装了哪些前缀。
应用到每个桶
无论上面如何,有两条规则值得在所有桶上都设:
- 中止未完成的分段上传,约 ~7 天后。否则失败的大文件上传会留下一些计费但在清单里看不见的分片。
- 让非当前版本过期,任何开了版本控制的桶都约 ~14 天。不然每次覆盖与删除都会把旧版本永久留在桶里;在繁忙的部署上,这部分会主导桶的体积。
- AWS S3(CLI)
- Azure Blob / GCS
终端窗口
# 1. The parse cache. Prefix-scoped, so nothing else in the bucket is touched.
aws s3api put-bucket-lifecycle-configuration \
--bucket <YOUR-PARSE-FILE-OUTPUT-BUCKET> \
--lifecycle-configuration '{
"Rules": [{
"ID": "parse-cache-expiry",
"Status": "Enabled",
"Filter": { "Prefix": "cache/" },
"Expiration": { "Days": 2 },
"NoncurrentVersionExpiration": { "NoncurrentDays": 2 },
"AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
}]
}'
# 2. Dedicated transient buckets (parseOutput, extractOutput). Safe bucket-wide.
aws s3api put-bucket-lifecycle-configuration \
--bucket <YOUR-PARSE-OUTPUT-BUCKET> \
--lifecycle-configuration '{
"Rules": [{
"ID": "parse-output-expiry",
"Status": "Enabled",
"Filter": {},
"Expiration": { "Days": 2 },
"NoncurrentVersionExpiration": { "NoncurrentDays": 2 },
"AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
}]
}'
# Confirm what is actually in effect, and what the cache prefix currently holds:
aws s3api get-bucket-lifecycle-configuration --bucket <YOUR-PARSE-FILE-OUTPUT-BUCKET>
aws s3 ls --summarize --human-readable --recursive \
s3://<YOUR-PARSE-FILE-OUTPUT-BUCKET>/cache/ | tail -2
# Durable buckets: no object expiration, just version and upload hygiene.
aws s3api put-bucket-lifecycle-configuration \
--bucket <YOUR-RAW-FILES-BUCKET> \
--lifecycle-configuration '{
"Rules": [{
"ID": "raw-files-hygiene",
"Status": "Enabled",
"Filter": {},
"Transition": { "Days": 0, "StorageClass": "INTELLIGENT_TIERING" },
"NoncurrentVersionExpiration": { "NoncurrentDays": 14 },
"AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
}]
}'同样的划分在这里也成立,只是机制不同。
- Azure Blob:用生命周期管理策略,配
delete: { daysAfterModificationGreaterThan: 2 },并用prefixMatch: ["<container>/cache/"]把解析缓存圈出来;开了 blob 版本控制的,再在version下设deleteAfterDaysSinceCreationGreaterThan。 - GCS:用对象生命周期管理规则,动作为
Delete、条件为age: 2,并用matchesPrefix: ["cache/"]圈出解析缓存;版本化的桶再加numNewerVersions。
把过期只应用到解析缓存前缀与那些临时桶上。持久的桶交给版本控制与分段上传的清理来管。
注意
应用任何规则之前,先确认每个键指向哪个桶。如果你把多个键指向了同一个共享桶,那里的一条 2 天过期规则也会把你的原始上传与 Index 文档一起删掉。要么给这些临时键各自一个桶,要么用前缀过滤器限定规则范围。
连接 AWS S3
下面给出两种配置 AWS S3 连接的方式:
(推荐)为服务账号配 IAM Role
我们建议为 LlamaCloud 新建一个 IAM Role 与 Policy。随后可以把这个 role ARN 作为服务账号的注解挂上去。
// Example IAM Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:*"], // this is not secure
"Resource": [
"arn:aws:s3:::llama-platform-parsed-documents",
"arn:aws:s3:::llama-platform-parsed-documents/*",
...
]
}
]
}创建好与上面那份策略类似的东西后,在 backend、jobsService、temporalWorkloads.llamaParse 以及每一个已配置的 temporalWorkloads.workers 条目上,用 EKS 的注解设好 serviceAccountAnnotations。
# Example for the backend service account. Repeat for each of the services listed above.
backend:
serviceAccountAnnotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/<role-name>这个 IAM Role 还必须信任你集群的 OIDC 提供方,并把范围限定在你 release 命名空间里的 LlamaCloud 服务账号。取集群的 OIDC issuer:
终端窗口
aws eks describe-cluster --name <cluster> \
--query 'cluster.identity.oidc.issuer' --output text
# e.g. https://oidc.eks.us-east-1.amazonaws.com/id/EXAMPLE0123456789然后为这个角色附加类似下面的信任策略(替换掉账号 id、地域、OIDC id,并把命名空间改成你的 release 命名空间):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account-id>:oidc-provider/oidc.eks.<region>.amazonaws.com/id/<OIDC-ID>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.<region>.amazonaws.com/id/<OIDC-ID>:aud": "sts.amazonaws.com"
},
"StringLike": {
"oidc.eks.<region>.amazonaws.com/id/<OIDC-ID>:sub": "system:serviceaccount:<namespace>:*"
}
}
}
]
}更多信息可参考 AWS 官方文档里关于这一点的说明。
AWS 凭据
创建一个用户并为它附加上述那些 s3 桶的策略。之后,只要在 values.yaml 里设置下列几项,就能让平台使用该用户的 aws 凭据:
config:
storageBuckets:
provider: "aws"
s3proxy:
enabled: true
containerPort: 8080
config:
JCLOUDS_PROVIDER: "aws-s3"
JCLOUDS_IDENTITY: <AWS-ACCESS-KEY>
JCLOUDS_CREDENTIAL: <AWS-SECRET-KEY>
JCLOUDS_REGION: <AWS-REGION> # e.g. "us-east-1"
JCLOUDS_ENDPOINT: "https://s3.<AWS-REGION>.amazonaws.com"覆盖默认桶名
我们允许你在 values.yaml 里覆盖默认的桶名。
config:
storageBuckets:
parsedDocuments: "<your-bucket-name>"
parsedEtl: "<your-bucket-name>"
parsedExternalComponents: "<your-bucket-name>"
parsedFileParsing: "<your-bucket-name>"
parsedRawFile: "<your-bucket-name>"
parseOutput: "<your-bucket-name>"
parsedFileScreenshot: "<your-bucket-name>"
extractOutput: "<your-bucket-name>"
parseFileUpload: "<your-bucket-name>"
parseFileOutput: "<your-bucket-name>"注意
共有十个键,但实际只需要八个不同的桶 —— parseFileUpload 与 parseFileOutput 默认与 parsedFileParsing 同桶(即 llama-platform-file-parsing)。这三个键可以都指向同一个桶。其余的键与要求一节下列出的桶一一对应。
进阶 S3 配置
使用 KMS 服务端加密或自定义 S3 兼容后端的部署,可能需要配置 S3 的签名版本。默认情况下平台交由 botocore 按地域自动决定。若你的桶用了 AWS KMS 加密、且预签名 URL 因签名版本错误而失败,就把 S3_SIGNATURE_VERSION 设为 s3v4:
config:
storageBuckets:
signatureVersion: "s3v4"注意
这通常只在使用 KMS 加密的 S3 桶、且 pod 环境里没有设 AWS_REGION 时才需要。IRSA 提供凭据,但不一定会设地域,这可能让 botocore 生成签名版本不对的预签名 URL。
另外,你也可以通过 extraEnvVariables 设置 AWS_REGION:
config:
storageBuckets:
extraEnvVariables:
AWS_REGION: "us-east-1"用 S3Proxy 连接 Azure Blob Storage 或其他提供方
LlamaCloud 最初是在 AWS 上开发的,也就是说我们从一开始就原生支持 S3。但要让自托管成为可能,就需要一条让平台能与其他提供方交互的路子。
我们借助开源项目 S3Proxy 把 S3 API 请求翻译成对其他存储提供方的请求。helm chart 里开箱支持以容器方式部署 S3Proxy。
只要 LlamaCloud 对接的是非 AWS 提供方(Azure Blob、GCS、MinIO 等),以及上文那条 AWS 的 access-key 路径,就必须用 S3Proxy。开启后,S3Proxy 会以边车形式部署在若干 LlamaCloud pod 上。
如果你在 AWS 上走的是**(推荐)IRSA** 那条路,就不需要 S3Proxy —— 平台会用服务账号角色原生与 S3 通信,因此可以把 config.storageBuckets.s3proxy.enabled 留着不设(false)。
下面是一个把 LlamaCloud 部署连到 Azure Blob Storage 的示例。更多连接不同提供方的例子,见该项目的示例页。
- 用 S3 Proxy 接 Azure Blob Storage
- 用 S3 Proxy 接 MinIO / S3 兼容存储
config:
storageBuckets:
provider: "azure"
s3proxy:
enabled: true
containerPort: 8080
config:
S3PROXY_ENDPOINT: "http://0.0.0.0:80"
S3PROXY_AUTHORIZATION: "none"
S3PROXY_IGNORE_UNKNOWN_HEADERS: "true"
S3PROXY_CORS_ALLOW_ORIGINS: "*"
JCLOUDS_PROVIDER: "azureblob"
JCLOUDS_REGION: "eastus" # Change to your region
JCLOUDS_AZUREBLOB_AUTH: "azureKey"
JCLOUDS_IDENTITY: "fill-out" # Change to your storage account name
JCLOUDS_CREDENTIAL: "fill-out" # Change to your storage account key
JCLOUDS_ENDPOINT: "fill-out" # Change to your storage account endpointMinIO、Ceph RADOS Gateway 以及其他 S3 兼容对象存储都用这一份配置,包括你在同一个集群里跑 MinIO 做本地评估部署的情形。
config.storageBuckets.provider 只接受 aws、gcp、azure 三个值,没有 S3 兼容这个选项。把它留作 aws 即可 —— 它只用于设置 CLOUD_PROVIDER 环境变量,并不决定 S3Proxy 是否运行。真正访问你的存储的是 S3Proxy,而它只看 s3proxy.enabled 这一个开关。
config:
storageBuckets:
provider: "aws" # sets CLOUD_PROVIDER only; S3Proxy does the talking
s3proxy:
enabled: true
containerPort: 8080
config:
JCLOUDS_PROVIDER: "s3"
JCLOUDS_IDENTITY: "<ACCESS-KEY>"
JCLOUDS_CREDENTIAL: "<SECRET-KEY>"
JCLOUDS_REGION: "us-east-1"
# In-cluster Service address of your store, reachable from the LlamaCloud pods
JCLOUDS_ENDPOINT: "http://minio:9000"请在安装 chart 之前,就在你的存储里建好要求一节列出的那八个桶,因为 S3Proxy 不会按需创建它们。
注意
S3Proxy 作为边车运行、指向 localhost,因此这个端点是在每个 pod 内部解析的。而交给浏览器的预签名 URL 也是按同一个端点生成的,这意味着只在集群内可达的存储无法为浏览器侧的下载服务。只要是本地评估之外的用途,就要把存储暴露在一个 pod 与你用户的浏览器都能访问的地址上。