news 2026/9/12 5:39:53

Cloudflare Pulumi Provider 资源配置全解:用 @pulumi/cloudflare v6.x 管理 Workers、KV、D1、R2 与 Queues

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cloudflare Pulumi Provider 资源配置全解:用 @pulumi/cloudflare v6.x 管理 Workers、KV、D1、R2 与 Queues

Cloudflare Pulumi Provider 资源配置全解:用 @pulumi/cloudflare v6.x 管理 Workers、KV、D1、R2 与 Queues

【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills

本文以 skills 仓库中 cloudflare-deploy 技能 的 Pulumi 资源配置参考 为主体,系统讲解如何用 TypeScript 编写 Pulumi 程序,以 IaC 方式程序化创建 Cloudflare Workers 及其绑定资源。读完本文,你将掌握@pulumi/cloudflarev6.x 下 WorkerScript、Workers KV、R2、D1、Queues、Pages、DNS、自定义域名、静态资源托管以及 v6.x 版本化部署的完整配置写法,并理解 binding 名称匹配、依赖编排与常见排错要点,可直接照搬到自己的部署项目中。

一、配置之前:认证与 Stack 基础

configuration.md中的所有资源示例都依赖两个前置事实:一个可用的 Cloudflare Provider 实例,以及从 stack 配置中读取的accountId。这部分前置配置定义在配套的 pulumi/README.md 中,是整个资源配置能够运行的前提。

1. 认证方式(推荐 API Token)

官方推荐使用 API Token 而非旧的 API Key:

import * as cloudflare from "@pulumi/cloudflare"; // API Token(推荐):从 CLOUDFLARE_API_TOKEN 环境变量读取 const provider = new cloudflare.Provider("cf", { apiToken: process.env.CLOUDFLARE_API_TOKEN }); // API Key(旧式):CLOUDFLARE_API_KEY + CLOUDFLARE_EMAIL 环境变量 const provider = new cloudflare.Provider("cf", { apiKey: process.env.CLOUDFLARE_API_KEY, email: process.env.CLOUDFLARE_EMAIL }); // API User Service Key:CLOUDFLARE_API_USER_SERVICE_KEY 环境变量 const provider = new cloudflare.Provider("cf", { apiUserServiceKey: process.env.CLOUDFLARE_API_USER_SERVICE_KEY });

2. Stack 配置:accountId 与 apiToken 的存放位置

Pulumi.yaml中声明项目与运行时,并把 token 交给 Pulumi 配置系统:

# Pulumi.yaml name: my-cloudflare-app runtime: nodejs config: cloudflare:apiToken: value: ${CLOUDFLARE_API_TOKEN}

在每个环境的Pulumi.<stack>.yaml中存放账号 ID(accountId是绝大多数资源必填的属性):

# Pulumi.<stack>.yaml,例如 Pulumi.prod.yaml config: cloudflare:accountId: "abc123..."

在入口文件index.ts中通过pulumi.Config读取:

import * as pulumi from "@pulumi/pulumi"; import * as cloudflare from "@pulumi/cloudflare"; const accountId = new pulumi.Config("cloudflare").require("accountId");

3. 五项核心原则

来自 pulumi/README.md 的 v6.x 使用原则,贯穿本文所有示例:

  1. 使用 API Token 而非旧式 API Key;
  2. accountId存放在 stack 配置中;
  3. 让 binding 名称在代码与配置之间严格一致;
  4. Worker 使用module: true声明 ES modules;
  5. 始终设置compatibilityDate锁定运行时行为。

二、资源类型总览

@pulumi/cloudflarev6.x 中本文会涉及的常用资源类型(来自 pulumi/README.md):

资源类型对应 Cloudflare 产品用途
Provider——Provider 配置(认证)
WorkerScriptWorkers部署 Worker 脚本
WorkersKvNamespaceWorkers KV键值存储命名空间
R2BucketR2对象存储桶
D1DatabaseD1关系型 SQL 数据库
QueueQueues消息队列
PagesProjectPages全栈站点项目
DnsRecordDNSDNS 记录
WorkerRouteWorkers Routes基于 pattern 的路由
WorkersDomainWorkers Custom Domains专属子域名

关键公共属性:accountId(多数资源必填)、zoneId(DNS/域名必填)、name/title(资源标识符)、*Bindings(将资源连接到 Worker 的绑定族)。

