電話でのお問い合わ

Fastly 無料トライアル

Terraform を使った Fastly サービスの設定方法

必要に応じてコントロールパネル、コマンドラインインターフェイス、APIどを通じて Fastly サービスの設定を行う一方で、アプリケーションのコードの進化と並行して設定を反映させ、追跡することも重要です。エッジで構築をする機会が増えるに従い、アプリケーションやインフラストラクチャへ変更をデプロイするのと同じように、エッジロジックをデプロイすることがより重要になります。クラウドサービスによってインフラストラクチャとソフトウェアの境界線が曖昧になる中、複数のベンダーのサービスに対してコードや設定の変更を1つのバージョンにまとめてデプロイする方法がいっそう必要となります。Fastly サービスにも当てはまるこの原則を利用することを Infrastructure as Code (IaC)言います。

以前今人気のツール Terraform使って継続的デプロイのパイプラインの構築方法を紹介しましたが、FastlyバージョンレスリソースWAFサードパーティのログエンドポイント、TLSCompute@Edgeサポートを強化すべく、機能の反復的な改善を続けてきました。今回は、Terraform使用して Fastly サービスの設定、管理、デプロイを行う際の全体的なプロセスとベストプラクティスを紹介します。

まずTerraform使って簡単な VCL サービス作成します。このサービスは、人気のリクエスト/レスポンスのテストサイト https://httpbin.org前に透過プロキシとしてまず配置されます (つまり httpbinプロキシされる前はリクエストオブジェクトへの変更は行われません)。その後、プログラムロジックをエッジで実行するための変更を行います。

今回のデモでは、以下のステップを行います。

  • 登録 : Fastly アカウントを作成し、API キーを生成する

  • 記述 : Terraform コードで要件を定義する

  • 実行 : Terraform CLI使って要件を計画実行する

  • 検証 : Web ブラウザを開き、サービスが正し動作していることを確認する

  • 変更 : 定義されたリソースを変更し、新たなプランを生成して再度実行する

これらのステップを頭の中でたどれるように、こちらの図で全体的なワークフローをわかりやすくまとめています。

Configuring Fastly services with Terraform jp

Fastlyアカウントを作成する

まずは、Fastlyアカウントを作成します。アカウントの作成は無料です。最大50ドル分のトラフィックを無料で試すことができます。アカウント作成後、ログインして Fastly API トークンを作成します。これは個々のユーザーに関連づけられた固有の認証情報です。ユーザーに代わって Fastly API とやり取りするために、このトークンを Terraform プロバイダーに渡す必要があります。

Terraform 設定を記述する

次に、お好きなコードエディターで新し Terraform ファイルを作成します。ファイルを main.tf名付け、以下のコードを加えます。

terraform {
  required_providers {
    fastly = {
      source  = "fastly/fastly"
      version = "~> 0.30"
    }
  }
}

resource "fastly_service_v1" "test_service" { 
 name = "An Example Service"

  domain {
    name = "<name>.global.ssl.fastly.net"
  }

  backend {
    address = "httpbin.org"
    name     = "My Test Backend"
  }

  force_destroy = true
}

output "active" {
  value = fastly_service_v1.test_service.active_version
}

今回はセットアップを素早く済ますためにコードを一つのファイルにまとめましたが、プロジェクトの進展につれてコードを別々のファイルに分割した方が管理しやすくなると思います。

上記のコードは、さまざまなブロックやコンテナを name { ... }示してコンテンツを整理することができる HashiCorp Configuration Language (HCL)書かれています。上記の例では3つのトップレベルブロックがあります。

1. terraform
2. resource
3. output

terraform ブロックは、使用する Terraform プロバイダーのリストを定義します。今回、私たちが使用するのは Fastly Terraform プロバイダー です。

ヒント : バージョン制約について詳しくは、Terraform ドキュメントを覧ください。

