Terraform のデプロイはそれぞれ異なります。次のベストプラクティスに従うと、成功しやすくなります。
Terraform は、リソースへのすべての変更とライフサイクルを自身で管理するときに、最もうまく動作します。
設定に対する操作のあと、Terraform はリモートの状態をローカルのステートに同期し、差分を解消しようとします。Terraform の外でリソースを管理した結果、ローカルとリモートに差がある場合は、ステートファイル上でリソースを削除して再作成する必要があります(通常は import を使います)。すべてのリソースがインプレース更新に対応しているわけではありません。
Cloudflare は、アカウント、ゾーン、プロダクトを組み合わせて変更を分離するディレクトリ構成を推奨します。この構成では、所有者を細かく分け、Terraform の操作をゾーン内の特定プロダクトに限定できます。所有者を Cloudflare の デフォルトロール に近づけやすく、AWS や GCP のストレージなどでも、ステートファイルごとに権限を分けられます。
Rulesets のように責任範囲が広いプロダクトでは、フェーズ単位(WAF、リダイレクト、Origin Rules)でさらに分割できます。
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 レコード、Page Rule をモジュールで用意するケースを考えます。利用者は次のように使います。
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 プロバイダーの外側にもロジックの不具合が入りうるため、問題の切り分けや再現が難しくなります。
既存のリソースを Terraform に取り込むには、cf-terraforming の利用を推奨します。
一部のリソースを Terraform で管理し、ほかを別のツールで管理しても問題ありません。ただし、同じリソースを両方で管理しない ようにしてください。
ステージング、QA、UAT、本番など、環境を安全に分けるには、別々の Cloudflare アカウントと別々のドメイン(example.com と example-staging.com など)を使います。
アカウントレベルで定義するプロダクトの一部(Load Balancer のモニターやプールなど)は共有されるため、同じアカウント内では分離した変更ができません。DNSSEC のように、設定を誤るとドメイン全体に影響するものを試す場合も、アカウントを分けると安全です。
ドリフトを抑えるには、両方のドメインに対して動く Terraform と CI/CD パイプラインを使い、必要に応じて同期します。
Cloudflare の認証情報を平文で保存することは推奨しません。
ローカルでは、cf-vault ↗ などのサードパーティツールで Cloudflare の認証情報を保管できます。
CI パイプラインでは、社内のシークレット保管ツール(Vault ↗ など)を使います。