クラウドインテグレーション2部の水本です。
最近は「テスト」がマイブームでして、プログラムだとpytestやmockerについて調べつつSlack-botを作ってみる、なんてことをやったりしてました。
その中で「IaC、特に弊社でよく使うAWS CloudFormation(以下、CloudFormation)のテストってどうするのか?」に疑問を抱き、調べてみたところtaskcatに出会ったので、これを触り始めています。
taskcatとは?
taskcatはAWSが開発している、CloudFormationのテストツールです。
CloudFormationのテストを自動化してCI/CDパイプラインに組み込むことができるほか、デプロイ先のリージョンを複数指定して一斉実行なども可能です。
テストが終わった後は自動でStackを削除してくれるので、利用料が大きく跳ね上がる心配もありません。
最近困った事
私がよくCloudFormationテンプレートを作成する場合、クロススタック参照を前提にします。
いわゆる、「VPCのIDはOutputsに記述しておいて、他のStackから呼び出せるように」という実装です。
しかしながら、どうやらtaskcatはテストデプロイを順序づけて実行はしてくれず一斉実行してしまうようで、実際に複数テスト定義を書いてtaskcat test run
を実行するとVPCのStack作成完了前にセキュリティグループのStackテストが始まり、エラー終了してしまいます。。。
対処
ここで語らずとも思い浮かぶ人はいると思いますが、スタックをネスト構造にすることで解決します。
テストするためのテンプレートを別で作り、それをテスト実行するだけです。
AWSTemplateFormatVersion: "2010-09-09" Description: root stack template Parameters: TemplateVPC: Description: VPC template URL(https://) Type: String TemplateSG: Description: SG template URL(https://) Type: String Resources: VPC: Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Ref TemplateVPC SG: Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Ref TemplateSG DependsOn: VPC
taskcat側のconfig(.taskcat.yml
)は以下のように記述します。
東京リージョンに対してテストを実行するものです。
各種「子テンプレート」のURLは確定しない(バケットにランダム値がセットされる)ので、taskcatが提供しているPsuedoパラメータで置換します。
project: name: my-project package_lambda: false regions: - ap-northeast-1 tests: root: template: ./templates/root.yaml parameters: TemplateVPC: https://s3.amazonaws.com/$[taskcat_autobucket]/$[taskcat_project_name]/templates/1_network.yaml TemplateSG: https://s3.amazonaws.com/$[taskcat_autobucket]/$[taskcat_project_name]/templates/2_sg.yaml
今回はローカルにtemplates
というディレクトリを作って、そこに各種テンプレートを配置しました。
このディレクトリは私が指定して作ったものです。
taskcatは実行するとS3バケットを作成し、上記のconfigと同一階層より下のファイル全てが階層そのままにアップされます。
configの配置場所には注意してください。
taskcat clean [projectname]
でS3ごと消すことも可能です。
実際に実行してみる
では、実際に実行してみます。
taskcatがNested Stackを認識して、メッセージもちゃんと変更してくれます。
最高ですね。
❯ taskcat test run _ _ _ | |_ __ _ ___| | _____ __ _| |_ | __/ _` / __| |/ / __/ _` | __| | || (_| \__ \ < (_| (_| | |_ \__\__,_|___/_|\_\___\__,_|\__| version 0.9.33 [INFO ] : Linting passed for file: /Users/owner/development/hogehoge/templates/root.yaml [S3: -> ] s3://tcat-my-project-g4z232nm/my-project/templates/2_sg.yaml [S3: -> ] s3://tcat-my-project-g4z232nm/my-project/templates/1_network.yaml [S3: -> ] s3://tcat-my-project-g4z232nm/my-project/templates/root.yaml [INFO ] : ┏ stack Ⓜ tCaT-my-project-root-cd0a4d60aa0a4c4cbad5d197d01ba411 [INFO ] : ┣ stack Ⓝ tCaT-my-project-root-cd0a4d60aa0a4c4cbad5d197d01ba411-VPC-1T8ULTULOWBA2 [INFO ] : ┣ stack Ⓝ tCaT-my-project-root-cd0a4d60aa0a4c4cbad5d197d01ba411-SG-WZA5XVINJTAE [INFO ] : ┣ region: ap-northeast-1 [INFO ] : ┗ status: CREATE_COMPLETE [INFO ] : Reporting on arn:aws:cloudformation:ap-northeast-1:123412341234:stack/tCaT-my-project-root-cd0a4d60aa0a4c4cbad5d197d01ba411/6ee7d2a0-68b1-11ed-b69f-0e787f1b4501 [INFO ] : Deleting stack: arn:aws:cloudformation:ap-northeast-1:123412341234:stack/tCaT-my-project-root-cd0a4d60aa0a4c4cbad5d197d01ba411/6ee7d2a0-68b1-11ed-b69f-0e787f1b4501 [INFO ] : ┏ stack Ⓜ tCaT-my-project-root-cd0a4d60aa0a4c4cbad5d197d01ba411 [INFO ] : ┣ stack Ⓝ tCaT-my-project-root-cd0a4d60aa0a4c4cbad5d197d01ba411-VPC-1T8ULTULOWBA2 [INFO ] : ┣ stack Ⓝ tCaT-my-project-root-cd0a4d60aa0a4c4cbad5d197d01ba411-SG-WZA5XVINJTAE [INFO ] : ┣ region: ap-northeast-1 [INFO ] : ┗ status: DELETE_COMPLETE
2022.11.26 追記
taskcatにはLambdaコードをパッケージ化する機能があり、これがDockerを暗黙的に求めるようです。
[ERROR ] : DockerException Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))
CIに組み込むなどの場合に面倒なので、今回のサンプルには当該の機能を使わない指示( package_lambda: false
)を追記しました。
2022.12.01 追記
taskcatはテストで作ったテンプレートS3格納バケットを削除しません。
必要な場合は以下のように削除処理をCIなどに組み込んでください。
aws s3 ls | awk '{print $3}' | grep "^tcat" | xargs -I {} aws s3 rb s3://{} --force
まとめ
taskcatでは複数リージョンのデプロイ試験ができる以外にも、Nested Stack、クロススタック参照でもテストができます。
皆様、良いテストライフを。