Fastlyの環境をTerraformで管理する

# はじめに
この記事は[ZOZOテクノロジーズ #2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech2)の16日目の記事となります。

今年、ZOZOテクノロジーズでは全部で5つのAdvent Calendarが公開されています。

[ZOZOテクノロジーズ #1 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech)
[ZOZOテクノロジーズ #2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech2)
[ZOZOテクノロジーズ #3 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech3)
[ZOZOテクノロジーズ #4 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech4)
[ZOZOテクノロジーズ #5 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech5)

様々な記事が投稿されていますので、皆様お時間有りましたら是非ご覧ください。

# 概要
ZOZOテクノロジーズでSREチームにてオンプレ基盤の運用をしている @EnKUMA です。
最近ではPublicCloudやCI/CD、k8sを使うプロジェクトに参加しておりオンプレミスとはまた違ったインフラに挑戦しております。

今回は業務にてFastlyの検証を行う事になったので検証時の履歴管理や運用後のCI/CDを想定してTerraformにて構成管理を試してみました。

# Fastlyとは？
[Fastly](https://www.fastly.com/build-on-fastly)は近年採用事例が多くなっているCDNです。
国内でのCDNといえば負荷分散を主目的とするものが多かったですが、最近ではA/Bテストやカナリアリリーステスト等をする際のアクセス振り分けを行うものとして運用されているケースも多くあるかと思います。
Fastlyはその様な運用をCI/CDで行う際にVCLをimportする事で設定を変更する事ができ、とても相性が良いサービスとなっております。
また、vclを使った事前cache処理等の実装も可能であり、Fastlyの機能をフルに使った[dev.to](https://dev.to/)はあまりの速さにオフラインページと思うほどの高速レスポンスを実現しております。

## VCLとは？
VCLは[Varnish Configuration Language](https://varnish-cache.org/docs/trunk/users-guide/vcl.html)の略であり、FastlyではVCLをimportする事でCDN設定を管理/運用させる事ができます。
_厳密に言うとFastlyのVarnish構文は多少[独自の機能](https://docs.fastly.com/ja/vcl/custom-vcl/creating-custom-vcl/)が追加されたカスタムバージョンとなります_

これによりCI/CD系ツールとの相性が良く、継続的インテグレーションを行う事ができます。
VCLによりアクセスのヘッダー情報による処理の変更やcookie付与&cookieによるアクセス振り分けといった処理を任意に記載する事ができる為、A/Bテストやカナリアテストといった運用を比較的簡単に実装する事ができます。

## Terraformとは？
[Terraform](https://www.terraform.io/)はHashicorp社が作成したインフラをコード管理するためのプロダクトです。最近では各種パブリッククラウドが対応してきており比較的触ったことがある方が多いかと思います。
2015年より[Fastly対応](https://www.hashicorp.com/blog/hashicorp-fastly/)が進んでおり、[GitHub](https://github.com/terraform-providers/terraform-provider-fastly)では現在も開発が進んでおります。

FastlyやCloud以外でも様々[SaaSやOSSに対応](https://www.terraform.io/docs/providers/index.html)しており、今後のインフラ設計では大きなポイントなりそうです。

# VCL作成
今回はA/Bテストを想定してPCとスマートフォンにてアクセスするホストを切り替える設定をTerraformにて構成管理します。

## PCとSPにてアクセスするホストを切り替える設定を作成する
FastlyではカスタムVCLを使って各種設定をimportします。
_Fastlyの基本設定もVCLで保存されている為、ユーザーが処理だけを記載するVCLはカスタムVCLと呼ばれます_

A/Bテストのsample-vclは[Fastlyの公式](https://docs.fastly.com/en/guides/delivering-different-content-to-different-devices)により提供されているのでそちらを使います。

上記公式ページの下部にあるデバイス判定のvclをdevicedetect.vclとして保存します。
また、main.vclとして[ボイラープレート](https://docs.fastly.com/ja/vcl/custom-vcl/creating-custom-vcl/)に下記編集をしたものを保存します。

```
include "detect_device"

sub vcl_recv {
  call detect_device;
 
  if (req.http.X-UA-Device ~ "desktop") {
    set req.url = "/pc.txt";
  } elsif (req.http.X-UA-Device ~ "smartphone") {
    set req.url = "/sp.txt";
  }
```

これでカスタムVCLの準備はできました。

# Terraform作成
## Terraformのディレクトリ構成を検討する。
構築するTerraformのディレクトリ構成を検討します。
今回は特に要件もなかったので下記ディレクトリ構成としました。
※ベストプラクティスがあれば教えて下さい。

```
fastly-tf
├── tf
│   └── fastly-dev.tf
└── vcl
    ├── detect_device.vcl
    └── main.vcl
```

## Terraformの実ファイル(tfファイル)を作ってみる
Hashicorpが公開している[公式マニュアル](https://www.terraform.io/docs/providers/fastly/r/service_v1.html)を参考に簡単なtfファイルを書いてみました。

```hcl
# Configure the Fastly Provider
provider "fastly" {
  api_key = "hogehogehogehoge"
}
 
resource "fastly_service_v1" "dev" {
  name = "dev-fastly"
 
  domain {
    name    = "dev-fastly.hogehoge.jp"
    comment = "terraform-dev"
  }
 
  backend {
    address = "XX.XX.XX.XX"
    name    = "A-Host"
    port    = 80
  }
 
  backend {
    address = "XX.XX.XX.XX"
    name    = "B-Host"
    port    = 80
  }
 
  force_destroy = true
 
  vcl {
    name    = "main"
    content = "${file("../vcl/main.vcl")}"
    main    = true
  }
 
  vcl {
    name    = "detect_device"
    content = "${file("../vcl/detect_device.vcl")}"
  }
}
```

ご覧の通りVCLの構造自体は人が見て理解しやすい記法となっております。
tfファイル作成時の注意点としては下記。

- Fastlyの管理画面にある「Account API tokens」より、APIキーを取得して記載する必要がある
- force_destroyは作成したresourceを削除できるかの設定
- vclを投入する場合は主となるvclに `main = true` のパラメータを付与する事
    - こちらを指定しないとvclが正常に読み込まれません
- 主となるvclに他のカスタムvclをincludeする

作成したtfファイルをapplyすればFastlyの環境構築は完了です。

![qiita_fastly_mosaic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528118/be1a7811-c1d8-d6dc-8e3f-c2d2e9c084ec.png)

# 悩んだ部分
## カスタムVCLとSnippetについて
設定となるVCLを編集する方法としてFastlyではSnippet呼ばれる機能もあります。
どちらも同じ様な設定を実装できるのでどのように使い分けるかを迷いました。
マニュアルやサポートさんとの話をまとめると下記が良いと考えています。

- 特定のSERVICE(Domain)に単発的な処理を加えたい場合はSnippet
- 複数のSERVICE(Domain)に跨るような設定等を行う際はカスタムVCL

## VCL記法の職人芸
VCLの構造自体は見やすいのですが、より詳細な設定をしていくとサブルーチン処理の分岐が多いことも有り複雑な点が多いと感じました。
Fastly側でも[Fiddle](https://fiddle.fastlydemo.net/)というvclのテストサイトを用意しているのでうまく活用する事が重要です。

# まとめ
今回はテストも兼ねてシンプルな要件で作成しましたがFastlyをTerraformで管理するための一通りの流れは把握できました。

初めてTerraformにてFastlyの構成管理を行いましたが、Domain / Host(origin) / csutomVCL とFastlyの構成要素をそれぞれ設定できるので、Terraformにて構成管理を完結する事ができるのでとても便利です。

SaaSサービスの利用はproduction環境がメインとなり、Git等で行われる『設定変更履歴管理』や『承認フローの作成』が可能かどうかはSaaS選定の重要なファクターになってくると思います。
FastlyとTerraformの組み合わせはそれらの要件をしっかりと満たす事ができるので有効な選択肢ですので、皆様も是非お試しください。