【免费下载链接】superplane
Open source factory for one-shot engineering
Hetzner Object Storage 提供兼容 S3 的对象存储服务,Superplane 通过hetzner.s3技能包中的六个标准组件(createBucket、deleteBucket、uploadObject、deleteObject、listObjects、presignedUrl),让开发者可以在画布工作流中直接完成桶的创建与销毁、对象的读写与列举、以及临时访问链接的签发。读完本文,你将掌握这些组件的输入输出契约、参数取值范围与默认值,并能结合源码理解其底层 S3 签名与请求构造原理,直接在环境中编排 CI 产物归档、环境级联清理、多租户桶供给等自动化场景。
前置条件:为 Hetzner 集成配置 S3 凭据
在使用任意 S3 组件之前,Hetzner 集成必须同时配置三项 S3 凭据,它们与 Hetzner Cloud API Token 是相互独立的两套凭据:
- S3 Access Key ID:对象存储访问密钥 ID;
- S3 Secret Access Key:对象存储访问密钥(敏感字段);
- S3 Region:桶所在区域,取值为
fsn1(Falkenstein)或nbg1(Nuremberg)。
从集成源码 pkg/integrations/hetzner/hetzner.go 可以看到,集成配置结构体将 API Token 与三个 S3 字段分开建模:
type Configuration struct { APIToken string `json:"apiToken" mapstructure:"apiToken"` S3AccessKeyId string `json:"s3AccessKeyId" mapstructure:"s3AccessKeyId"` S3SecretAccessKey string `json:"s3SecretAccessKey" mapstructure:"s3SecretAccessKey"` S3Region string `json:"s3Region" mapstructure:"s3Region"` }在 UI 配置表单中(Configuration()方法,hetzner.go),s3AccessKeyId与s3SecretAccessKey被标记为Sensitive: true,属于敏感字段;s3Region是一个下拉选择字段,选项固定为fsn1(Falkenstein)与nbg1(Nuremberg),与文档中给出的取值完全一致。
凭据校验逻辑
Hetzner 集成在Sync阶段会对 S3 凭据做一次一致性校验(hetzner.go):
- 三个 S3 字段要么全部为空,要么全部填写——只要其中一个非空,其余两个必须同时提供,否则返回错误
s3AccessKeyId, s3SecretAccessKey, and s3Region must all be provided together; - 三者齐备时,会创建 S3 客户端并调用
ListBuckets()实际探测一次,验证凭据可用后才将集成标记为Ready()。
这意味着你无法只填 Access Key 而漏掉 Region 就保存集成,配置阶段的强校验可以避免后续组件运行时才暴露凭据缺失问题。
如何获取凭据
集成自带的Instructions()(hetzner.go)给出了获取路径:在 Hetzner Cloud Console →Object Storage中创建 S3 凭据(Access Key + Secret Key),并将 Region 设置为与桶位置匹配的fsn1或nbg1。API Token 则在 Console → Project → Security → API Tokens 中创建,需使用Read & Write权限范围,二者不能混用。
组件总览
hetzner.s3技能覆盖了对象存储的完整生命周期,六个组件均通过 S3 兼容 API 执行,注册于集成动作列表中(hetzner.go):
| 组件名 | 对应 S3 操作 | 用途 |
|---|---|---|
hetzner.createBucket | PUT /{bucket} | 创建桶 |
hetzner.deleteBucket | DELETE /{bucket} | 删除空桶 |
hetzner.uploadObject | PUT /{bucket}/{key} | 上传对象 |
hetzner.deleteObject | DELETE /{bucket}/{key} | 删除对象 |
hetzner.listObjects | GET /{bucket}?list-type=2 | 按前缀列举对象 |
hetzner.presignedUrl | SigV4 预签名 | 生成限时访问 URL |
下面逐个详解每个组件的适用场景、输入参数与输出契约。
hetzner.createBucket:创建桶
在环境搭建阶段预先供给存储桶,或为多租户供给流程创建租户专属桶。
输入参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
Bucket | 表达式 | 是 | 待创建桶的名称,支持表达式 |
输出
组件执行成功后会向默认通道发出hetzner.bucket.created事件(见 create_bucket.go),负载包含:
bucket:桶名称;region:Hetzner 区域(如fsn1);endpoint:完整的桶访问端点 URL,由客户端构造为https://{region}.your-objectstorage.com/{bucket}。
实现细节
CreateBucket的Execute会先对Bucket做去空格与空值校验(空桶名直接报错),然后调用 S3 客户端CreateBucket,其底层即PUT请求到桶端点,仅当响应为200 OK或204 No Content时才视为成功(hetzner_s3_client.go)。
hetzner.deleteBucket:删除桶
拆除临时环境桶(环境销毁后清理),或在工作流结束时清空测试桶。
输入参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
Bucket | 集成资源下拉框 | 是 | 要删除的桶,从集成已发现的bucket资源中选择 |
约束:桶必须为空才能删除。若桶内仍有对象,S3 服务端会返回错误,因此删除桶之前通常需要先删除其中的对象(可配合
listObjects+deleteObject实现"先清空、再删除"的级联清理)。
输出
发出hetzner.bucket.deleted事件,负载仅包含bucket(被删除的桶名称),见 delete_bucket.go。
实现细节
与创建桶对应,删除桶即DELETE /{bucket}请求,同样以200/204为成功判据(hetzner_s3_client.go)。该组件(以及deleteObject、listObjects、presignedUrl、uploadObject)的 Bucket 字段类型为FieldTypeIntegrationResource,资源类型为bucket——UI 会通过集成资源发现接口实时拉取账号下的桶列表(见 hetzner.go 的ListResources中case "bucket"分支),供下拉选择,也可以改用表达式动态指定。
hetzner.uploadObject:上传对象
向桶中写入对象内容,典型场景包括:
- CI 流水线结束后归档构建产物(编译输出、Docker 压缩包);
- 将工作流生成的报告或 JSON 载荷写入对象存储;
- 保存初始化脚本或配置文件,供环境搭建阶段后续使用。
输入参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
Bucket | 下拉框或表达式 | 是 | 目标桶 |
Key | 表达式 | 是 | 桶内对象键/路径,支持表达式,如artifacts/{{ $.run.id }}.json |
Content | 表达式 | 是 | 上传内容。字符串原样上传;对象/数组自动 JSON 序列化 |
Content Type | 字符串 | 否 | MIME 类型(如application/json、text/plain),默认application/octet-stream |
输出
发出hetzner.object.uploaded事件,负载包含bucket、key、size(字节数)、etag(服务端返回的 ETag),见 upload_object.go。
实现细节
Content的序列化逻辑非常明确(upload_object.go):字符串直接转字节;其余类型走json.Marshal。这保证了传入 Go 对象或数组时,上传到桶里的是结构化 JSON,而传入文本时则保持原样。
请求构造上,PutObject仅在显式提供了Content-Type时才设置该请求头(hetzner_s3_client.go),ETag 从响应头读取。Execute阶段对空Bucket、空Key、空Content均有前置校验。
hetzner.deleteObject:删除对象
删除桶中的指定对象,适用于:
- 部署后工作流中清理过期产物;
- 移除环境搭建阶段上传的临时文件。
输入参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
Bucket | 下拉框或表达式 | 是 | 对象所在桶 |
Key | 表达式 | 是 | 要删除的对象键,支持表达式 |
输出
发出hetzner.object.deleted事件,负载包含bucket、key(见 delete_object.go)。
实现细节
DeleteObject即DELETE /{bucket}/{key}请求(hetzner_s3_client.go)。对象键支持多段路径,客户端在构造 URL 时会对每一段路径分别做 URL 编码并保留/分隔符(encodeKeyPath,hetzner_s3_client.go),确保含特殊字符的键也能被正确寻址。
hetzner.listObjects:列举对象
列举桶内对象,支持前缀过滤,典型场景:
- 触发回滚路径前检查回滚产物是否存在;
- 作为合规/报告工作流的一部分审计桶内容;
- 将对象列表喂给下游处理循环。
输入参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
Bucket | 下拉框或表达式 | 是 | 要列举的桶 |
Prefix | 表达式 | 否 | 按键前缀过滤(如releases/) |
Max Keys | 数字 | 否 | 返回对象上限,默认 100,最大 400 |
输出
发出hetzner.objects.listed事件,负载包含(见 list_objects.go):
bucket、prefix:本次列举的桶与前缀;count:返回的对象数量;truncated:布尔值,为true说明maxKeys之外还有更多对象;objects:对象数组,每项为{ key, size, lastModified, etag }。
当truncated为true时,应缩小Prefix或增大Max Keys以看到剩余对象——这一提示同样写在了组件的内置文档中(list_objects.go)。
实现细节
ListObjects底层走的是 S3ListObjectsV2协议(请求参数list-type=2,并携带可选的prefix与max-keys,见 hetzner_s3_client.go),响应解析ListBucketResult下的Contents列表与IsTruncated标志。
Max Keys的 400 上限并非随意设定:源码注释解释了约束来源(list_objects.go)——每个条目会整体进入事件负载,而平台将事件负载上限设为 512KB;S3 键最长可达 1024 字节,取全部最长键的最坏情况(400 × 1024 字节量级)仍能控制在限值之下。同时 UI 表单将该字段的输入范围约束在1 ~ 400(默认 100)。
hetzner.presignedUrl:生成预签名 URL
为对象生成限时有效的预签名 URL,访问者无需任何凭据即可使用,典型场景:
- 工作流完成后,通过 Slack 或邮件分享生成的报告/构建产物;
- 允许外部 Agent 或 CI 系统向指定位置上传文件,而不授予永久访问权限;
- 为第三方系统提供产物的临时下载通道。
输入参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
Bucket | 下拉框或表达式 | 是 | 对象所在桶 |
Key | 表达式 | 是 | 对象键,支持表达式 |
Method | 下拉框 | 是 | GET(下载)或PUT(上传),默认GET |
Expires In | 数字 | 否 | 有效期(秒),默认 3600(1 小时),最小 60,最大 604800(7 天) |
输出
发出hetzner.object.presigned事件,负载包含(见 presigned_url.go):
bucket、key:目标对象;url:预签名 URL;expiresAt:过期时间(ISO 8601 时间戳,基于 UTC 当前时间 + 有效期计算)。
实现细节
Method在Setup与Execute两处都会被校验,只接受GET或PUT(大小写不敏感,自动转大写);Expires In小于等于 0 时回退为默认 3600 秒(presigned_url.go)。
URL 的签发使用 AWS SDK v4 签名器(hetzner_s3_client.go):先构造目标 URL,将有效期写入X-Amz-Expires查询参数,再以UNSIGNED-PAYLOAD模式执行PresignHTTP,最终返回可直接使用的签名 URL。这意味着presignedUrl发出的 URL 里已经嵌入了签名与过期时间,第三方拿到链接即可在有效期内直接下载或上传,无需共享 Secret Key。
底层原理:HetznerS3Client 与 SigV4 签名
所有六个组件最终都汇聚到同一个轻量级客户端 pkg/integrations/hetzner/hetzner_s3_client.go,理解它的构造方式有助于排查凭据与区域相关的问题:
端点推导。客户端不要求配置 endpoint,而是根据s3Region直接拼出https://{region}.your-objectstorage.com(hetzner_s3_client.go)。因此 Region 填写错误会导致所有请求指向不存在的区域端点,这也是它必须与桶实际位置匹配的原因。
SigV4 签名。请求统一使用 AWS Signature V4(s3Service = "s3")签名,区域取自配置的s3Region。值得注意的一个兼容性细节:代码注释明确指出 Hetzner Object Storage 底层的Ceph 要求X-Amz-Content-SHA256作为已签名请求头存在,因此doRequest会在签名前先设置该头(空请求体使用空体 SHA-256 常量,hetzner_s3_client.go),再交由v4.Signer.SignHTTP完成签名。
统一错误解析。非 2xx 响应会尝试将 XML 错误体解析为{ Code, Message },返回形如S3 error 409 (BucketNotEmpty): ...的带状态码与错误码的错误信息(parseS3Error,hetzner_s3_client.go),便于在画布上直接定位失败原因(例如删除非空桶触发的BucketNotEmpty)。
测试覆盖。仓库同时提供了客户端单元测试 pkg/integrations/hetzner/hetzner_s3_client_test.go,覆盖 S3 客户端的行为,可作为自定义扩展或排错的参考。
组合实战:一条"构建 → 归档 → 分享 → 清理"的完整链路
将上述组件按生命周期串联,即可在 Superplane 画布中构建一条端到端的产物管理流水线:
- 供给阶段:
hetzner.createBucket以表达式生成按运行唯一命名的桶(如artifacts-{{ $.run.id }}),输出bucket/endpoint供后续节点引用; - 归档阶段:CI 完成后,
hetzner.uploadObject将构建产物写入artifacts/{{ $.run.id }}.json,Content传入工作流生成的 JSON 载荷——非字符串内容会自动序列化,无需手工转义; - 分享阶段:
hetzner.presignedUrl生成GET方法、有效期 3600 秒的下载链接,将输出url与expiresAt通过 Slack 或邮件通知渠道发送,接收方无需任何对象存储凭据即可下载; - 审计阶段:
hetzner.listObjects以releases/为前缀检查回滚产物是否存在,并利用count与truncated判断是否需要继续列举或触发回滚分支; - 清理阶段:环境销毁时,先以
hetzner.deleteObject(配合listObjects枚举键)清空桶内对象,最后hetzner.deleteBucket删除空桶,完成临时环境的彻底回收。
这条链路恰好覆盖了技能文档中列举的全部"何时使用"场景,也体现了六个组件在真实工作流中的组合价值:从资源供给、数据写入、安全分享到最终回收,全程无需手工调用 API 或外挂脚本。
小结
hetzner.s3技能用六个语义清晰的组件把 Hetzner Object Storage 的 S3 兼容能力完整封装进 Superplane 工作流:创建/删除桶对应环境生命周期管理,上传/删除/列举对象覆盖产物流转,预签名 URL 提供无凭据的安全访问通道。每个组件的输入输出契约、默认值与取值范围都与源码实现一一对应(组件实现位于 pkg/integrations/hetzner/ 目录,S3 客户端与测试见 hetzner_s3_client.go 和 hetzner_s3_client_test.go),配置 S3 凭据时请务必牢记"三件套必须同时提供、Region 必须与桶实际位置一致"这两条规则,即可稳定地在画布上编排对象存储自动化。
【免费下载链接】superplane
Open source factory for one-shot engineering
相关推荐
3 分钟部署大麦自动抢票脚本:从扫码登录到自动下单
3 分钟部署大麦自动抢票脚本:从扫码登录到自动下单 开票第一秒,你手指还在刷新键上,票就没了。大麦抢票自动化系统(ticket purchase)用 Pytho
GUI 自动化RPA使用 Oracle Cloud Object Storage 作为 Velero 备份存储:S3 兼容 API 完整配置指南
使用 Oracle Cloud Object Storage 作为 Velero 备份存储:S3 兼容 API 完整配置指南 导读 本文以 Velero 仓库中
云原生灾备存储后端Velero(Ark)接入 IBM Cloud Object Storage:以 S3 兼容对象存储作为备份目的地的完整配置指南
Velero(Ark)接入 IBM Cloud Object Storage:以 S3 兼容对象存储作为备份目的地的完整配置指南 本文以 v0.9.0 时代(当
云原生灾备存储后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考