Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

ベストプラクティス

最終更新 Markdown で表示Agent セットアップ

Terraform のデプロイはそれぞれ異なります。次のベストプラクティスに従うと、成功しやすくなります。

Terraform のリソースは 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.tf

モジュールは避ける(または控えめに使う)

Terraform モジュールは、複数のリソースとロジックを抽象化したインターフェースにまとめる方法です。たとえば、デフォルトのロードバランサーとプール、いくつかの 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 に移行する

既存のリソースを Terraform に取り込むには、cf-terraforming の利用を推奨します。

一部のリソースは Terraform の外で管理する

一部のリソースを Terraform で管理し、ほかを別のツールで管理しても問題ありません。ただし、同じリソースを両方で管理しない ようにしてください。

環境を分ける

ステージング、QA、UAT、本番など、環境を安全に分けるには、別々の Cloudflare アカウントと別々のドメイン(example.comexample-staging.com など)を使います。

アカウントレベルで定義するプロダクトの一部(Load Balancer のモニターやプールなど)は共有されるため、同じアカウント内では分離した変更ができません。DNSSEC のように、設定を誤るとドメイン全体に影響するものを試す場合も、アカウントを分けると安全です。

ドリフトを抑えるには、両方のドメインに対して動く Terraform と CI/CD パイプラインを使い、必要に応じて同期します。

認証情報は安全に保管する

Cloudflare の認証情報を平文で保存することは推奨しません。

ローカルでは、cf-vault などのサードパーティツールで Cloudflare の認証情報を保管できます。

CI パイプラインでは、社内のシークレット保管ツール(Vault など)を使います。

役に立ちましたか?