はじめに
皆様こんにちは、ソーシャル経済メディア「NewsPicks」(Media Infrastructureチーム)エンジニアの北見です。
先日、↓ の記事を書かせて頂きました。
前回では CDK
の良さをメインに紹介しましたが、今回は上手く使えずにドはまりしてしまった例をご紹介します。
ことの始まり
ある日、チームメンバーからこんな報告があがってきました。
「CDKのバージョン上げたのですが、cdk deployで失敗しちゃうんですよね。これ分かります?」
xxx-cluster-stack failed: Error: The stack named xxx-cluster-stack failed to deploy: UPDATE_ROLLBACK_COMPLETE: Resource handler returned message: "Resource of type 'AWS::ECS::Service' with identifier 'xxx-app-service' already exists." (RequestToken: aaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee, HandlerErrorCode: AlreadyExists) at FullCloudFormationDeployment.monitorDeployment (/Users/hoge/xxx/node_modules/aws-cdk/lib/index.js:412:10236) at runMicrotasks (<anonymous>) at processTicksAndRejections (node:internal/process/task_queues:96:5) at async Object.deployStack2 [as deployStack] (/Users/hoge/xxx/node_modules/aws-cdk/lib/xxx/node_modules/aws-cdk/lib/index.js:415:152469) at async /Users/hoge/xxx/node_modules/aws-cdk/libg/yyyy/node_modules/aws-cdk/lib/index.js:415:136265
原因を深掘りしていくと、ECS Service
の管理・更新を↓のように CodeDeploy
を使って行っていることが原因でした。
const appEcsService = new ecs.FargateService(this, "xxx-app-service", { serviceName: "xxx-app-service", cluster, taskDefinition: appTaskDefinition, desiredCount: 2, securityGroups: [appSecurityGroup], deploymentController: { type: ecs.DeploymentControllerType.CODE_DEPLOY, }, vpcSubnets: privateAppSubnets, });
このコードでは「この ECS Service
の更新は CodeDeploy
でしなきゃだめだよ」という設定をしています。
しかし CDK
のバージョンアップによって ECS Service
に変更が入ってしまい、CodeDeploy
以外の方法で更新しようとしていました。
これってつまり...?
CDKのバージョンアップができない、詰み状態です
CodeDeploy
でしか更新できないECS Service
をCDK
管理するCDK
のバージョンを上げるCDK
のバージョンアップに伴い、意図せずECS Service
に変更が出るcdk deploy
しようとすると、「このECS Service
はCodeDeploy
でしか更新しちゃだめだよ」と怒られてエラーになる
結局どうしたのか?
新基盤に作り直す ことになりました。
CDK
管理しない方式で ECS Service
をデプロイ・更新するためのフローを作成し、新たな Service
へリクエストを徐々に切り替え、最終的に↑の CDK
コードを削除することができました 。
このためにかなり多くの時間を費やしてしまいましたが、結果的にデプロイフロー等もすっきりしたものになりました。
(新基盤の作成については、詳細はまた後日記事にさせて頂きます。)
何がよくなかったのか?
根本原因としては、
インフラとして管理すべきでないものを CDK
管理した
のが原因でした。
更新頻度が高い、すなわち揮発性が高いものはインフラではなく、インフラ上で動作する「アプリケーション」です。
一方で更新頻度が低い、すなわち揮発性が低いものは、アプリケーションを動かすための「インフラ」です。
API
のタスク定義は、(一般的に)コード変更の度に新しく入れ替える必要があるので、高頻度で書き換わりますね?
今回の場合、確かに ECS
の Cluster
であればインフラです。
ですが、アプリケーションのコード変更の度に更新が走る Service
は、インフラではなかったのです。
結論:「インフラ」でないものを CDK
管理してはいけない
「インフラ」でないものを CDK
管理してはいけません
逆に言うと、ECS Service
だろうがなんだろうが、更新頻度が低いものはインフラとして捉える方が良いと思います。
さいごに
このようにドはまりしてしまった CDK
ですが、正しく使えば、生の CloudFormation
を扱うよりはるかにたやすくインフラを構築できますので、私はやはりメリットの方が大きいと判断しています。
どの技術にも言えることですが、誤った使い方をすると保守やアップデートが大変ですし、それは CDK
でも変わりません。
今回の話を聞くと「CDK
って怖い!」と思ってしまうかも知れませんが、
- 「インフラ」はアプリケーションを動かすための基盤であり、更新頻度は低いはずである(頻繁に変更するものをインフラとは呼ばない)
CDK
は「インフラ」をコード管理するものであって、インフラでないものはCDK
で管理しないという強い意志を持つ。
というポイントを押さえておけば、同様の失敗はしにくいんじゃないかと思います。
CDK
アンチパターンの一例を紹介させて頂きましたが、皆様のお役に立てれば幸いです。