resource ブロック一つ以上のインフラオブジェクトを示します。上記の設定では、Terraform プロバイダーによって提供され、新し VCL サービスの作成に必要な fastly_service_v1いう特定のリソース 「test_service」と表示される)定義されています。このリソースには2つのブロック domain backendネストされています。これらのブロックは、どのドメイン名に対して VCL サービスがリクエストを処理するべきか、そして最終的にどのバックエンドサービスがリクエストを処理すべきか判断するために必要になります。Terraform使用の有無にかかわらず、すべての Fastly サービスでこの2つの設定が最低限必要です。

このデモでは、domain 値の <name> 部分を固有の名前に変更します。変更しない場合、ドメイン名が他のサービスによってすでに使用されているというエラーが表示される恐れがあります。

output ブロックでは、インフラストラクチャのデプロイ完了後に Terraform表示する値を定義することができます。例えば、バージョン番号など、デプロイによって変わ値がよく使われます。

fastly_service_v1 リソースによって active_version 属性が生成され、サービスが正常に作成有効化された後にその値が明らかになります。Terraform コード内の active表示された output ブロックに割り当てられた値は、アクティブなバージョンへのアクセスを可能にする HCLプログラム表現です。

以下のシンタックスでリソース内の属性値を参照することができます。

<resource_type>.<resource_label>.<resource_attribute>

特定の Fastly リソースに関する属性はすべて、そのリソースの Fastly Terraform プロバイダーのドキュメント確認できます。

Terraform実行してプランを生成する

Terraform設定が完了したら、Terraform CLIインストールします。インストール後、ターミナルで以下を実行すると利用可能なコマンドをすべて表示することができます。

$ terraform -help

そのコマンドの一つである init は、現在使用中の作業ディレクトリ Terraform プロジェクトを初期化します。先ほど main.tf ファイルを作成した同じディレクトリで以下を実行します。

$ terraform init

この初期化ステップによって、Terraform required_providers ブロックで指定されたすべてのプロバイダーのダウンロードを開始します。後で新しプロバイダーを追加する必要が生じた場合は、新しプロバイダーを参照するように main.tfアップデートし、terraform init再度実行します。

Terraform main.tf設定を使用し、意図した状態を実現するために必要な操作を示す「実行計画」を生成します。そして、Terraform記述されたインフラストラクチャを構築するべく、計画を実行します。その際、Terraform代理として Fastly API とやり取りするため、先ほど作成した Fastly API トークンを Terraform提供する必要があります。API トークンを環境変数としてシェルにエクスポートして Terraform実行計画を生成し、内容を確認します。

$ export FASTLY_API_KEY="====PUT YOUR TOKEN HERE===="
$ terraform plan

まだこの設定が Fastly サービスに対してデプロイされていないため、この出力ではさまざまなリソースが未作成であることが示されています。

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:

  + create