三、Workers:cloudflare.WorkerScript 的完整配置

WorkerScript是部署 Worker 的核心资源,configuration.md给出的完整示例覆盖了从模块格式、兼容性配置到可观测性、Placement 与全部绑定类型:

import * as cloudflare from "@pulumi/cloudflare"; import * as fs from "fs"; const worker = new cloudflare.WorkerScript("my-worker", { accountId: accountId, name: "my-worker", content: fs.readFileSync("./dist/worker.js", "utf8"), module: true, // ES modules compatibilityDate: "2025-01-01", compatibilityFlags: ["nodejs_compat"], // v6.x: Observability logpush: true, // 启用 Workers Logpush tailConsumers: [{service: "log-consumer"}], // 将日志流式转发给另一个 Worker // v6.x: Placement placement: {mode: "smart"}, // Smart Placement 优化延迟 // Bindings kvNamespaceBindings: [{name: "MY_KV", namespaceId: kv.id}], r2BucketBindings: [{name: "MY_BUCKET", bucketName: bucket.name}], d1DatabaseBindings: [{name: "DB", databaseId: db.id}], queueBindings: [{name: "MY_QUEUE", queue: queue.id}], serviceBindings: [{name: "OTHER_SERVICE", service: other.name}], plainTextBindings: [{name: "ENV_VAR", text: "value"}], secretTextBindings: [{name: "API_KEY", text: secret}], // v6.x: Advanced bindings analyticsEngineBindings: [{name: "ANALYTICS", dataset: "my-dataset"}], browserBinding: {name: "BROWSER"}, // Browser Rendering aiBinding: {name: "AI"}, // Workers AI hyperdriveBindings: [{name: "HYPERDRIVE", id: hyperdriveConfig.id}], });

关键参数逐项说明

  • content:Worker 代码内容,直接读取构建产物(如./dist/worker.js)。这里有一个重要前提——Pulumi 不会帮你打包/bundle 代码,它只上传你提供的内容。这一点在 pulumi/gotchas.md 中有明确警告:如果直接读取原始index.ts而非构建后的 JS,Worker 会报Cannot use import statement outside a module。正确做法是先构建再部署(详见下文"实战编排"小节)。
  • module: true:声明 Worker 使用 ES modules 格式;对应的compatibilityFlags: ["nodejs_compat"]开启 Node.js 兼容层,便于使用node:*模块。
  • compatibilityDate:锁定 Worker 运行时的兼容性日期,防止 Cloudflare 侧行为变更造成破坏,是官方推荐必须设置的值。
  • logpush/tailConsumers(v6.x Observability)logpush: true启用 Workers Logpush 把日志推送到外部;tailConsumers则把实时日志流式转发给另一个 Worker(service指向其名称),适合日志消费/观测场景。
  • placement: {mode: "smart"}(v6.x):开启 Smart Placement,让 Worker 就近后端源站运行以优化延迟。
  • 绑定(Bindings)族:连接 KV / R2 / D1 / Queue / Service / 环境变量 / 密钥 / Analytics Engine / Browser Rendering / Workers AI / Hyperdrive。绑定名称(如MY_KVAPI_KEY)会注入 Worker 运行时的env对象中。

绑定名称必须精确匹配

gotchas.md 强调:绑定名称区分大小写,Pulumi 侧的name必须与 Worker 代码中env的引用完全一致,否则运行时会报env.MY_KV is undefined

// Pulumi 侧 kvNamespaceBindings: [{name: "MY_KV", namespaceId: kv.id}]
// Worker 代码侧 export default { async fetch(request, env) { await env.MY_KV.get("key"); }}

四、Workers KV:命名空间与键值写入

KV 由命名空间(namespace)与具体的键值(value)两层组成:

const kv = new cloudflare.WorkersKvNamespace("my-kv", { accountId: accountId, title: "my-kv-namespace", }); // 写入值 const kvValue = new cloudflare.WorkersKvValue("config", { accountId: accountId, namespaceId: kv.id, key: "config", value: JSON.stringify({foo: "bar"}), });

注意 KV 命名空间的资源标识字段是title(而非name),创建后通过kv.id引用;WorkersKvValue允许在 IaC 阶段就把初始化数据(如配置 JSON)写入命名空间,适合会话、缓存、配置类数据。

五、R2 Buckets:对象存储

const bucket = new cloudflare.R2Bucket("my-bucket", { accountId: accountId, name: "my-bucket", location: "auto", // 或 "wnam" 等地域标识 });

location: "auto"表示由 Cloudflare 自动选择存储地域;需要固定地域时可按供应商文档指定如wnam(西美)等取值。创建后用bucket.name注入 Worker 的r2BucketBindings

六、D1 数据库与迁移编排

创建 D1 数据库后,Pulumi不会自动执行迁移configuration.md给出的标准做法是结合@pulumi/commandcommand.local.Command资源,在数据库创建完成后用 wrangler CLI 执行 SQL:

const db = new cloudflare.D1Database("my-db", {accountId, name: "my-database"}); // 通过 wrangler 执行迁移 import * as command from "@pulumi/command"; const migration = new command.local.Command("d1-migration", { create: pulumi.interpolate`wrangler d1 execute ${db.name} --file ./schema.sql`, }, {dependsOn: [db]});

dependsOn: [db]显式声明依赖,确保数据库先创建、迁移后执行。同理,如果 Worker 依赖迁移完成后的表结构,应让 Worker 的d1DatabaseBindings所在资源dependsOn: [migration](详见 pulumi/api.md 的显式依赖示例)。

七、Queues:生产者与消费者配置

队列由Queue资源定义,生产者通过queueBindings写入,消费者通过queueConsumers订阅:

const queue = new cloudflare.Queue("my-queue", {accountId, name: "my-queue"}); // Producer:把消息写入队列 const producer = new cloudflare.WorkerScript("producer", { accountId, name: "producer", content: code, queueBindings: [{name: "MY_QUEUE", queue: queue.id}], }); // Consumer:异步消费 const consumer = new cloudflare.WorkerScript("consumer", { accountId, name: "consumer", content: code, queueConsumers: [{queue: queue.name, maxBatchSize: 10, maxRetries: 3}], });

消费者侧可配置的关键参数:maxBatchSize(单批最大消息数,示例为 10)、maxRetries(最大重试次数,示例为 3);在 patterns.md 的队列处理模式中还出现了maxWaitTimeMs: 5000(最长批量等待时间)。这一配置直接支撑"API 接收请求 → 队列削峰 → Worker 异步处理"的典型架构。

八、Pages Projects:全栈站点配置

PagesProject支持 Git 源自动构建与生产环境配置注入:

const pages = new cloudflare.PagesProject("my-site", { accountId, name: "my-site", productionBranch: "main", buildConfig: {buildCommand: "npm run build", destinationDir: "dist"}, source: { type: "github", config: {owner: "my-org", repoName: "my-repo", productionBranch: "main"}, }, deploymentConfigs: { production: { environmentVariables: {NODE_VERSION: "18"}, kvNamespaces: {MY_KV: kv.id}, d1Databases: {DB: db.id}, }, }, });

要点拆解:

  • buildConfig:声明构建命令(buildCommand)与产物目录(destinationDir),对应 Pages 的构建配置;
  • source:关联 GitHub 仓库(type: "github"+ 仓库所有者的config),配置后 Pages 支持 Git 触发自动部署;
  • deploymentConfigs.production:为生产环境注入环境变量(NODE_VERSION等)以及把 KV、D1 等资源绑定到 Pages 运行时,其中键(如MY_KVDB)就是 Pages Functions 侧引用的绑定名。

九、DNS Records:Zone 数据源与记录创建

需要先通过cloudflare.getZone数据源查询目标域名对应的 zone,再创建记录:

const zone = cloudflare.getZone({name: "example.com"}); const record = new cloudflare.DnsRecord("www", { zoneId: zone.then(z => z.id), name: "www", type: "A", content: "192.0.2.1", ttl: 3600, proxied: true, });
  • zoneId:通过getZone数据源异步获取(zone.then(z => z.id)拿到 Output 值);
  • type/content/ttl:记录类型、解析值、TTL(秒,3600 为 1 小时);
  • proxied: true:开启 Cloudflare 代理(橙色云朵),流量先经过 Cloudflare 边缘。

十、Workers Domains 与 Routes:流量接入的两种方式

把 Worker 暴露到域名有两种方式,按需选择:

// 方式一:Route(基于 pattern 的路由,作用于 Zone 内路径) const route = new cloudflare.WorkerRoute("my-route", { zoneId: zoneId, pattern: "example.com/api/*", scriptName: worker.name, }); // 方式二:Domain(专属子域名) const domain = new cloudflare.WorkersDomain("my-domain", { accountId: accountId, hostname: "api.example.com", service: worker.name, zoneId: zoneId, });
  • WorkerRoute:把某个域名下的路径模式(example.com/api/*)路由到指定 Worker,scriptName引用 Worker 的name
  • WorkersDomain:为 Worker 分配专属子域名(hostname),service指定 Worker 名称,需要accountIdzoneId同时提供。

十一、Assets 静态资源配置(v6.x)

v6.x 允许 Worker 直接托管本地静态资源目录,无需单独的对象存储:

const worker = new cloudflare.WorkerScript("app", { accountId: accountId, name: "my-app", content: code, assets: { path: "./public", // 本地目录,上传后由 Workers 直接托管 }, });

assets.path指向本地静态目录(如构建后的前端产物./public),Cloudflare 会将其中文件作为 Worker 的静态资源上传并服务,适合单仓库同时交付 API 与前端静态文件的场景。

十二、v6.x 版本化部署:三资源模式

v6.x 引入了 Worker 版本化机制。configuration.md给出的高级模式由三个资源协作,实现渐进式发布:

// 1. Worker:作为版本的容器 const worker = new cloudflare.Worker("api", { accountId: accountId, name: "api-worker", }); // 2. Version:不可变的代码 + 配置 const version = new cloudflare.WorkerVersion("v1", { accountId: accountId, workerId: worker.id, content: fs.readFileSync("./dist/worker.js", "utf8"), compatibilityDate: "2025-01-01", compatibilityFlags: ["nodejs_compat"], // 注意:Bindings 在 Deployment 层配置 }); // 3. Deployment:版本 + 绑定 + 流量分配 const deployment = new cloudflare.WorkersDeployment("prod", { accountId: accountId, workerId: worker.id, versionId: version.id, // Bindings 作用于 Deployment kvNamespaceBindings: [{name: "MY_KV", namespaceId: kv.id}], });

适用场景:蓝绿部署(blue-green)、金丝雀发布(canary)、渐进式灰度(gradual rollout)。结合 patterns.md 的示例,WorkersDeployment还可以通过versions数组按百分比切流:

// 渐进式发布:10% 流量到 v2,90% 到 v1 const deployment = new cloudflare.WorkersDeployment("canary", { accountId, workerId: worker.id, versions: [{versionId: v2.id, percentage: 10}, {versionId: v1.id, percentage: 90}], kvNamespaceBindings: [{name: "MY_KV", namespaceId: kv.id}], });

不适用场景:简单的单版本部署——此时应直接使用WorkerScript(自带自动版本管理,是绝大多数应用的默认选择)。gotchas.md 特别提醒:如果创建了Worker+WorkerVersion+WorkersDeployment但流量没有打到 Worker,往往是三资源链路不完整导致;简单场景务必回到WorkerScript

十三、实战编排:一个完整全栈应用的资源依赖

把以上资源串起来,参考 patterns.md 的 Full-Stack 模式,一个带 KV 缓存、D1 数据库、R2 对象存储的 API Worker 的完整编排如下:

const kv = new cloudflare.WorkersKvNamespace("cache", {accountId, title: "api-cache"}); const db = new cloudflare.D1Database("db", {accountId, name: "app-database"}); const bucket = new cloudflare.R2Bucket("assets", {accountId, name: "app-assets"}); const apiWorker = new cloudflare.WorkerScript("api", { accountId, name: "api-worker", content: fs.readFileSync("./dist/api.js", "utf8"), module: true, kvNamespaceBindings: [{name: "CACHE", namespaceId: kv.id}], d1DatabaseBindings: [{name: "DB", databaseId: db.id}], r2BucketBindings: [{name: "ASSETS", bucketName: bucket.name}], });

这里的依赖是隐式的:kv.iddb.idbucket.name作为 Input 传入绑定后,Pulumi 自动建立"Worker 依赖这三个资源"的关系(详见 api.md 的隐式依赖说明),无需手写dependsOn

另外两种与构建/部署强相关的编排模式:

先构建后部署(解决 Pulumi 不打包的问题):

import * as command from "@pulumi/command"; const build = new command.local.Command("build", {create: "npm run build", dir: "./worker"}); const worker = new cloudflare.WorkerScript("worker", { accountId, name: "my-worker", content: build.stdout.apply(() => fs.readFileSync("./worker/dist/index.js", "utf8")), }, {dependsOn: [build]});

内容版本强制刷新(解决"内容哈希未变导致误判无变更"的问题):

const version = Date.now().toString(); const worker = new cloudflare.WorkerScript("worker", { accountId, name: "my-worker", content: code, plainTextBindings: [{name: "VERSION", text: version}], // 强制触发新部署 });

gotchas.md 记录了此类问题的成因:当代码仅有空白/注释级别的变化时内容哈希相同,Pulumi 会误判"no changes",注入时间戳版本的plainTextBindings是推荐的规避手段。

十四、配置相关的常见错误速查

来自 pulumi/gotchas.md,与本文配置内容直接相关的几类高频问题:

报错/现象根因解法
Error: Missing required property 'accountId'资源未提供 accountIdPulumi.<stack>.yaml中添加cloudflare:accountId
env.MY_KV is undefinedPulumi 绑定名与 Worker 代码不一致严格按大小写对齐绑定名
Cannot use import statement outside a modulePulumi 直接上传了未构建的 TS 源码npm run build再用command.local.Command驱动部署
本地wrangler dev正常但pulumi up失败Pulumi 不读取wrangler.toml将 Pulumi 配置导出生成wrangler.toml,保持单一事实源
D1 建库后 schema 未生效Pulumi 只建库不跑迁移command.local.Command+dependsOn执行wrangler d1 execute
代码改了但 Pulumi 显示 "no changes"内容哈希未变注入VERSION时间戳绑定强制更新
认证报错authentication error (10000)Token 权限不足授予Account.Workers Scripts:EditAccount.Account Settings:Read等权限

推荐的最佳实践归纳:始终设置compatibilityDate;构建先于部署;绑定名大小写精确匹配;迁移用dependsOn串行;敏感信息通过pulumi config set --secret存入 stack 配置(在 state 中加密存储,见 api.md 的 Secrets 管理)。

十五、延伸阅读

  • 本技能入口与决策树:cloudflare-deploy/SKILL.md("我需要基础设施即代码"分支指向本参考)
  • Pulumi 参考整体导读与认证/Stack 配置:pulumi/README.md
  • 输出、依赖、导入与密钥管理:pulumi/api.md
  • 多环境、组件化资源、队列与微服务架构模式:pulumi/patterns.md
  • 排错与最佳实践:pulumi/gotchas.md
  • 相关替代方案:Terraform 参考 terraform/、CLI 部署参考 wrangler/、绑定体系 bindings/、Worker 运行时 workers/

【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 5:39:17

Deepagents快速实战:如何搭建一个能长跑任务的AI代理

Deepagents快速实战&#xff1a;如何搭建一个能长跑任务的AI代理 【免费下载链接】deepagents The batteries-included agent harness. 项目地址: https://gitcode.com/GitHub_Trending/de/deepagents Deepagents是一个MIT许可的开源AI代理框架&#xff0c;构建在LangGr…

作者头像 李华
网站建设 2026/9/12 5:35:25

hyperframes:用硬件抽象让机器人驱动与算法彻底解耦

先说结论&#xff1a;如果你在做轮式或四足机器人&#xff0c;并且已经受够了“调完底盘驱动&#xff0c;一换板子全得重写”的日子&#xff0c;hyperframes 这套硬件抽象思路值得你花一个晚上认真研究。我在自己的底盘项目里把它跑通之后&#xff0c;最大的感受是——它解决的…

作者头像 李华
网站建设 2026/9/12 5:34:05

GIMP专业图像处理全流程指南

1. 项目概述&#xff1a;当GIMP成为数字游侠的瑞士军刀十年前我第一次接触GIMP时&#xff0c;它还是个被Photoshop光芒掩盖的开源图像处理工具。如今这款完全免费的软件已经进化成能够独立完成专业级图像创作的利器。这次我想分享如何仅用GIMP完成从基础修图到复杂合成的全流程…

作者头像 李华