☁️

cfft - CloudFront Functionsをテスト、デプロイ - fujiwara-ware 2024 day 7

2024/12/07に公開

この記事は fujiwara-ware advent calendar 2024 の7日目です。

cfft とは

https://github.com/fujiwara/cfft

cfft とは、CloudFront Functions(CFF)KeyValueStore(KVS) を管理、デプロイするためのツールです。

「しーえふえふてぃー」と読みます。

CloudFront Functions は、Amazon CloudFront においてリクエストやレスポンスを処理するための JavaScript ランタイムです(Lambda@Edge とは異なります)。

なぜ作ったのか

https://techblog.kayac.com/cfft-test-cloudfront-functions

3行でまとめると

  • CloudFront Functions のランタイムは非公開なので、手元でテストができなくて面倒
  • CloudFront KVS の扱いがちょっと面倒
  • テストとデプロイができるツールを作った

ということです。

ランタイムが非公開のため、手元や CI/CD 環境でコードを実行してテストができません。テストするためにはマネージメントコンソールを使うか、AWS API を呼び出すか AWS CLI を複数回組み合わせて叩く必要があります。これは大変面倒なため、テストやデプロイを自動化するためのツールを作りました。

使い方

詳しくはドキュメントを読んで頂くとして、できることは次の通りです。

ecspresso, lambroll など他の fujiwara-ware デプロイツールと同様に、既存のリソースをファイル化したり、diffを取ったりする機能があります。

  • cfft init: 既存のCFFを指定して、cfft 用の設定ファイルとコード、テストのための入力イベントを生成する
    • 関数が存在しない場合は新規にファイルを一式生成します
  • cfft test: CFFをファイルの内容で更新し、設定ファイルにしたがって入力イベントを元にテストを実行し、出力が期待したものかどうか検証する
  • cfft diff: ローカルのコードとCFF上のコードの差分を表示する
  • cfft render: ローカルのコードをレンダリングした結果を表示する
    • 設定ファイルとローカルのファイルはテンプレートとして処理され、環境変数の展開などが可能です
  • cfft publish: DEVELOPMENTステージでテストを実行した後、CFFをLIVEステージに公開する
  • cfft kvs: CloudFront KeyValueStoreの操作。list, get, put, delete, info コマンドがあります
  • cfft tf: Terraformとの連携機能

面白い機能

基本的な使い方は置いておいて、ちょっと面白い機能を紹介します。

複数の関数をひとつにまとめてデプロイ

CFF では、ひとつのビヘイビア(リクエストの処理)にはひとつの関数しか指定できません。しかし実運用においては、複数の関数を用意しておいて、リクエストされたpathによって組み合わせて使いたいことがあります。

例えば

  • 認証を行う関数(A)
  • URLの書き換えを行う関数(B)

があるとします。あるパスに対しては認証のみを行い(A)、別のパスに対しては認証+URLの書き換えを行いたい(A+B)場合、個別に関数を用意すると認証するためのコードが重複してしまいます。ひとつの関数にまとめると、URLの書き換えが必要ないリクエストを判断して処理をスキップするというコードが必要になります。

これでは運用もテストも面倒です。個別にテストした関数を用意しておいて、それらをまとめてデプロイする機能が cfft にはあります。

# cfft.yaml
name: combined-function
runtime: cloudfront-js-2.0 # required
function:
  event-type: viewer-request
  functions:
    - auth.js
    - rewrite.js
testCases:
# ...

function.functions に複数の関数ファイルを指定できます。このように書いておくと、cfft publishauth.jsrewrite.js がまとまったコードが自動で生成され、デプロイされます。

処理は functions に並べた順に行われ、auth.js が実行された結果が rewrite.js に引き継がれます。このようにして、複数の処理を連鎖することができます。便利ですね。

もちろんそれぞれの関数定義ファイルは、個別にテストを書いておくことができます。

name: auth
runtime: cloudfront-js-2.0
function:
  event-type: viewer-request
  functions:
    - auth.js
testCases:
# ...

Terraform との連携

cfft は CFF と KVS を管理するためのツールですが、CFF は CloudFront にデプロイする必要があります。CloudFront は別途なんらかの手段で管理する必要があります。

筆者は主に Terraform を用いて AWS のリソースを管理しているため、Terraform との連携ができると便利です。

cfft では、Terraform との連携方法を2種類用意しています。

tf.json を生成する方法

$ cfft tf > cff.tf.json

このコマンドを実行すると、cfft が管理している CFF の構成を Terraform リソースとして表現する JSON のファイルを生成します。このファイルを Terraform の .tf ファイルと同じディレクトリに置いておけば、Terraform でそのまま利用できます。

https://developer.hashicorp.com/terraform/language/syntax/json

Terraform の external data source として扱う方法

cfft tf --external を実行すると、external data sources(https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) から読み込める形式の JSON を標準出力に出力します。

Terraform 側では external data source を定義し、その出力をソースとして利用してリソースを定義できます。

data "external" "some-function" {
  program = ["cfft", "--config", "cfft.yaml", "tf", "--external"]
}

resource "aws_cloudfront_function" "some-function" {
  name    = data.external.some-function.result["name"]
  runtime = data.external.some-function.result["runtime"]
  code    = data.external.some-function.result["code"]
  comment = data.external.some-function.result["comment"]
  publish = true
}

まとめ

cfft は CloudFront Functions と KeyValueStore を管理、デプロイするためのツールです。テストやデプロイが面倒な CFF を簡単に扱えるようにするために作りました。Terraform との連携もサポートしています。ぜひお試しください。

それでは、明日もお楽しみに!

Discussion