Terraform will perform the following actions:

  # fastly_service_v1.test_service will be created
  + resource "fastly_service_v1" "test_service" {
      + activate              = true
      + active_version        = (known after apply)
      + cloned_version        = (known after apply)
      + comment               = "Managed by Terraform"
      + default_host          = (known after apply)
      + default_ttl           = 3600
      + force_destroy         = true
      + id                    = (known after apply)
      + name                  = "An Example Service"

      + backend { 
          + address                = "httpbin.org"
          + auto_loadbalance       = true
          + between_bytes_timeout  = 10000
          + connect_timeout        = 1000
          + error_threshold        = 0
          + first_byte_timeout     = 15000
          + max_conn               = 200
          + name                   = "My Test Backend"
          + port                   = 80
          + ssl_check_cert         = true
          + use_ssl                = false
          + weight                 = 100
        }

      + domain {
          + name = "<name>.global.ssl.fastly.net"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + active = (known after apply)

出力の最後の数行を見ると、作成予定のリソースが1つあり、変更や削除予定のリソースがないことが分かります。

プロバイダーは、サービスとドメイン、バックエンドを (設定内にネストされたブロックに基づいて) 作成します。fastly_service_v1 リソースで複数のブロックを定義したにもかかわらず、Terraform 側では作成するリソースは一つのみであることが示されています。

内容に間違いがなければ計画を実行します。

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

...<snip>...

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:

すると、先ほどと同じ出力と、計画の実行を確認するプロンプトが表示されます。「Yes」と入力し、Enter キーを押します。残りの出力にはステータスアップデートが表示されます。

  Enter a value: yes

fastly_service_v1.test_service: Creating...
fastly_service_v1.test_service: Still creating... [10s elapsed]
fastly_service_v1.test_service: Still creating... [20s elapsed]
fastly_service_v1.test_service: Creation complete after 29s
[id=2Z2KJsHtnsNGkGpafGVdbx]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

active = 1

最後の方にある「Outputs:」セクションには、main.tf定義した active出力変数が表示されています。この値が1と表示されているのは、今回作成されたサービスがバージョン1であることを示しています。

ヒント : CI システムなどの自動化された環境で Terraform使用している場合、apply サブコマンドに -auto-approve フラグを使用することで、プロンプトに対して「yes」と手動で入力するステップを省くことができます。

設定を検証する

サービス設定で定義したドメインに基づいて Fastly生成する特別なテスト URL使って、サービス設定への変更を検証することができます。

https://<name>.global.ssl.fastly.net

例えば、ドメインの <name> example設定されている元の Terraform コードが実行された場合、テスト URL次のようになります。

https://example.global.ssl.fastly.net

新し設定が有効になるまで最大60秒程度かかる場合があります。設定完了後、テスト URLそのバックエンドとして設定されている https://httpbin.org/同じコンテンツを表示します。この場合 Terraform コードのサービスリソースではカスタム VCL コード定義されていませんが、Fastlyデフォルト VCL使用されます。デフォルト VCL指定されたバックエンドに対するリクエストをプロキシし、レスポンスのキャッシュを自動的に処理するなど、合理的か安全に動作します。

設定を変更する

では、Terraformコードに新しブロックを追加してみましょう。カスタム VCL ファイルを表す新しブロックを fastly_service_v1追加します。その際、創造力を活かして工夫しながらエッジで実行したロジックのカスタム VCL ファイルを書くことができますが、今回のデモでは簡単なファイルを使います。

まずは main.tf同じディレクトリ内に vcl ディレクトリを作成し、その中に main.vcl ファイルを追加します。

$ mkdir vcl && touch vcl/main.vcl

次に、main.vcl ファイルに以下の VCL コードを入力します。

sub vcl_recv {
  #FASTLY recv

  if (req.url.path == "/anything/here") {
    set req.http.X-CustomHeader = "example";
  }

  if (req.url.path == "/anything/not/found") {
    error 600;
  }

  return(lookup);
}

sub vcl_error {
  #FASTLY error
  if (obj.status == 600) {
    set obj.status = 404;
    set obj.http.Content-Type = "text/html";
    synthetic {"<h1>Not Found</h1>"};
    return(deliver);
  }
}

このカスタム VCL単純ながら、Terraform でも VCL アップデートの管理が可能であることを示します。この VCL コードには2つの明確なロジックが含まれています。

  1. /anything/here対するリクエストを受信した場合、リクエストにカスタム HTTP ヘッダーを追加する (httpbin.org /anything/始まるパスに対して 200 OK と、リクエストの詳細を含む JSON レスポンスを返します)。

  2. /anything/not/found対するリクエストを受信した場合、通常 httpbin返す 200 OK レスポンスの代わりに 404 Not Foundシンセティックレスポンスを返す。

ヒント : カスタム VCL記述やテストには Fastly Fiddle便利です。また、Developer Hub VCL関するページもぜひご覧ください。

次に、fastly_service_v1 リソースに以下のような vcl ブロックを追加して Terraform コードを変更します。

resource "fastly_service_v1" "test_service" {
  ...<snip>...

  vcl {
    content = file("vcl/main.vcl")
    main      = true
    name     = "custom_vcl"
  }

  ...<snip>...
}

変更が完了したら、plan apply コマンドを再実行します。

$ terraform plan

vcl追加が出力に反映されているはずです。

fastly_service_v1.test_service: Refreshing state...[id=2Z2KJsHtnsNGkGpafGVdbx]

An execution plan has been generated and is shown below.

Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # fastly_service_v1.test_service will be updated in-place
  ~ resource "fastly_service_v1" "test_service" {
        id             = "2Z2KJsHtnsNGkGpafGVdbx"
        name           = "An Example Service"
        # (5 unchanged attributes hidden)

      + vcl {
          + content = <<-EOT
                sub vcl_recv {
                  #FASTLY recv

                  if (req.url.path == "/anything/here")
                    set req.http.X-CustomHeader = "example";
                  }

                  if (req.url.path == "/anything/not/found")
                    error 600;
                  }
                  return(lookup);
                }

                sub vcl_error {
                  #FASTLY error

                  if (obj.status == 600) {
                    set obj.status = 404;
                    set obj.http.Content-Type = "text/html";
                    synthetic {"<h1>Not Found</h1>"};
                    return(deliver);
                  }
                }
            EOT
          + main    = true
          + name    = "custom_vcl"
        }
        # (2 unchanged blocks hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

まず「Refreshing state...」の部分に注目してください。Terraformステートは、インフラストラクチャと設定のキャッシュです。このステートは、Terraform 設定にて定義された要件を実際の環境と比較するのに使用されます。このステートをリフレッシュすることで、Terraform最新のリソースの内容に基づく実行計画を算出することができます。

次に、最後の行に注目してください。変更すべきものが一つあると表示されています。これは、fastly_service_v1 リソースの設定変更が行われることを示しています (Terraformステートの変更をチルダ記号~使って表します)。

また、この差分出力は既存のネストされたブロックの一部が未変更であることを示すと同時に、新たに追加された行にプラス記号 +使用して表示しています。Terraform 設定は file 関数を使ってプロジェクトディレクトリの VCL ファイルにアクセスしましたが、実行計画を算出する場合はファイルのコンテンツをインラインし、それが差分出力に表示されます。

Terraform表示した実行計画に間違いがなければ、変更を適用します (今回は「yes」と手動で入力せず、-auto-approve フラグを使ってみてください)。

$ terraform apply --auto-approve

変更適用後新たな設定が Fastlyネットワーク全体にデプロイされ、VCL定義されたエンドポイントが新しルールに基づいて動作し始めるまでに20秒ほどかかります。

これで最初のパス /anything/hereでは "X-Customheader": "example"カスタムヘッダーが httpbin.org からの JSON レスポンスに表示され、2つ目のパス /anything/not/foundでは VCL コードによって生成される 404 Not Foundシンセティックレスポンスが返されるようになりました。これでサービス設定と VCL コードが正し動作していることが確認できました。

これで完了です!ざっくりまとめると、今回のデモでは Terraform 設定を使って Fastly サービスのカスタム要件を定義し、実際に Fastly リソースを作成する実行計画を生成し、実行しました。その後、サービスリソースへの変更を完全に可視化コントロールしながら、典型的なアップデートライフサイクルを実行しました。

次のステップ

VCL利用することで、Terraform Fastly 両方の機能を有効に活かすことができます。さらに、WebAssemblyパワー活用し、Rust AssemblyScriptどの言語からコンパイルされた安全なカスタムバイナリを実行する Compute@Edge サービス管理することも可能です。Compute@Edge Terraform駆使して Fastly最大限に活用する方法については、Terraform Fastly Terraform プロバイダーを使ったオーケストレーション関するページと Fastly Terraform ドキュメントをご覧ください

この投稿を共有する