尽管所有 Terraform 部署都是独一无二的,但遵循这些最佳实践可以让您顺利取得成功。
当 Terraform 管理资源的所有更改和生命周期时,它的效果最佳。
在对配置进行任何操作之后,Terraform 尝试通过将远程内容同步到本地状态来协调差异。如果本地和远程之间存在差异——由在 Terraform 之外管理资源引起——您可能需要在状态文件中删除并重新创建资源(通常通过导入),因为并非所有资源都支持就地更新。
Cloudflare 建议使用一种结合账户、区域和产品来进行更改隔离的目录结构。此设置让您可以拥有细粒度的所有者以及作用于区域中特定产品的范围受限的 Terraform 操作。通过为单独的状态文件分配权限,它还可以使所有者与 Cloudflare 的默认角色以及其他工具(如 AWS 或 GCP 存储)更加紧密地结合。
对于包含许多职责的产品(例如规则集),您可以通过在阶段级别(WAF、重定向、源规则)进行分区来进一步扩展。
example-tf/
├── demo_account_a # per account segregation of resources
│ ├── users # top level directory for account members as they are "zoneless"
│ │ ├── provider.tf # `provider.tf` is for configuring the providers
│ │ ├── users.tf # `<subject>.tf` (users.tf) is for managing the individual resources
│ │ └── vars.tf # manage all variables for this component
│ ├── zone_a # group all zone based features together
│ │ ├── dns # individual (or grouped, your choice) of products or features to manage together
│ │ │ ├── dns.tf # `<subject>.tf` (dns.tf) is for managing the individual resources
│ │ │ ├── provider.tf # `provider.tf` is for configuring the providers
│ │ │ └── vars.tf # manage all variables for this component
│ │ └── page_rules # ... same as above but for Page Rules
│ │ ├── page_rules.tf
│ │ ├── provider.tf
│ │ └── vars.tf
│ ├── zone_b
│ │ ├── dns
│ │ │ ├── dns.tf
│ │ │ ├── provider.tf
│ │ │ └── vars.tf
│ │ └── page_rules
│ │ ├── page_rules.tf
│ │ ├── provider.tf
│ │ └── vars.tf
│ └── zone_c
│ ├── dns
│ │ ├── dns.tf
│ │ ├── provider.tf
│ │ └── vars.tf
│ └── page_rules
│ ├── page_rules.tf
│ ├── provider.tf
│ └── vars.tf
└── demo_account_b
├── users
│ ├── provider.tf
│ ├── users.tf
│ └── vars.tf
├── zone_a
│ ├── dns
│ │ ├── dns.tf
│ │ ├── provider.tf
│ │ └── vars.tf
│ └── page_rules
│ ├── page_rules.tf
│ ├── provider.tf
│ └── vars.tf
├── zone_b
│ ├── dns
│ │ ├── dns.tf
│ │ ├── provider.tf
│ │ └── vars.tf
│ └── page_rules
│ ├── page_rules.tf
│ ├── provider.tf
│ └── vars.tf
└── zone_c
├── dns
│ ├── dns.tf
│ ├── provider.tf
│ └── vars.tf
└── page_rules
├── page_rules.tf
├── provider.tf
└── vars.tfTerraform 模块是一种在抽象接口中使用逻辑封装多个资源的方法。考虑这样一个示例,其中模块使用池、一些 DNS 条目以及可能的页面规则设置默认负载平衡器。最终用户可能会像这样使用它:
module "example" "an_example_site" {
domain = "example.com"
origin_ip = "192.168.0.1"
}然而,在 Terraform 资源方面,上面的示例将被翻译为:
resource "cloudflare_record" "example_1" {
zone_id = var.cloudflare_zone_id
name = "terraform"
value = "198.51.100.11"
type = "A"
ttl = 3600
}
resource "cloudflare_record" "example_2" {
zone_id = var.cloudflare_zone_id
name = "terraform"
value = "198.51.100.12"
type = "A"
ttl = 3600
}
resource "cloudflare_record" "example_3" {
zone_id = var.cloudflare_zone_id
name = "terraform"
value = "198.51.100.13"
type = "A"
ttl = 3600
}
resource "cloudflare_load_balancer" "bar" {
zone_id = var.cloudflare_zone_id
name = "example-load-balancer.example.com"
fallback_pool_id = cloudflare_load_balancer_pool.foo.id
default_pool_ids = [cloudflare_load_balancer_pool.foo.id]
description = "example load balancer using geo-balancing"
proxied = true
steering_policy = "geo"
pop_pools {
pop = "LAX"
pool_ids = [cloudflare_load_balancer_pool.foo.id]
}
country_pools {
country = "US"
pool_ids = [cloudflare_load_balancer_pool.foo.id]
}
region_pools {
region = "WNAM"
pool_ids = [cloudflare_load_balancer_pool.foo.id]
}
rules {
name = "example rule"
condition = "http.request.uri.path contains \"testing\""
fixed_response {
message_body = "hello"
status_code = 200
content_type = "html"
location = "www.example.com"
}
}
}
resource "cloudflare_load_balancer_pool" "example_lb_pool" {
name = "example-lb-pool"
origins {
name = "example-1"
address = "198.51.100.1"
enabled = true
}
}
resource "cloudflare_page_rule" "example_page_rule" {
zone_id = var.cloudflare_zone_id
target = "sub.${var.cloudflare_zone}/page"
priority = 1
actions {
ssl = "flexible"
email_obfuscation = "on"
}
}虽然方便,但此设置可能会导致意外问题。如果此模块是共享的然后在其内部发生了更改,则模块可能会出现资源不同步或被重新创建的情况。
使用模块还会增加调试或复现问题的难度,因为您必须在 Terraform 核心和 Cloudflare 提供程序之外将潜在的逻辑错误纳入考量因素。
Cloudflare 建议使用 cf-terraforming 将现有资源迁移到 Cloudflare 中。
完全可以在 Terraform 内部管理一些资源,而使用不同的工具管理其他资源,但请确保您不要对同一资源同时执行这两种操作。
为了安全地管理独立的环境(阶段环境、QA、UAT、生产环境),请使用独立的 Cloudflare 账户以及独立的域名(例如 example.com 和 example-staging.com)。
这是因为在账户级别定义的一些产品是共享的(例如负载平衡器监视器和池),如果它们在同一账户中,您无法对它们进行隔离的更改。如果您打算测试 DNSSEC 等内容(配置不当可能会影响您的整个域),使用独立的账户也是有好处的。
为了尽量减少漂移,请使用跨两个域运行的 Terraform 和 CI/CD 管道,以在需要时保持它们同步。
我们不建议将 Cloudflare 凭据存储为纯文本。
在本地,您可以使用 cf-vault ↗ 等第三方工具来存储您的 Cloudflare 凭据。
对于 CI 管道,请使用内部或机密存储工具(例如 Vault ↗)。