MoTLab -Mobility Technologies Engineering Blog-MoTLab -Mobility Technologies Engineering Blog-

TerraformではなくCDKを使っている話

AWS
December 23, 2022

(これはMoT Advent Calender 2022の24日目です)

データエンジニアの渡部徹太郎です。私の担当しているプロジェクトでは、Infra as CodeにTerraformではなくCDKというツールを使っているので、その話をします。


CDKの概要

CDKとはAWS専用のInfra as Codeツールです。正式名称AWS クラウド開発キット (AWS Cloud Development Kit)です。

CDKの特徴

  • プログラミング言語でAWSのリソースを記述
  • プログラミング言語はTypeScriptがメインだが、他にもJavaScript,Python,Java,C#でも記述できる
  • AWSのリソースを表すクラスをNewすると、AWSのリソースができるイメージ
  • 実態はCloudFormationを吐き出してデプロイするツール。デプロイするとAWSのCloudFormationのStackになる。
An image from Notion

CDKをつかった作業イメージ

  1. TypescriptでAWSのリソースを記述
An image from Notion
  1. CDKによるデプロイ
$ cdk deploy S3Stack

CDKの特徴

プログラミング言語で記述できるため自由度が高い

  • 同じようなリソースをたくさん作る場合は forループを書けば良い
  • 特定のものだけ条件をつけたい場合はifを書けば良い
    • 例えば、本番環境、ステージング環境、開発環境での設定の分岐したい場合など
  • 共通処理は関数やクラスを作れば良い
    • 例えば、RDSとRDS Proxyをまとめて作るクラスを作るなど

例1: S3バケットの作成

An image from Notion

プログラミング言語で記述できるため、いろんなライブラリや開発ツールの恩恵を受けられる

  • IDEによる開発補助をうけられるため、文法チェック、補完、リファクタリングなどがしやすい
  • テストをするのも、既存のテストフレームワークで書ける。Typescriptならjestをつかえる

実際のプロジェクトでのCDKの利用

ここからは実際にどのようにプロジェクトでCDKを利用しているか紹介します

CDKのコード管理方法

アプリケーションのレポジトリの中に、アプリケーションのソースコードと一緒に、アプリケーション固有のAWSリソースのCDKのコードを管理します。例えば、IAM Role、CloudWatch Log Group、S3、Lambdaなどそのアプリケーションでしか使わないAWSリソースなどです。

アプリケーションを跨ぐ共通のリソースは、「共通インフラ」のレポジトリのCDKで管理します。例えば、VPC、RDS、ALBなどどのアプリケーション使うAWSリソースなどです。

An image from Notion

CDK Stack間の連携

アプリケーションのCDKのStackから、共通インフラのCDKのStackのリソースを参照する場合は、共通インフラ側でSSMパラメータを登録し、アプリケーション側からはそのパラメータをもとにlookupします。

例:共通インフラ側ではVPCを作り、VPC IDをSSMパラメータに登録

// VPCの定義
const vpc = new ec2.Vpc(this, 'Vpc', {
    cidr: "192.168.0.0/16",
    maxAzs: 2,
})

//他でも使うためSSM パラメータに登録する
new ssm.StringParameter(this, `StringParameterVpcId`, {
    parameterName: `${env}-cm-vpc-id`,
    stringValue: vpc.vpcId
})

アプリ側では、SSMパラメータをもとにVPC IDを取得し、Vpc.fromLookup()によりVPCのインスタンスを得る

//共通インフラのVPC
const vpcId = ssm.StringParameter.valueFromLookup(this, `${env}-cm-vpc-id`);
const vpc = ec2.Vpc.fromLookup(this, "vpc", {vpcId: vpcId})

他にもCDK Stack間の連携方法はありますが、この方法がStack間を疎結合にでき扱いやすいと思っています。

CDKを使った感想

CDKで良かった点

TypeScriptで書ける

TypeScriptがかなり書きやすいプログラミング言語です。モダンな文法でありストレスなく書け、かつ型に厳格でありどんな引数を渡せばよいかIDEが教えてくれます。

また、日々のプログラミングで培った頭の使い方をInfra as Codeで活用できます。

そして、何より、インフラエンジニアやサーバサイドエンジニアにとっては普段触れることのないTyepScriptに触れるので、楽しいです。

AWSのメジャーなサービスの使い勝手はよい

AWSのメジャーなサービスは使いやすいです。

特にVPCを構築する場合は効果が絶大で、SubnetやNatgatewayなど細々設定しなくても、使いたいIPアドレスレンジとPublic or Privateを指定するだけでVPCを構築できます。

他にも、IAM, EC2, S3, AWS Batch, SQS, CloudWatchなど、みんながよく使ってるメジャーなサービスは、よくメンテナンスされていて快適に使えます。

WebUIでデバッグしやすい

