morishitaです。
アクトインディのインフラの多くは AWS CDK を利用して構築しています。
それについていくつかのエントリで紹介してきました。
そして 2021 年 12 月に初のメジャーアップデートとなる v2.0.0 がリリースされました🎉。
ちなみに 2022/02/04 現在の最新バージョンは v2.10.0 です。
今回は CDKv2 を触ってみて、既存プロジェクトをマイグレーションしてみたので紹介します。
なお、本エントリは Typescript 前提です。
まずは触ってみる
とりあえず、CDKv2 を触る最初の一歩として、CDK プロジェクトを初期化してみます。
❯ cd aws-cdk-init-sample ❯ npx cdk@2 init --language=typescript npx: 213個のパッケージを7.157秒でインストールしました。 Applying project template app for typescript # Welcome to your CDK TypeScript project! This is a blank project for TypeScript development with CDK. The `cdk.json` file tells the CDK Toolkit how to execute your app. ## Useful commands * `npm run build` compile typescript to js * `npm run watch` watch for changes and compile * `npm run test` perform the jest unit tests * `cdk deploy` deploy this stack to your default AWS account/region * `cdk diff` compare deployed stack with current state * `cdk synth` emits the synthesized CloudFormation template Initializing a new git repository... hint: Using 'master' as the name for the initial branch. This default branch name hint: is subject to change. To configure the initial branch name to use in all hint: of your new repositories, which will suppress this warning, call: hint: hint: git config --global init.defaultBranch <name> hint: hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and hint: 'development'. The just-created branch can be renamed via this command: hint: hint: git branch -m <name> Executing npm install... npm WARN deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. npm WARN deprecated uuid@3.3.2: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. npm WARN deprecated sane@4.1.0: some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN aws-cdk-init-sample@0.1.0 No repository field. npm WARN aws-cdk-init-sample@0.1.0 No license field. ✅ All done!
CDKv1 のときと同様、実行したディレクトリに package.json とサンプルコードなどが作られたのち、npm install
が実行されます。
すでに Git リポジトリも初期化された状態です。
デフォルトではメインブランチ名は master となっています。v2 になっても main にはなってないんですね。
出来上がるファイル群は次の通りです。これも CDKv1 と変わりません。
. ├── bin │ └── aws-cdk-init-sample.ts ├── lib │ └── aws-cdk-init-sample-stack.ts ├── node_modules ├── test │ └── aws-cdk-init-sample.test.ts ├── README.md ├── cdk.json ├── jest.config.js ├── package-lock.json ├── package.json └── tsconfig.json
ちなみに、上記の例ではわかりやすく npx cdk@2 init
と @2
でバージョンを指定していますが、バージョン指定なしでも構いません。
ちょっと前まではバージョン指定なしの npx cdk init
では CDKv1 で初期化されたんですが、CDKv2 を使うようにアップデートされたようです。
cdk init
を比べてみる
ざっと見た感じ、CDKv1 で init したものと大きくは変わらないようです。
もう少し詳しく見るために CDKv1 、CDKv2 それぞれで初期化した結果できたファイルと比較してみます。
わかりやすく比較するために npx cdk@1 init
を使って作ったリポジトリに npx cdk@2 init
で作ったファイルを上書きコピーしてプルリクエストを作りました。
違いがあるのは次のファイルでした。
- package.json
- package-lock.json
- cdk.json
- bin/aws-cdk-init-sample.ts
- lib/aws-cdk-init-sample-stack.ts
- test/aws-cdk-init-sample.test.ts
package.json
まずは package.json を見てみます。
aws-cdk が 2.10.0 (2022/02/04 時点の最新バージョン) になっています。
そして @aws-cdk/** が廃止され aws-cdk-lib に集約されていますね。
さらに constructs* が追加されています。
AWS Cloud Development Kit v2 開発者プレビューのお知らせ | Amazon Web Services ブログ に記述されているとおりです。
cdk.json
cdk.json は CDK プロジェクトの動作設定をするファイルですが、あんまり自分で意識して編集しているファイルではないかもしれません。
context
には各種機能の動作を変更する Feature Flag が設定されています。
CDKv2 では context
以下に追加はなく削除されているものがあります。
AWS Cloud Development Kit v2 開発者プレビューのお知らせ | Amazon Web Services ブログによると「v1 で作成された Feature flags はすべてデフォルトで有効になっているためです」とのことなので気にしなくても良さそうです。
CDKv2 に残っているものもデフォルトは有効だけど、無効にできるものが残されているようです。
Typescript ファイル
Typescript のコードは import
部分が変更されているだけです。
package.json で見たようにモジュール構成が整理されたためですね。
主な違いは次の通りです。
CDKv1 | CDKv2 |
---|---|
@aws-cdk/core |
aws-cdk-lib |
@aws-cdk/XX |
aws-cdk-lib/XX |
基本的には import
の from
に @aws-cdk
が含まれているところを直していけば良さそうです。
CDKv1 から CDKv2 へのマイグレーション
さて、ざっと CDKv2 について確認したところで、既存の CDKv1 のプロジェクトを CDKv2 にマイグレーションしてみました。
マイグレーションの手順
マイグレーションは次の手順で行いました。
- CDK を v1.x.x の最新バージョンにアップデートする
- 非推奨なメソッド等を利用している部分を修正する
cdk diff
でデプロイ環境と差がないことを確認する- cdk.json の
context
をすべて削除する - package.json を変更する。
- コードを修正
cdk diff
で差分の有無の確認
以下にやってみて感じたポイントを記します。
1. CDK を v1.x.x の最新バージョンにアップデートする
どうせ CDKv2 にアップするなら最新版にしたいところ。
古い CDKv1 から一気に CDKv2 の最新版にマイグレーションした場合、不具合が出ても CDKv2 に移行したためかどうか判別しづらくなります。
なので先に CDKv1 の最新にアップデートしておきます。
また、CDK のテストに利用される @aws-cdk/assert は deprecated になっており、@aws-cdk/assertionsへの移行が促されています1。
例えば、CDK のアップデート時の変更を検出しやすいようにスナップショットテストを実装することがあるかと思います。
@aws-cdk/assertions に移行すると SynthUtils
クラスが使えなくなるため、代わりに Template
クラスを使って次の様に変更します。
- import { SynthUtils } from '@aws-cdk/assert'; + import { Template } from '@aws-cdk/assertions'; import { App } from '@aws-cdk/core'; import { MyStack } from '../../lib/stacks/MyStack'; describe('MyStack', () => { test('Snapshot test', () => { const app = new App(); const stack = new MyStack(app); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + expect(Template.fromStack(stack)).toMatchSnapshot(); }); });
この変更前後で保存されているスナップショットファイルは変わりませんでした。
@aws-cdk/assert には CDKv2 に対応したバージョンも一応提供されていますが、これを機に @aws-cdk/assertions 移行しておくほうがいいと思います。
2. 非推奨なメソッド等を利用している部分を修正する
古いバージョンからアップデートすると利用していたクラスやメソッド、プロパティが非推奨になってしまっているかもしれません。
VSCode だと非推奨の利用箇所にワーニングが表示されるかと思います。
CDKv1 の API リファレンスに代わりに使うクラスやメソッドなどの記述があるかもしれません。それを参考に修正しておきましょう。
というのも、CDKv1 の非推奨は CDKv2 すべて削除されているとのことだからです。
3. cdk diff
でデプロイ環境と差がないことを確認する
CDKv1 で最新にバージョンアップデートしたら、それをデプロイ環境にも反映しておきましょう。
デプロイしたら、念の為 cdk diff
で差分が発生しないことを確認しておきます。
ここで差分をなくしておくと CDKv2 への移行後に差分が発生した場合に移行が原因だとわかります。
仮に差分の解消が難しいとしてももともとある差を知っておくと差分発生時の切り分けに役立つと思います。
ここまでが CDKv1 でやっておく作業です。
4. cdk.json の context
をすべて削除する
ここからが CDKv2 への移行のための変更です。
まずは cdk.json の context
をすべて削除します。
もし、今まで自分で設定していたものがあるなら、それらの値が CDKv2 で引き続き設定可能か?
あるいは別のフラグに変わっていないか?
あるとして意味が変わっていないかを確認して再設定してください。
5. package.json を変更する。
次のポイントを変更します。
- *@aws-cdk/** モジュールをすべて削除する
devDependencies
の aws-cdk のバージョンを"^2.10.0"
にするdependencies
に次のモジュールを追加する- aws-cdk-lib (
"^2.10.0"
) - constructs (
"^10.0.0"
)
- aws-cdk-lib (
変更したら npm install
or yarn install
を実行してモジュールをインストールします。
7. コードを修正
コードの修正は主にモジュール構成の変更に伴う import
の修正です。
基本は次の 2 つの置換です。
@aws-cdk/core
をaws-cdk-lib
に置換@aws-cdk/
をaws-cdk-lib/
に置換
上記の置換でほとんど解決しますが、Construct
クラスは aws-cdk-lib ではなく constructs モジュールからインポートすることに注意です。
例えば、CDKv1 で Construct
, Stack
をインポートしていた場合、CDKv2では次の様に 2 つの import
に分かれます。
- import { Construct, Stack } from '@aws-cdk/core'; + import { Construct } from 'constructs'; + import { Stack } from 'aws-cdk-lib';
一通り修正したら、 cdk list
やテストを実行して抜け漏れがないかを確認しましょう。
要修正箇所が残っていればエラーが発生すると思います。
import
を修正してもエラーが発生する場合、次の原因が考えられます。
- CDKv1 で非推奨なメソッド等を利用している
- CDKv1 の API リファレンスを確認して代わりのメソッドやプロパティで実装し直す
- experimental なモジュール(
@aws-cdk/aws-appsync
など) を利用している@aws-cdk/*-alpha
なモジュールが別途公開されているのでそれらをインストールしてimport
も修正する- 参考:npm の "@aws-cdk alpha" での検索結果
上記以外が原因で発生するエラーもあるかもしれません。CDKv2 の API リファレンスなどを参考に修正しましょう。
7. cdk diff
で差分の有無の確認
ここまで修正してコンパイルエラーも出なくなったら、cdk diff
でデプロイされているものとの差分を確認しましょう。
差がないのが理想ですが、どうしても発生する差分があるようです。 Migrating to AWS CDK v2 - AWS Cloud Development Kit (CDK) v2の Troubleshooting には次の様に記載されています。
Expected changes include but are not limited to:
- Changes to the CDKMetadata resource
- Updated asset hashes
- Changes related to the new-style stack synthesis, if your app used the legacy stack synthesizer in v1 (CDK v2 does not support the legacy stack synthesizer)
- The addition of a CheckBootstrapVersion rule
「Changes to the CDKMetadata resource」というのは CDKv1 でもアップデートすると時々変わっていたやつだと思います。
「Updated asset hashes」は S3 に一旦置かれるもの(Lambda 関数のコード)などのハッシュ値が変わるということで、これまでの CDK のアップデートでも時々発生していたと思います。
「The addition of a CheckBootstrapVersion rule」は cdk diff
の結果で次の様に出力される部分のことだと思います。
[+] Unknown Rules: {"CheckBootstrapVersion":{"Assertions":[{"Assert":{"Fn::Not":[{"Fn::Contains":[["1","2","3","4","5"],{"Ref":"BootstrapVersion"}]}]},"AssertDescription":"CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."}]}}
この他に Parameters
の AssetParameters
から始まるキーの定義とそれを参照している箇所がなくなっています。
おそらく Lambda 関数などをデプロイするときに一旦 S3 に置くのですが、そのファイルの情報を Parameters
に定義して、それを参照する方法をやめた様です。
これらは仕方がないようなので、これら以外で差分が発生しているかを確認します。
ひょっとすると cdk.json
でデフォルト有効となった次の Feature Flag に関係あるかもしれないので次の様に無効に設定すると解決するかもしれません。
{ "context": { "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": false, "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": false, "@aws-cdk/aws-rds:lowercaseDbIdentifier": false, "@aws-cdk/core:stackRelativeExports": false } }
理由不明の差分がなくなるまで調べますが、構築リソースの動作を変えるものでなければ無視してもいいかもしれません。
こうして原因不明の差分がなくなればマイグレーション完了です。cdk deploy
でデプロイして動作確認しましょう。
まとめ
AWS CDK v2 がリリースされたので、CDKv1 からの変更点を確認しました。
そして既存の CDKv1 プロジェクトを CDKv2 にマイグレーションする手順とポイントを説明しました。
CDKv1 では利用する AWS のサービスに応じて @aws-cdk/** のモジュールを追加する必要がありました。
一方、CDKv2 では aws-cdk-libに集約されてモジュールの管理が格段に簡単になりました。./node_modules/aws-cdk-lib/* 以下に利用してないサービスのモジュールもインストールされてしまうのが気になりますが、致し方なしか…。
さて、今は CDKv1 も更新が続いていますが、そのうち CDKv1 の更新は終了すると思われます。
マイグレーションによる差分発生も少ないうちに CDKv2 に移行しておくのがいいのかなと思います。
このエントリがその一助になれば幸いです。
参考
- AWS Cloud Development Kit v2 開発者プレビューのお知らせ | Amazon Web Services ブログ
- Migrating to AWS CDK v2 - AWS Cloud Development Kit (CDK) v2
- AWS CDKv2にマイグレーションしてみた #reinvent | DevelopersIO
最後に
アクトインディではエンジニアを募集しています。
-
CDKv2 へのアップデート作業中に気づきました。あらゆる言語でのCDKアプリケーションのテスト | Amazon Web Services ブログ↩