[ PROMPT_NODE_24212 ]
Cloudflare Pulumi 部署常见问题与最佳实践
[ SKILL_DOCUMENTATION ]
# 故障排除与最佳实践
## 常见错误
### "No bundler/build step" - Pulumi 上传原始代码
**问题:** Worker 报错 "Cannot use import statement outside a module"
**原因:** Pulumi 不会打包 Worker 代码 - 它会直接上传你提供的原始文件
**解决方案:** 在 Pulumi 部署之前构建 Worker
```typescript
// 错误写法:Pulumi 不会打包此文件
const worker = new cloudflare.WorkerScript("worker", {
content: fs.readFileSync("./src/index.ts", "utf8"), // 原始 TS 文件
});
// 正确写法:先构建,后部署
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", {
content: build.stdout.apply(() => fs.readFileSync("./worker/dist/index.js", "utf8")),
}, {dependsOn: [build]});
```
### "wrangler.toml not consumed" - 配置漂移
**问题:** 本地 wrangler 开发正常,但 Pulumi 部署失败
**原因:** Pulumi 会忽略 wrangler.toml - 必须在代码中重复配置
**解决方案:** 从 Pulumi 生成 wrangler.toml 或手动保持同步
```typescript
// 模式:将 Pulumi 配置导出到 wrangler.toml
const workerConfig = {
name: "my-worker",
compatibilityDate: "2025-01-01",
compatibilityFlags: ["nodejs_compat"],
};
new command.local.Command("generate-wrangler", {
create: pulumi.interpolate`cat > wrangler.toml <<EOF
name = "${workerConfig.name}"
compatibility_date = "${workerConfig.compatibilityDate}"
compatibility_flags = ${JSON.stringify(workerConfig.compatibilityFlags)}
EOF`,
});
```
### "False no-changes detection" - 内容 SHA 未改变
**问题:** Worker 代码已更新,但 Pulumi 显示 "no changes"
**原因:** 内容哈希值完全一致(仅空格或注释更改)
**解决方案:** 添加构建时间戳或版本号以强制更新
```typescript
const version = Date.now().toString();
const worker = new cloudflare.WorkerScript("worker", {
content: code,
plainTextBindings: [{name: "VERSION", text: version}], // 强制触发新部署
});
```
### "D1 migrations don't run on pulumi up"
**问题:** D1 数据库创建后未应用数据库架构(Schema)
**原因:** Pulumi 仅创建数据库,不会自动运行迁移脚本
**解决方案:** 使用 Command 资源并配合 dependsOn
```typescript
const db = new cloudflare.D1Database("db", {accountId, name: "mydb"});
// 数据库创建后运行迁移
const migration = new command.local.Command("migrate", {
create: pulumi.interpolate`wrangler d1 execute ${db.name} --file ./schema.sql`,
}, {dependsOn: [db]});
// Worker 依赖于迁移完成
const worker = new cloudflare.WorkerScript("worker", {
d1DatabaseBindings: [{name: "DB", databaseId: db.id}],
}, {dependsOn: [migration]});
```
### "Missing required property 'accountId'"
**问题:** `Error: Missing required property 'accountId'`
**原因:** 资源配置中未提供 Account ID
**解决方案:** 添加到堆栈配置中
```yaml
# Pulumi..yaml
config:
cloudflare:accountId: "abc123..."
```
### "Binding name mismatch" - 绑定名称不匹配
**问题:** Worker 运行失败,报错 "env.MY_KV is undefined"
**原因:** Pulumi 中的绑定名称与 Worker 代码中的名称不一致
**解决方案:** 确保完全匹配(区分大小写)
```typescript
// Pulumi 配置
kvNamespaceBindings: [{name: "MY_KV", namespaceId: kv.id}]
// Worker 代码
export default { async fetch(request, env) { await env.MY_KV.get("key"); }}
```
### "API token permissions insufficient" - API 令牌权限不足
**问题:** `Error: authentication error (10000)`
**原因:** 令牌缺少必要的权限
**解决方案:** 授予令牌以下权限:Account.Workers Scripts:Edit, Account.Account Settings:Read
### "Resource not found after import" - 导入后找不到资源
**问题:** 导入的资源在下次执行 `pulumi up` 时显示已更改
**原因:** 实际资源与 Pulumi 配置之间的状态不匹配
**解决方案:** 检查属性名称/类型是否完全匹配
```bash
pulumi import cloudflare:index/workerScript:WorkerScript my-worker /
pulumi preview # 如果显示更改,请调整 Pulumi 代码以匹配实际资源
```
### "v6.x Worker versioning confusion" - 版本控制混淆
**问题:** Worker 已部署但未接收流量
**原因:** v6.x 架构需要 Worker + WorkerVersion + WorkersDeployment(3 个资源)
**解决方案:** 使用 WorkerScript(自动处理版本)或完整的版本控制模式
```typescript
// 简单方案:WorkerScript 自动处理版本(默认行为)
const worker = new cloudflare.WorkerScript("worker", {
accountId, name: "my-worker", content: code,
});
// 高级方案:手动版本控制以实现渐进式发布 (v6.x)
const worker = new cloudflare.Worker("worker", {accountId, name: "my-worker"});
const version = new cloudflare.WorkerVersion("v1", {
accountId, workerId: worker.id, content: code, compatibilityDate: "2025-01-01",
});
const deployment = new cloudflare.WorkersDeployment("prod", {
accountId, workerId: worker.id, versionId: version.id,
});
```
## 最佳实践
1. **始终设置 compatibilityDate** - 锁定 Worker 行为,防止破坏性变更。
2. **部署前构建** - Pulumi 不负责打包;请使用 Command 资源或 CI 构建步骤。
3. **匹配绑定名称** - 区分大小写,必须在 Pulumi 和 Worker 代码之间保持一致。
4. **为迁移使用 dependsOn** - 确保 D1 迁移在 Worker 部署之前完成。
5. **为 Worker 内容设置版本** - 添加 VERSION 绑定以在内容更改时强制重新部署。
6. **在堆栈配置中存储机密** - 使用 `pulumi config set --secret` 存储 API 密钥。
## 限制说明
| 资源 | 限制 | 备注 |
|----------|-------|-------|
| Worker 脚本大小 | 10 MB | 包含所有依赖项,压缩后 |
| Worker CPU 时间 | 50ms (免费版), 30s (付费版) | 每次请求 |
| 每个命名空间的 KV 键 | 无限制 | 1000 次/秒写, 10万次/秒读 |
| R2 存储 | 无限制 | A 类操作:100万次/月免费, B 类:1000万次/月免费 |
| D1 数据库 | 每个账户 50,000 个 | 免费版:每个账户 10 个,每个 5 GB |
| 队列 (Queues) | 每个账户 10,000 个 | 免费版:100万次操作/天 |
| Pages 项目 | 每个账户 500 个 | 免费版:100 个项目 |
| API 请求 | 视计划而定 | 免费版约 1200 次/5分钟 |
## 相关资源
- **Pulumi Registry:** https://www.pulumi.com/registry/packages/cloudflare/
- **API 文档:** https://www.pulumi.com/registry/packages/cloudflare/api-docs/
- **GitHub:** https://github.com/pulumi/pulumi-cloudflare
- **Cloudflare 文档:** https://developers.cloudflare.com/
- **Workers 文档:** https://developers.cloudflare.com/workers/
---
参见:[README.md](./README.md), [configuration.md](./configuration.md), [api.md](./api.md), [patterns.md](./patterns.md)
数据来源:claude-code-templates(MIT),中文翻译由 AI 生成。详见关于我们。
粤公网安备44030002003366号