CDKをデプロイしてなにかエラーが発生した場合に、AWSマネージメントコンソールからデバッグしやすいです。CDKはCloudFormationのStackになりますので、CloudFormationのStackの画面を見れば、どのリソースで問題が発生しているかわかりますし、リンクをクリックすればそのリソースに飛べます。

CDKの辛い点

マイナーなサービスや設定値だと使い勝手が悪い

まず、この話を説明する前の前提知識として、CDKには高レベルAPIと低レベルAPIの2種類があることを説明します。高レベルAPIは上記のVPCのようにリソースを抽象化してくれて簡素な記述だけでリソースを定義できます。一方で低レベルAPIはCloudFormationと同じ粒度で細かく定義しなくてはいけません。

AWSでマイナーなサービスやサービスの設定値だと、高レベルAPIが提供されていなかったり、サービスの高レベルAPIはあっても一部の設定値が設定できないことがあります。例えば、ChatBotのSlackチャンネルパラメータ、EC2からFSx Lustreをマウントするパラメータ、StepFunctionに環境変数を渡すパラメータなどです。これらをデプロイしようと思ったら、低レベルAPIを用いてCloudFormationと同じ粒度で細かく定義する必要があり、面倒です。

ただし、CDKは日々バージョンアップしているため、以前は高レベルAPIがなかったサービスや設定値も、最新のバージョンだと存在するといったことはあります。

バージョンアップがやたらと早く、破壊的変更もたまにある

CDKは開発のサイクルが早く、一週間の間に3回リリースされることもあります。また、破壊的な変更が入ることもたまにあります

そのため、おすすめとしてはバージョンを追従するのはある程度諦め、一定期間はバージョンを固定して運用することをおすすめします。古いバージョンでも問題なく動きます。

マイナーなサービスや設定値は、バグも多い

上記の通りCDKの開発は非常に活発ですので、バグも結構あります。

特に、リソースをデプロイするときは問題なくても、デストロイ(削除) するときにバグを踏むことが多いです。例えば、CDKが先にIAM Roleだけ消してしまい、サービスそのものを消すときに、消す権限がなくて削除に失敗する事がありました。

削除に失敗した場合は、マネージメントコンソールに入り手動でぽちぽち消すことが必要になります。

社内勉強会で発表したときに出た質問と回答

このブログで説明した内容ですが、以前ほぼ同じ内容を社内勉強会で話し、そこで色々質問が出ましたので、その質問と回答を記載しておきます。

Q: 自由に記述できることが逆にマイナスにならないか?CDKのコード自体のレビューが難しくならないか?

A: 基本インスタンスをNewするだけなので、そこまで複雑にはならない。今まで他人が書いたCDKが読めなかったということはない。

Q: CDKを経由せずに手動でAWSのリソースを変更したらその変更はdiffとしてでるのか?

A: 出ない。CDKはデプロイされたCloudFormationのStackとしか比較しないため、CloudFormationが変わらないとdiffは出ない。

Q: Terrafomでは、Terraformで管理されていないリソースを後から追加するterraform importみたいな機能はあるが、CDKにはあるか?

A: やったことはないができるらしい。まず、CloudFormationのresource imports機能を利用してリソースを取り込みます。その時に取り込んだスタック名とCDKのスタック名を一致させることによりCDKとしてリソースを取り込むことでできるらしい。

Q: terraform planやdiffみたいな差分を見る機能はあるのか?

A: CDK diffというコマンドがありdiffが見れる。

Q: 生成されたCloudFormationのJSONをレビューすることはできるか?

A: ビルドするときに生成されるので見ることはあるが、それをレビューすることはない。レビューはCDKのコードだけ行う。Cloud FormationのJSONを見たくないからCDKを使っている。

Q: CDKで生成されたCloudFormationのJOSNをレポジトリで管理しているか?

A: してない。CDKを信用している。

Q: TerraformのStateファイルみたいなもはあるのか? A: ない。AWSにデプロイされたCloudFormationStackそのものがstateの役割

Q: 依存関係はどうやって表現するのか?

A: 同一stack内であれば依存関係を考慮して作ってくれる。たとえば、role作ってからそれを使うサービスを作ってくれるといったことは自動でやってくれる。dependancyとかを明示的に入れる必要はない。Stackを超える場合は、SSMパラメータなどを経由して使うことが多い。

まとめ

このブログではCDKの紹介と使った感想を記載しました。アップデートが早く暴れ馬な感じはありますが、Typescriptで書けるため柔軟で書いてて楽しいです。みなさんもぜひ使ってみてはいかがでしょうか?


We're Hiring!

📢
Mobility Technologies ではともに働くエンジニアを募集しています。

興味のある方は 採用ページ も見ていただけると嬉しいです。

Twitter @mot_techtalk のフォローもよろしくお願いします!