AWS LambdaをTerraformでIaCしようとするとロジックとインフラが密結合になる現象をどうするか

VoicyのSRE、せんちゃんこと千田です。

普段はよくオムライスを作っています!

本記事では、AWS LambdaのIaCについて書いています。

VoicyではIaCにTerraformを使っているのですが、Lambdaの管理に課題感を持っています。

本記事は「こうすれば完璧!」というベストプラクティスの説明ではなく、複数のパターンを提示した上で、「いまVoicyではこうなっているよ」という現状を紹介します。

最初に結論だけを述べると、インフラをTerraformで作成し、コードは別リポジトリで管理、デプロイ操作のためだけにServerless Frameworkを使用しています。

Voicyの実行環境

まず、Voicyというサービスやバックエンドの環境について、とてもざっくりと説明します。

Voicyは、パーソナリティが収録した音声をリスナーが聴けるプラットフォームです。

大きく分けて、リスナー向けの「Voicy (再生アプリ) 」と、パーソナリティ向けの「Voicy Recorder (収録アプリ) 」という2つのアプリが存在します。

データ分析基盤を除くほとんどすべてのサービスはAWS上で動作しています。

主な実行環境は以下の通りです。 ひとことで言えば、主要なものはにEKS、サブ的なものにはLambdaを使用しています。

  • Amazon Elastic Kubernetes Service (EKS)
    • 主要なアプリケーションのバックエンドAPIが動いている
    • Cronjobによる定期実行タスクも動いている
  • AWS Lambda
    • 主に、イベントドリブンでAPIとは非同期に実行される一連のタスクに使用されている
    • 音声処理やプッシュ通知配信など

また、現在はほとんど使用されていませんが、比較的古い時期に作られた一部のバッチやAPIは、EC2やElastic Beanstakでも動作しています。

以上がVoicyの実行環境です。

LambdaをIaC管理するときに使えるツールたち

Terraform

AWSに限らず、いろいろなプラットフォームのリソースをコード管理できるIaCのデファクトスタンダードです。 WebサービスAWSだがデータ分析はGCPなど、複数のクラウドを使っている場合でも、同じ文法で記述できるという利点があります。 Terraformでは、HCL (Hashicorp Configuration Language) という専用の言語を使います。

TerraformでLambdaを管理しようとすると、以下のように実行ファイルを指定する必要があり、インフラ定義とロジックを独立に管理することが難しいです。

resource "aws_lambda_function" "my_lambda" {
  filename      = "lambda_function_payload.zip"
  # 以下略
}

また、事前にコンパイル等を行って実行ファイルを作成した上で、terraform apply する必要があります。

CloudFormation

AWS専用のIaCツールです。JSONYAMLでリソースを定義することできます。複雑なリソースを定義しようと行数が多くなって大変なので、最近は次に紹介するCDKの使用が推奨されています。詳細は省略します。

Cloud Development Kit (CDK)

内部的にはCloudFormationが使用されています。 2022年10月現在、JavaScript、TypeScript、PythonJavaC#で書くことができます。 開発者プレビューではGoもサポートされています (VoicyはバックエンドをGoで書いています) 。 CloudFormationよりも少ない行数でシンプルに記述できます。

個人的には、AWSだけを使っている方であれば、CDKを使っておくのが良いと考えています。 ただし、一般的に学習コストはTerraformの方が低いと言われています。

Serverless Application Model (SAM)

サーバーレスに特化したIaCのための、AWS認定のオープンソースフレームワークです。Lambda本体だけでなく、S3やDynamoDB、API Gatewayといった関連リソースも一緒に定義できます。 CDKで定義したリソースの動作確認をSAMで行うこともできるようです。さすが公式認定。

定義するリソースが他のリソースとの結合度が低く、特定のサービス専用のLambdaを構築する際におすすめです。

Serverless Framework (SLS)

こちらもサーバーレスに特化したオープンソースフレームワークです。Wikipediaによると、AWS Lambdaでアプリケーションを構築するために開発された最初のフレームワークだそうです。

現在はGCPなど、他のクラウドのコンピューティングサービスのリソース定義にも使用できます。

テンプレートから簡単にプロジェクトを作成できたり、トリガーの設定もできます。 また、デプロイなどの操作をコマンドで簡単にできます。

VoicyでのLambdaのIaCの現状

「インフラはTerraform管理 + ロジックは別のGitリポジトリ管理 + SLSでデプロイ」

という構成をとっています。

Voicyでは原則として全てのAWSリソースをTerraformで管理しています。 そのため、Lambdaの定義もTerraformで統一したいという判断となりました。Terraformの定義ファイルは、全てひとつのGitリポジトリに集約しています。

とはいえ、Terraformの定義とLambdaのロジックを密結合にしたくはありません。言い換えるなら、上記のTerraform用のリポジトリの中に、Lambdaのロジックを記述したコードを含めたくはありません。このような背景から、ロジックを記述したコードは別のGitリポジトリで管理しています。

この際、Terraform上に用意する実行ファイルは空のダミーファイルにします。

また、デプロイにはServerless Frameworkのコマンドを使っています。コマンドひとつで簡単にデプロイできるためです。コードのコンパイル用のスクリプトと、slsコマンドの実行等をまとめてMakefileで実行できるようにしてあります。

が、ここはSLSである必要性は特にありません。もしかしたら過去にSLSでLambda開発を行おうとしたのかもしれません。

IaCはすばらしいですが、これだけで全ての悩みが解決するわけではないですね。 ベストプラクティスが定まっていないのも悩みの種です。

LambdaのIaCについて考えた背景

最近、大きめのプロジェクトとして取り組んでいたのが「通知基盤」の開発です。

Voicyでのプッシュ通知のユースケースには「パーソナリティが放送を更新した際に、そのチャンネルをフォローしているリスナーに知らせる」などがあります。

他にも複数のAPIがプッシュ通知を送信しているのですが、通知文言の構築や通知対象者の選定を各APIが独立に担っており、ロジックが点在していたため、それらを集約する目的で作成されたのが通知基盤です。

これを開発するにあたり、AWS Lambdaを中心にサーバーレスなサービスを使ったことが、LambdaのIaCについて考えるきっかけとなりました。

最後に

こちらのVoicyチャンネルで音声発信をしています!

ここまで読んでくださった方はぜひ聴きに来てください! voicy.jp