尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Cloudflare Terraform Patterns:用 IaC 落地多环境架构与 CI/CD 实战指南

Cloudflare Terraform Patterns:用 IaC 落地多环境架构与 CI/CD 实战指南 Cloudflare Terraform Patterns用 IaC 落地多环境架构与 CI/CD 实战指南【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills本指南以 cloudflare-deploy 技能中 patterns.md 为骨架系统讲解用 Cloudflare Terraform Provider 构建生产级基础设施的架构模式从推荐的目录结构、多环境编排、R2 远程状态后端到 Worker 全绑定写法、Wrangler 职责边界与 CI/CD 流水线最后给出静态站点 API、多区域负载均衡、Access 安全管控与可复用模块四类真实场景。读完你可以在自己的 Cloudflare 账号上直接落地一套可复制、可扩展、可审计的基础设施即代码工程。为什么需要一套 Terraform 模式Cloudflare 平台面广Zone、DNS、Workers、KV、R2、D1、Pages、Access、Load Balancer……如果靠控制台手点或临时脚本拼凑环境一多必然失控。用 Terraform Provider 统一管理能得到版本化、可评审、可回滚的声明式基础设施。在 terraform/README.md 中项目给出了五条核心原则Provider 优先所有基础设施都用 Terraform 管理绝不让同一资源被wrangler.jsonc重复声明远程状态团队环境必须使用远程状态S3、Terraform Cloud 等模块化架构为 Zone、Workers、Pages 等常见模式创建可复用模块版本锁定始终用~锁定 Provider 版本保证升级可预期密钥管理敏感数据走变量与环境变量绝不硬编码 API Token。本文的 patterns.md 就是在这套原则之上回答目录怎么摆、环境怎么隔离、状态放哪里、Wrangler 和 Terraform 怎么分工、真实业务怎么组合这几个落地问题。推荐的目录结构environments modules shared多环境是 IaC 的第一道门槛。文档推荐如下布局terraform/ ├── environments/ │ ├── production/ │ │ ├── main.tf │ │ └── terraform.tfvars │ └── staging/ │ ├── main.tf │ └── terraform.tfvars ├── modules/ │ ├── zone/ │ ├── worker/ │ └── dns/ └── shared/ # Shared resources across envs └── main.tf要点拆解environments/ 按环境隔离production/与staging/各自持有一份main.tf与terraform.tfvars同一套模块代码、不同变量取值从物理目录层面杜绝改错环境modules/ 沉淀公共模式zone/域名与 DNS、worker/Worker 脚本与绑定、dns/记录模板等模块被各环境引用shared/ 放跨环境共享资源例如多环境共用的 Access 策略、审计相关配置只维护一份。需要特别留意文档中的NoteCloudflare recommends avoiding modules for provider resources due to v5 auto-generation complexity. Prefer environment directories shared state instead.也就是说由于 v5 Provider 由 OpenAPI 自动生成、资源定义高度自动化的特性不要过度封装模块——把环境目录 共享状态作为首选方案模块只用于确实重复度高的模式下文可复用模块一节会给出适度封装的范例。多环境编排一套模块多套实例在environments/{production,staging}/main.tf中通过source指向模块并为每个环境传入不同变量如environment、name后缀实现同一模块、两套资源# Directory: environments/{production,staging}/main.tf modules/{zone,worker,pages} module zone { source ../../modules/zone; account_id var.account_id; zone_name example.com; environment production } module api_worker { source ../../modules/worker; account_id var.account_id; zone_id module.zone.zone_id name api-worker-prod; script file(../../workers/api.js); environment production }模块输出module.zone.zone_id直接作为下游模块输入形成依赖链先建 Zone 拿到zone_id再创建绑定在该 Zone 上的 Worker。配合terraform.tfvars里的环境差异变量域名、环境名、资源后缀terraform apply即可分别产出 staging 与 production 两套完全隔离的资源。从源码结构看这与 api.md 中跨模块引用 data source的模式互为补充——数据源用于查询已存在资源模块输出用于传递新建资源。R2 状态后端免费且 S3 兼容的远程状态团队协作时本地terraform.tfstate会导致状态冲突与并发问题。文档给出的方案是把状态放到 Cloudflare R2S3 兼容对象存储用backend s3直接对接 R2 的 S3 兼容端点terraform { backend s3 { bucket terraform-state key cloudflare.tfstate region auto endpoints { s3 https://account_id.r2.cloudflarestorage.com } skip_credentials_validation true skip_region_validation true skip_requesting_account_id true skip_metadata_api_check true skip_s3_checksum true } }逐项说明这些跳过参数的作用R2 不是真实 AWS因此必须跳过凭证校验skip_credentials_validation、区域校验skip_region_validation、请求账号 IDskip_requesting_account_id、Metadata API 探测skip_metadata_api_check与 S3 校验和skip_s3_checksum否则 backend 初始化会误判为 AWS 环境而失败。endpoints.s3指向account_id.r2.cloudflarestorage.comregion auto与 R2 的无区域特性对应。这样所有协作者共享同一份状态文件配合terraform plan/apply可避免状态漂移。Worker 全绑定写法KV、R2、D1、Secret 一网打尽生产 Worker 几乎必然要挂存储与密钥。文档给出一个满配示例同时创建 KV Namespace、R2 Bucket、D1 Database 并全部绑定到 Workerlocals { worker_name full-stack-worker } resource cloudflare_workers_kv_namespace app { account_id var.account_id; title ${local.worker_name}-kv } resource cloudflare_r2_bucket app { account_id var.account_id; name ${local.worker_name}-bucket } resource cloudflare_d1_database app { account_id var.account_id; name ${local.worker_name}-db } resource cloudflare_worker_script app { account_id var.account_id; name local.worker_name; content file(worker.js); module true compatibility_date 2025-01-01 kv_namespace_binding { name KV; namespace_id cloudflare_workers_kv_namespace.app.id } r2_bucket_binding { name BUCKET; bucket_name cloudflare_r2_bucket.app.name } d1_database_binding { name DB; database_id cloudflare_d1_database.app.id } secret_text_binding { name API_KEY; text var.api_key } }几个实操要点先建资源、再取 IDKV/R2/D1 资源先创建再通过.id/.name属性回填到 bindingTerraform 自动处理依赖顺序module true与compatibility_dateES Module 格式的 Worker 需要显式声明module true并固定compatibility_date示例为2025-01-01避免运行时特性随日期漂移Secret 走变量secret_text_binding的text引用var.api_key密钥通过环境变量或 tfvars 注入与 README.md 的密钥管理原则一致。关于 v5 的绑定类型configuration.md 给出了更完整的表格可按需选用BindingAttribute示例KVkv_namespace_binding{ name KV, namespace_id ... }R2r2_bucket_binding{ name BUCKET, bucket_name ... }D1d1_database_binding{ name DB, database_id ... }Serviceservice_binding{ name AUTH, service auth-worker }Secretsecret_text_binding{ name API_KEY, text ... }Queuequeue_binding{ name QUEUE, queue_name ... }Vectorizevectorize_binding{ name INDEX, index_name ... }Hyperdrivehyperdrive_binding{ name DB, id ... }AIai_binding{ name AI }Browserbrowser_binding{ name BROWSER }Analyticsanalytics_engine_binding{ name ANALYTICS, dataset ... }mTLSmtls_certificate_binding{ name CERT, certificate_id ... }另外 configuration.md 还推荐生产环境使用渐进式发布Gradual Rolloutscloudflare_workercloudflare_worker_version带content_sha256 filesha256(worker.js)cloudflare_workers_deploymentversions { percentage 100 }三层组合支持按百分比灰度比一条cloudflare_workers_script直接覆盖更适合作线上发布。Wrangler 与 Terraform 的分工边界文档用CRITICAL标注了最容易踩的坑Wrangler and Terraform must NOT manage same resources.职责划分如下Terraform 负责Zone、DNS、安全规则、Access、负载均衡、Worker 部署CI/CD 场景、KV/R2/D1 资源的创建Wrangler 负责本地开发wrangler dev、手动部署、D1 迁移、KV 批量操作、日志流式查看wrangler tail。这一分工是有底层原因的两者都拥有对同一资源的所有权同时操作会造成状态冲突。文档在 gotchas.md 中明确列出对应报错——409 Conflict on worker deployment 的根因正是Worker 被 Terraform 与 wrangler 同时部署解法是只保留一种部署方式。同理D1 的 Schema 迁移 Terraform 不负责它只创建数据库资源需要在terraform apply之后手动执行wrangler d1 migrations apply db-name。CI/CD 模式Terraform 建资源envsubst 注入wrangler 部署最稳妥的流水线是Terraform 只建资源与输出 IDWrangler 只部署代码。先看 Terraform 侧如何暴露关键 ID# Terraform creates infrastructure resource cloudflare_workers_kv_namespace app { account_id var.account_id; title app-kv } resource cloudflare_d1_database app { account_id var.account_id; name app-db } output kv_namespace_id { value cloudflare_workers_kv_namespace.app.id } output d1_database_id { value cloudflare_d1_database.app.id }再在 GitHub Actions 中串联三个步骤# GitHub Actions: terraform apply → envsubst wrangler.jsonc.template → wrangler deploy - run: terraform apply -auto-approve - run: | export KV_NAMESPACE_ID$(terraform output -raw kv_namespace_id) envsubst wrangler.jsonc.template wrangler.jsonc - run: wrangler deploy执行顺序与作用terraform apply -auto-approve确保 KV Namespace、D1 等基础设施存在terraform output -raw kv_namespace_id读取刚创建的资源 ID通过envsubst把wrangler.jsonc.template中的${KV_NAMESPACE_ID}占位符替换为真实 ID生成wrangler.jsoncwrangler deploy用注入好 ID 的配置部署 Worker。这套模式的精髓在于把资源 ID这种运行时才知道的值通过 Terraform output 作为唯一事实来源single source of truth注入部署配置避免在仓库里硬编码 ID也让 Terraform 与 Wrangler 各管一摊、互不越界。真实场景用例场景一静态站点 API Worker前端用 Pages 构建部署Git 集成自动构建后端 API 用 Worker 承载DNS 与路由统一由 Terraform 编排resource cloudflare_pages_project frontend { account_id var.account_id; name frontend; production_branch main build_config { build_command npm run build; destination_dir dist } } resource cloudflare_worker_script api { account_id var.account_id; name api; content file(api-worker.js) d1_database_binding { name DB; database_id cloudflare_d1_database.api_db.id } } resource cloudflare_dns_record frontend { zone_id cloudflare_zone.main.id; name app; content cloudflare_pages_project.frontend.subdomain; type CNAME; proxied true } resource cloudflare_worker_route api { zone_id cloudflare_zone.main.id; pattern api.example.com/*; script_name cloudflare_worker_script.api.name }解读Pages 项目声明build_command/destination_dir由平台完成构建cloudflare_dns_record用 Pages 生成的subdomain作为 CNAME 目标cloudflare_worker_route用api.example.com/*把 API 流量路由到 Worker。需要给 Pages 项目挂自定义域名或绑定 KV/D1 时可参考 configuration.md 的cloudflare_pages_domain与deployment_configs写法。场景二多区域负载均衡用geo策略把流量按地理区域路由到不同池子实现就近访问与故障隔离resource cloudflare_load_balancer_pool us { account_id var.account_id; name us-pool; monitor cloudflare_load_balancer_monitor.http.id origins { name us-east; address var.us_east_ip } } resource cloudflare_load_balancer_pool eu { account_id var.account_id; name eu-pool; monitor cloudflare_load_balancer_monitor.http.id origins { name eu-west; address var.eu_west_ip } } resource cloudflare_load_balancer global { zone_id cloudflare_zone.main.id; name api.example.com; steering_policy geo default_pool_ids [cloudflare_load_balancer_pool.us.id] region_pools { region WNAM; pool_ids [cloudflare_load_balancer_pool.us.id] } region_pools { region WEU; pool_ids [cloudflare_load_balancer_pool.eu.id] } }关键点monitor引用健康检查HTTP 探测/health池子只接收健康来源default_pool_ids是兜底池region_pools按 Cloudflare 区域代码如WNAM北美西、WEU欧洲西覆盖路由。健康检查、池、负载均衡的完整定义如interval、timeout可对照 configuration.md 的 Load Balancers 一节。场景三用 Access 保护管理后台对 Pages 部署的 admin 站点套一层 Zero Trust Access只有指定邮箱可访问resource cloudflare_pages_project admin { account_id var.account_id; name admin; production_branch main } resource cloudflare_access_application admin { account_id var.account_id; name Admin; domain admin.example.com; type self_hosted; session_duration 24h allowed_idps [cloudflare_access_identity_provider.google.id] } resource cloudflare_access_policy allow { account_id var.account_id; application_id cloudflare_access_application.admin.id name Allow admins; decision allow; precedence 1; include { email var.admin_emails } }含义access_application声明受保护的应用type self_hosted、会话时长 24h、允许的 IdPaccess_policy定义放行规则decision allow、按邮箱白名单、precedence决定规则优先级。IdP如 Google、GitHub的完整配置参考 configuration.md 的 Access 一节cloudflare_access_identity_provider需配置client_id/client_secret。场景四可复用 Zone 模块在确认模块确实被多环境复用的前提下可以适度封装。文档给出一个最小的 Zone 模块# modules/cloudflare-zone/main.tf variable account_id { type string }; variable domain { type string }; variable ssl_mode { default strict } resource cloudflare_zone main { account { id var.account_id }; name var.domain } resource cloudflare_zone_settings_override main { zone_id cloudflare_zone.main.id; settings { ssl var.ssl_mode; always_use_https on } } output zone_id { value cloudflare_zone.main.id } # Usage: module prod { source ./modules/cloudflare-zone; account_id var.account_id; domain example.com }模块对外暴露account_id、domain、ssl_mode默认strict三个输入与zone_id一个输出内部把 Zone 创建与 SSL/HTTPS 设置固化使用方一行module prod即可接入。注意文档建议的权衡——模块只封装高复用逻辑其余尽量用环境目录直写避免为 Provider v5 的自动生成能力增加无谓的间接层。落地时的常见坑速查结合 gotchas.md 与本篇模式文档实战中高频出现的问题包括v5 资源改名cloudflare_record→cloudflare_dns_record、cloudflare_worker_script→cloudflare_workers_script复数、cloudflare_access_*→cloudflare_zero_trust_*升级后需用terraform state mv迁移旧状态R2 位置大小写location必须大写WNAM、ENAM、WEUR、EEUR、APAC小写会导致第二次 apply 失败Pages 项目持续漂移deployment_configs会被 Cloudflare API 回填默认值加lifecycle { ignore_changes [deployment_configs] }Secret 显示为 REDACTEDWorker 的secret_text_binding状态漂移用ignore_changes忽略Worker 脚本超限脚本加依赖超过 10 MB 会部署失败需要代码分割、外置依赖或压缩DNS record already exists线上已存在的记录未导入状态用terraform import cloudflare_dns_record.example zone-id/record-id导入完整导入 ID 格式见 api.md。进一步阅读本技能内 Terraform 参考文档的完整阅读顺序建议terraform/README.mdProvider 安装、认证API Token 优先于 Global Key、常用命令与 cf-terraforming 导入terraform/configuration.mdZone/DNS、Workers含渐进式发布、KV/R2/D1、Pages、Rulesets、Load Balancer、Access 全量资源配置terraform/api.md数据源查询已存在资源、跨模块引用、Import ID 格式本文patterns.md多环境、状态后端、Wrangler 分工与 CI/CD 模式terraform/gotchas.md状态漂移、v5 破坏性变更、常见报错与资源配额。在更大的 cloudflare-deploy 技能里Terraform 属于Infrastructure as Code分支pulumi/为替代方案api/为 REST 直调它与 wrangler 的分工边界正是本文的核心约束Terraform 管资源与编排Wrangler 管开发、迁移与调试二者永不管理同一资源。【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表