CDK Conference Japan 2024の参加メモ
公開日: 2024/07/07
TS何も分からんマンが作ったJAWSDAYS2024ティザーサイト徹底解剖
- 概要
- JAWSDAYSで作成したティザーサイトをCDKで構築したときの構成と大変だったこと
- どんな機能
- レスポンシブ、セッションのお気に入り機能等をフルスクラッチで作った
- どんな構成
- NEXT.js, chakra
- S3, Lambda, DynamoDB, Cognito, ACM等
- CDKの構成
- API、Cognito、DatastoreをConstructに分けたワンスタック構成
- アプリデプロイ方法
- リリースブランチにプッシュするとデプロイされる構成
- configure-aws-credentialsを採用してcredential引っ張ってくる
- デプロイ時にCloudFrontのキャッシュクリアも実施
- リリースブランチにプッシュするとデプロイされる構成
- インフラ部分のデプロイは手動で行った
- アプリ構成
- モノレポをnpm workspaceで実現
- 型定義や共有ライブラリをモノレポで共有
- フロントとバックエンドをTSで統一
- npmのアップデートにDependabotを採用
- CypressとCDK Synthを実行して壊れていないかを自動実施
- モノレポをnpm workspaceで実現
- 大変だったこと
- Linter、Formatterがあるbiomeを使ってみたがパイプラインをよく落としていた
- 当時はまだ安定していなかった
- 古いバージョンではルール定義が頻繁に変わってしまうのでそんなルールないエラーが出ていた
- CloudFrontをCDKで管理せずマネコンで作ったことを後悔
- 全パスをキャッシュ対象のパスパターンに入れていたがリアルタイムで表示切り替えたい要件が途中で出てきたので手運用が入った
- 早めにcdk importすればよかった
CDK初心者が開発で遭遇したトラブルと解決法
- プログラミングによるトラブル
- 自由度が高いぶん人によって書き方が違ってくる
- ベタ書き、共通設定、ラッパー関数、サービス単位の分割、機能単位の分割の思想が異なる
- 思想を揃える
- ベタ書き、共通設定、ラッパー関数、サービス単位の分割、機能単位の分割の思想が異なる
- 設定値外だしをcdk.jsonで行ったが型設定など自由度が低いのでTSで定義したほうがいい
- リファクタリング
- ベタ書きを継承したクラスにすると論理IDが変化してリソース再作成になってしまう
- 自由度が高いぶん人によって書き方が違ってくる
- デプロイによるトラブル
- 同名リソースのエラーが起きる
- 明示的にリソース名を指定しないCDK推奨の方法を取ったほうがいい
- 識別番号を付与して重複を避けるなど
- RETAIN_ON_UPDATE_OR_DELETEを活用する
- スタック間参照でデプロイできない
- 循環参照エラー
- formName、fromArnなどで分ける
- スタック間参照削除エラー
- cdk deploy -eでデプロイする、exportValueを利用する、SSMパラメータで参照しないようにする
- 循環参照エラー
- リソース作成順序によるエラー
- addDependencyで作成順序を制御する
- リソース上限エラー
- 500個までスタックを作れない
- 同名リソースのエラーが起きる
- 作りにくいリソース
- S3クロスリージョンレプリケーションは作るのが難しい
- スタック間参照を使わないほうがおすすめ
- Aurora作成時に自動作成されるロググループの設定変更
- 先に同名のロググループを作成すれば設定することができた
- S3クロスリージョンレプリケーションは作るのが難しい
初心者がおさえておきたいAWS CDKのベストプラクティス 2024年版
- ドキュメントを読もう
- cdk developer guideに実践的なベストプラクティスが載っている
- api referenceを読もう
- 特にoverviewを読もう
- github repository(aws/aws-cdk)のissueやプルリクを読もう
- CDKの仕組みを理解する
- aws cloudformationを経由していることを知ると問題解決時に役立つ
- CDKのblackbeltを見よう
- tenetsに共感する
- 相談先を知る
- aws support、aws re:post、公式のq&aサービス、cdk.dev(Slackチャンネル)
- 技術的なお問い合わせに関するガイドラインを読もう
- gitでバージョン管理しよう
- IDEの機能を活用しよう
- BLEA, Projenの利用、 型チェック、スニペットの登録等
- 生成AIの活用
- はじめから標準化しない
- 標準の書き方を先に決めると自由度が下がってしまう
- 認知負荷が下がらないように標準化しすぎない(Platform as a Product, TVP)
- 標準の書き方を先に決めると自由度が下がってしまう
- リソースの置き換えに注意
- cdk diffで確認、論理IDの変更に注意
- 外部の変更によるリプレースに注意
- SSM Parameter、AMI IDの変更等
- cacheInContext: trueの設定で対策できる
- SSM Parameter、AMI IDの変更等
- ハイレベルなコンストラクトを使おう
- 抽象度の高いコンストラクトを使おう
- 最終的にはCloudFormationに合成される
- スナップショットテストをして差分を確認しよう
- 抽象度の高いコンストラクトを使おう
- grant, metric, connectionsを活用しよう
- 抽象化された権限設定
- 必要になるまではスタックを分けない
- 出発点は1つでいい
- CloudFormationはyaml単位でスタックが管理されるがCDKは自由にファイルを分けられる
- 出発点は1つでいい
- スタックでなくコンストラクトで分割するようにしよう
- ベタ書きから始めよう
- 変数化、外部化しすぎない
- アプリのコードに比べて文脈上わかりやすいことがおおい
- アプリのように再ビルドを避けるための外だしという概念がない(必ず合成される)
- 早すぎる最適化の文脈
- リファクタリングしてもCfnが変わらないことを保証できる
- 変数化、外部化しすぎない
- パラメータはAppレベルから注入する
- Appから渡すようにしよう
- コンストラクト単位でがテスト可能になるため
- Appから渡すようにしよう
- スナップショットを書こう
- 定型文ですぐにテストできる
- CloudFormationの変更がされていないことを確認できる
- 定型文ですぐにテストできる
- リソース名でなくコンストラクトIDにこだわろう
- リソース名は変更が難しくなるのでコンストラクトIDで
- コードベースと環境の一貫性を保つ
- 常にdeploy —allすればかならず同期される
- 個別にデプロイすると途中からデプロイするのが怖い状態になる
- 手で修正したらすぐにコードに反映しよう
- 常にdeploy —allすればかならず同期される
脱ぽちぽちを目指してCDKでインフラ構築してみた
- 感動したところ
- 抽象化されているので利用しやすい(L1,L2,L3)
- App/Stack/Constructがクラスで分かれているのでプログラミングしていればわかりやすい
- 躓いたところ
- ロールバック失敗
- デプロイ失敗してロールバックも失敗する状態
- Ctrl+Cでデプロイを止めない、手動でリソース操作しない
- 強制的にスタックを削除する
- デプロイ失敗してロールバックも失敗する状態
- ロールバック失敗
LocalstackとcdklocalでつくるCDK開発環境入門
- LocalStackとは
- docker上でAWSサービスをエミュレートするプラットフォーム
- docker composeでインストールできる(Localstack CLI、Desktop、Helm等ある)
- awslocalコマンドでawsコマンドのように利用できる
- docker上でAWSサービスをエミュレートするプラットフォーム
- cdklocalとは
- LocalStack社が提供するLocalStack上にcdkを実行できるツール
- tflocal、samlocalなどもある
- cdklocal bootstrapしてcdklocal deployでデプロイできる
- LocalStack社が提供するLocalStack上にcdkを実行できるツール
- リソースブラウザ
- awslocalコマンドだけでなくブラウザ上で可視化できる
- 無料版有料版がある
- 提供されるAWSサービスの違い、リソース永続化の違いがある
- ECS、Amplify、RDSなどは無料版では使えない、無料版ではdockerを止めるとリソースは消えてなくなる
- 提供されるAWSサービスの違い、リソース永続化の違いがある
- その他注意
- SERVICEでCloudFormationを有効にする必要がある
- マシンスペックはどのくらい?
- メモリ32GB積むと不快感感じない
CDKアプリとしてのAmplify Gen2
- Amplify Gen2はCDKベースで作り直された、Amplifyのモジュールを見ることでCDKのプラクティスを見てみる
- Gen2に変わったことによる機能
- CDKによるバックエンド構築
- これまではCLIだったがコード化できるようになった
- バックエンドをTSで定義できる
- ファイルベース規約を用意している
- Gitブランチと環境のマッピング
- stageingブランチ、productionブランチ
- pushすると反映される
- stageingブランチ、productionブランチ
- sandbox環境の提供
- npx ampx sandboxコマンドでクラウド上の環境を作ることができ、hot swapでデプロイもできる(CDKを使っているので)
- CDKによるバックエンド構築
- Amplify Gen2のバックエンドの裏側でCDKを使っている
- ここではフロントエンドは含まれない
- npx ampxによるデプロイ
- cdkのプロセスを内部で実行しておりcdk synthしたあとCfnをデプロイしている
- Gen2から見るベストプラクティス
- AWS規範ガイダンス、AWS CDKを使用したクラウドインフラストラクチャの開発とデプロイのベストプラクティスを参考にしている
- L3コンストラクトの作成をしている
- dataとauthのL3コンストラクトがamplify用に作られている
@aws-amplify/<feature>-construct
- GraphQLのスキーマ定義、AppSync+DynamoDBのパターンに特化したインターフェース
@aws-amplify/auth-construct
- 引数で宣言するだけで認証設定ができる
- dataとauthのL3コンストラクトがamplify用に作られている
- Abstract Factoryパターンを利用する
- 万人向けではない
- ConstructFactoryインタフェースが内部で作られている
- CDK Constructを生成する責務がある
- 定義ファイルで定義したdefineXXXがAbstract Factoryの実装になっている
- DIコンテナによって管理され依存関係を実行時に解消している
- CDK Constructを生成する責務がある
- Aspectsを使ったセキュリティプロパティに関するアサーション
- Cognito IdPの信頼ポリシー
- 例)AssumeRoleWithWebIdentityが広範囲に許可するのでユーザーのConditionを設定するべき
- Aspectsを使ってチェックしている
- CognitoRoleTrustPolicyValidatorという実装でConditionが含まれているかチェックしている
- Aspectsを使ってチェックしている
- 例)AssumeRoleWithWebIdentityが広範囲に許可するのでユーザーのConditionを設定するべき
- Cognito IdPの信頼ポリシー
- カスタムリソース
- Amplify Gen2で使われているカスタムリソース
- secrets
- シークレット値を管理する機能がある
- 内部的にはSSMParameterStoreに格納されている
- 内部的にはカスタムリソースで実現している
- カスタムリソースはLambdaが実態
- ParameterStoreからシークレット値を取得して値を返す実装になっている
- Lambdaでも動くようにカスタムされている
- 最初はダミー値を取得してその後動的にシークレット値を取得するコードを処理の先頭で追記するようになっている
- カスタムリソースはLambdaが実態
- Custom::AmplifyDynamoDBTable
- Amplify向けにカスタムされたリソースが作られている
- 一回のデプロイでGSIを複数デプロイできるようにカスタムされている
- カスタムリソースのLambdaがStepFunctionsを実行して処理が完了するまで待ち続ける仕組みになっている
- ProviderFrameworkをもともと使っていたがパフォーマンス向上するためStepFunctionsのリトライ処理に変更された
- カスタムリソースのLambdaがStepFunctionsを実行して処理が完了するまで待ち続ける仕組みになっている
- 一回のデプロイでGSIを複数デプロイできるようにカスタムされている
- Amplify向けにカスタムされたリソースが作られている
- secrets
- Amplify Gen2で使われているカスタムリソース
- まとめ
- 万人向けではないがCDKをベースとしたプラットフォームを作りたいというような場合には上記のようなプラクティスが使えるかもという話
”AWS CDKを選定しなかった理由”から見るCDKの現在地
- 期待値と時間のサイクルからみる現在地
- CDKを選定しなかった理由
- メンバーはIaCちょっとやっとあるAWS経験ある
- 業務は受託でリリース日が決まっている
- 初期は自分だけが使えていたがキャッチアップの面倒が自分だけになってしまう
- インフラチームとの分断があった
- アプリチームは別に存在している
- リリース後に他社の運用チームへの引き渡しが決まっていた
- 初学者でも運用できることが期待されていた
- アーキテクチャは非公開だがサードパーティソフトウェアのEC2上での実行が決まっていた
- CloudFrontのようなAWSのサービスとの相性も不明な状態であった
- 何を選定したか
- CloudFormation(+Rain、Checkov)に決めた
- 経験者がいた
- ツール更新による影響が少ない
- 後方互換性が強い
- CloudFormation(+Rain、Checkov)に決めた
- 選定しなかった理由を深堀りする
- 学習したメンバーがいない
- IaCへの関心事が増える→全員に必要なのか、JSON、YAMLが主戦場の人によってはコストが増える
- できることが増える→なんでもできてしまう、余計な関心事が増えるとも言える
- L2、L3を使えつつL1も使える
- プログラミング言語のサポートや言語機能の利用
- DRYであるかEarly Optimizationであるか
- できることが増える→なんでもできてしまう、余計な関心事が増えるとも言える
- IaCへの関心事が増える→全員に必要なのか、JSON、YAMLが主戦場の人によってはコストが増える
- リリース後の運用チームが別
- CDKの引き継ぎをする問題
- CDKの引き継ぎがためらわれる
- CfnのほうがAWSサポートが効きやすいと思った
- Constructの難しさ
- CfnにCDKで追いつくまでのラグ、L2で使えるまでのラグがある、使えないアップデートがあることを理解する必要がある
- 引き継ぎ先に求めるレベルが高くなる
- コーディング規約が難しさがある
- 規約はツールがある
- 言語の規約、CDKの規約(cdk-nag, snyk, checkov)
- スタイルガイドが難しい
- ディレクトリ構成、ファイル分割、Stack分割、Construct分割、言語の機能を使っていいか、設定ファイルをどうするか
- ベストプラクティスはある
- BLEA、GenU、CDK Aspect、CloudFormation Guardなどはある
- メンバー入れ替え、引き継ぎ時に思想を引き継げるかの問題がある
- ディレクトリ構成、ファイル分割、Stack分割、Construct分割、言語の機能を使っていいか、設定ファイルをどうするか
- 規約はツールがある
- 運用が難しい
- ツールのアップデート問題
- 毎週アップデートされる
- 引き継ぎ先にもやってもらう必要があるか、リリースタイミングにするか、何かあるかまで止めるか等
- スナップショットによる差分ケアはできる、実環境での動作確認はするか等
- 毎週アップデートされる
- ツールのアップデート問題
- チーム内ではどう
- CDKの引き継ぎをする問題
- その他のリスク
- 許容できるリスクが閾値を超えそう
- 2割新しいことに選択してそれ以外は既存の技術を使うという考え
- 他のリスクもあったのでCDKを使わないことにした
- 許容できるリスクが閾値を超えそう
- 学習したメンバーがいない
- CDKの現在地
- L2コンストラクトは便利でわかりやすい抽象度でAWSに集中できる
- コードをメンテし続ける体制がある、アプリケーションも作っているメンバーがいる
- 学習コストが低いとはいいきれない
- CDKを使うためにツールをかえるか、チームをかえるか
- ツールをかえないとしてガイドラインをつくっておくとよさそう
- CDK使えないと言いづらいので上がっている情報にはバイアスがかかっている
- ベストプラクティスの簡略化、ツール化、OSS化
- ツールをかえないとしてガイドラインをつくっておくとよさそう
- まとめ
- チームの形によって合う合わないがある、Cfnの上位互換とは言いづらい
- 流行ってるからだけで選定するのではなく納得できる選定にしていきたい
AWS CDK コンストラクトの分割戦略:レベル指向プラクティスの実践
- 概要
- L2/L3コンストラクトの作成で分割できるという提案
- L4という言葉を説明上だしているが公式ではない
- L2/L3コンストラクトの作成で分割できるという提案
- CDKの3つのリソース分割手法
- わけない
- コンストラクト
- コンストラクトを自作することがプラクティスとしてある
- ファクトリ関数
- コンストラクトの分け方
- リソースグループカット
- DBやNWの単位で分ける
- コンポーネントカット
- サービス単位で分ける
- どこになにがあるかわかりにくくなる
- サービス単位で分ける
- コンストラクトでの解消と問題
- 解消できたこと
- 基本概念でのコード分割ができ、Aspectやタグ付けなどしやすくなる、TreeViewでの見やすくなる
- 問題
- 指針がないと無秩序になる、コンストラクトが肥大化する
- リファクタリングしにくくなる
- 再利用性のないコンストラクトが量産される
- 特定サービス用のコンストラクトでこの資料上ではL4と呼んでいる
- 解消できたこと
- リソースグループカット
- レベル指向プラクティスの提案
- L4コンストラクトを量産するのではなくL2/L3のような汎用性の高いコンストラクトを自作する
- ナレッジを横展開できるようになる
- 例:Route53 Resolver
- セキュリティグループ、インバウンド、アウトバウンドなどをL1コンストラクト含めて作る必要がある
- 使い回すことが多ければL2コンストラクトを自作することでコードを薄くできるようにする
- セキュリティグループ、インバウンド、アウトバウンドなどをL1コンストラクト含めて作る必要がある
- L2、L3はどのように分けている?
- デザインガイドを確認するとL2、L3の定義がされている
- L2は特定リソースに注力しているが、L3はリソースの組み合わせパターンにフォーカスする
- デザインガイドを確認するとL2、L3の定義がされている
- L1を直接使ったL4を作らずL2、L3を間につくることで再利用できるようにする
- L2やL3を作ればコントリビュートできる
- Open Constructも最近できた
- L4コンストラクトを量産するのではなくL2/L3のような汎用性の高いコンストラクトを自作する
- cdklib以外のL2,L3を活用する
- Open ConstructやConstruct Hubに既にあるかもしれない
- コンストラクトの分割手法
- L2をどうやってつくるか
- L2によくある機能
- 物理名の決め方
- L2インターフェースの定義
- IGrantable、grantXxxメソッドを実装する
- IConnectableを実装する
- L2によくある機能
- L2をどうやって管理するか
- まずはチーム内で利用
- 成熟してきたら組織内に配布
- OSSへ公開する
- まとめ
- L4を作ることだけじゃない
- L2/L3を分割することも検討しよう
- Open Constructも活用して再実装の負荷を減らそう
App Staging Synthesizerに入門する
- App Staging Synthesizerとは
- ブートストラップのモデルを置き換えてよりコントロールできるようにする
- 既存のブートストラップを置き換える
- ブートストラップのモデルを置き換えてよりコントロールできるようにする
- Bootstrapモデルとは
- 環境ごとにCDKを使用するまえに準備するためのプロセスでデプロイ前にする必要がある
- 環境とは
- リージョンとアカウントの組み合わせのことをCDKでは環境と呼んでいる
- 環境が違えばブートストラップも環境だけ必要
- 逆に言えば環境ごとに1つしか作れない
- 何をしている→デプロイに必要なリソースを作っている
- S3バケットやECRリポジトリを作る
- pushするためのIAMロールを作る
- ImagePublishingRole, FilePublishingRoleなど
- デプロイ時に最小権限のロールをAssumeしている
- ImagePublishingRole, FilePublishingRoleなど
- Stack Synthesizer
- スタックをどのように合成、デプロイするかを決定するオブジェクトでスタックごとに持つ
- アセットの保存参照、IAM Roleは何が必要か
- DefaultStackSynthesizer
- デフォルトで使われるStack Synthesizer
cdk.out/manifest.json
に吐き出される- App Staging Sythesizerはこれの代わりに利用しようとしている
- Assets
- S3バケットとECRに保存
- CloudFormationのテンプレートやLambdaのコードが含まれる
- Lambda作成時などに裏で自動で利用している
- 既存のBootstrapの課題とは
- 自動で作られる組織のセキュリティポリシーとリソースが違う可能性がある
- テンプレートの変更に追従する必要がある
- 同一環境でデプロイされるプロジェクトでアセット分離が難しい
- S3とECRにあるアセットが肥大化する
- ライフサイクルポリシーをわからない
- ハッシュ値として保存されるのでどこで使われているのかわからない
- そのため削除もしにくい
- 2018年からガベージコレクションが提案されているが放置されている
- サードパーティのツールも作成されている
- App Staging Synthesizerがどのようにそれを解決するのか
- DefaultStackSynthesizerの代わり
- 裏でStagingStackがデプロイされる
- bootstrapで作成されたリソースの代わりに使われる
- Appクラスのインスタンス化のタイミングで指定する
- 同じようにECRとS3が作られIAMRoleも別途作成される
- ECRとS3のプッシュ用IAMRoleだけが別に存在するためBootstrapは引き続き利用される
- 特徴
- 変わらないこと
- Bootstrapプロセスは引き続き必要
- IAMロール名にはリージョン名が含まれることに注意する
- Bootstrapプロセスは引き続き必要
- 変わること
- S3、ECRに関するバケット、リポジトリが専用で作成される
- ECRは複数作成される
- Stack削除時にアセットが自動で削除される
- Deploy Time S3 Assetsという概念がある
- デプロイ時に利用されるアセットが該当
- 保存するときにdeploy-time/に保存される
- ライフサイクルルールで30日とデフォルトでなっているので定期削除される
- デプロイ時に利用されるアセットが該当
- DockerImageAssetを作ったときにassetNameを自動で指定する必要がある
- 逆に言えば指定がなければECRのリポジトリはつくられない
- S3、ECRに関するバケット、リポジトリが専用で作成される
- 制約
- CDK Pipeline現状非対応
- ECRリポジトリが20個に限定される
- まだalpha版なので破壊的変更の可能性がある
- 既知のバグがある
- 変わらないこと
- まとめ
- アプリごとにアセットを保存することでS3ライフサイクル管理がApp毎にできるようになる
今こそ始める、CDKコンストラクトライブラリ開発 ― 入門から実践まで
- CDKコンストラクトライブラリを開発するうえでの利点
- ライブラリ化のメリット
- npm installで導入できる、全世界で使える
- depricationを通知できる、更新を促せる
- 開発者としての学びが多い
- PdM、マーケティング、OSS、ライブラリの運用
- ライブラリの例
- cdk-nag, cdk-ecr-deployment, cdk-remote-stack, PDK
- 配布方法
- aws-cdk-lib
- open-constructs GitHub
- self-publish(今回)
- 自身で公開、メンテナンスへの責任を負う
- 知っておくといいこと
- 初級
- hayao_kのProjenによる方法が2020年あたりの記事だが今もほとんど変化ない
- new projen new awscdk-construct
- .projecrc.tsで構成を整理できる
- TSでpackage.jsonや.pretterrcなどの構築をする、直接npm installしない
- Construct Hubに掲載
- 特定の条件に準拠する必要がある
- jsii-compliantなTSを書く必要がある
- jsiiは他言語で利用できる仕組み
- Union型を使わない、camelCase, PascalCaseの準拠などいくつかある
- jsiiは他言語で利用できる仕組み
- jsii-compliantなTSを書く必要がある
- TS専用の道をいくライブラリもある
- AmplifyAuth、CDK decoratorなどの実例がある
- 特定の条件に準拠する必要がある
- hayao_kのProjenによる方法が2020年あたりの記事だが今もほとんど変化ない
- 中級
- README.mdの書き方
- Semantic versioning、conventional commitsに従う
- Semantic versioningとは
- MAJOR.MINOR.PATCHでバージョン番号を分ける
- conventional commitsとは
- コミットメッセージにルールを与える、Semantic versioningのバージョン番号の採番をしやすくする
- Semantic versioningとは
- Lambda関数のコードをライブラリに含める
- NodejsFunctionなどビルド時に処理がかかる方法をすすめない
- インストール時点でビルド済みにしたほうがいい
- Projenで指定するのがおすすめ
- SingletonFunctionを使うと何度定義されても実態は1つになるので余計な関数が作られない
- Inline code(Zipfile)を使うとS3アセットを使わずにCfnテンプレート内に埋め込まれる
- CloudFormationカスタムリソースに関する知識があるとよい
- ライブラリ側でつくるとユーザー側が助かる
- Lambda関数を作ってイベントに対する処理を書くとリソース管理できるようになる
- 作成時、更新時、削除時
- あらゆる例外時にCfnに返してあげることが大事
- タイムアウト時間がとても長くなる(15分~1時間)
- integ-runnerを導入する
- CDKコードのintegration test用フレームワーク
- ライブラリ開発では重要
- スナップショットテストが自動でできる
- ライブラリ開発では重要
- CDKコードのintegration test用フレームワーク
- 上級
- 最小CDKバージョンの選択
- あらゆるバージョンから使用される可能性があるので表明が必要、最小バージョンでの検証をする
- 上げると機能豊富になるが下げるとユーザーが増えるというトレードオフ
- 2.38.0がinteg-runnerができたのでおすすめ
- feature flagどうする
- フラグが40個以上存在するので網羅は難しい
- 関連するフラグを調べる、全ON全OFF、無視するという選択などある
- 最小CDKバージョンの選択
- 初級
大規模ドラレコデータ収集・機械学習基盤を支えるAWS CDK 〜導入・運用事例紹介〜
- CDKを使ったバッチベースのデータパイプラインインフラの運用事例について
- 自動車のドラレコやジャイロセンサーを吸い上げて道路標識と地図の差分を検出したい
- Lambda、ECS、Batchでセンサー収集→S3に格納→AWS Batchで推定→Auroraに保存
- airflowなどは使っていない
- Lambda、ECS、Batchでセンサー収集→S3に格納→AWS Batchで推定→Auroraに保存
- 運用
- 2020/07から運用している
- スタック数
- prod60, qa385, dev80
- 切るべきでないという話はあったが…いまは動かせてる
- データエンジニア5人、MLOps1人
- prod60, qa385, dev80
- 経緯
- もともと研究開発PJだったのでスクラップ&ビルドだった
- 短く記述できるから
- AWSが99%のため
- DEV,QA,PRODでの一貫性のあるインフラ構築
- もともとCDK使ってたので推薦した
- 構成
- 共通インフラのスタック、モジュールごとにLambda、S3別にスタックを作る
- デプロイ
- AWS CDKとGitHub Actionsによる環境
- デプロイの流れ
- 環境とモジュールを指定してデプロイ、テストを実行、マージしてタグ付け、デプロイ実施
- ワークフロー
- git cloneしてOIDCで認証、make build、make depoy
- Makefileで定義するルールを定めている
- make buildでビルド作業をmake(cdk build、go build、docker buildなど)
- make deployでデプロイ作業(cdk deploy、docker pushなど)
- Makefileで定義するルールを定めている
- git cloneしてOIDCで認証、make build、make depoy
- デプロイの流れ
- AWS CDKとGitHub Actionsによる環境
- CDK実装ルール(ガイドライン)
- スタック間の参照ルール
- モジュール間、内で弱い参照を推奨
- SSM, Secrets Manager、命名規則に沿ったリソース名
- 強い参照はモジュール内でのみ使って良いということにしている
- Props参照渡し
- 依存環境が辛くなるので極力使わない
- モジュール間、内で弱い参照を推奨
- 複数環境へはcontextで制御している
- cdk.jsonで定義することがほとんどだが規定はしていない
- リソース名命名規則を作っている
- スタック間の参照ルール
- qa環境を量産する
- 機械学習を使うため実験環境をたくさんつくりたい
- 特にAWS Batchのロジックが量産される
- 実験環境をJSONなどで用意してデプロイ時にcontextを使って実験環境の実験IDを指定する
- GitHub Actionsを動かすことで共通環境上に実験環境を生やす
- 実装上でも実験環境のファイルを参照している
- 最後に
- やってよかったこと
- 先にCDK込みのCICDを作る→デプロイとテストのループを気軽に回す環境ができた
- CDKを直接叩かない→contextなどの設定ミスによる事故を減らせる、ジョインしたメンバーも環境をすぐに作れる
- CDK管理外のリソース恐怖症になった
- 権限管理がCDKだとしやすい
- 冪等性を確保できた
- やればよかった
- cdk.jsonによる管理は型チェックなどできないのでつらい
- スタックわけすぎ問題
- スタック間参照が辛くなるとうのがあるが、正直そこまで困ってない
- CICDのロール権限が強すぎる
- 強い権限でないとデプロイできないがセキュリティ上の強さがある
- コミュニティに関わっておく
- こもって作っていたのでプラクティスをやってこなかった
- やってよかったこと
AWS CDKにおける「再利用性」を考える
- 再利用性とは
- 使い回しが聞くこと
- リポジトリ内外で使い回せる
- 内:クラスを作ってループする
- 外:汎用的なコンストラクト
- どのように実現するか
- コンストラクトをつくる→どうやって作るかのポイントを紹介
- ポイント
- スタックのPropsをそのままConstructに渡さない
- スタックに依存するので他のリポジトリで使えなくなってしまう
- 無駄なプロパティも連携されてしまう
- プロパティはreadonlyにする
- 入力値が上書きされてしまうと信頼性がなくなり安全性がなくなる
- 何度も使えなくなる
- 入力値が上書きされてしまうと信頼性がなくなり安全性がなくなる
- PropsのバリデーションはTokenに注意
- Token:後で分かる値を仮であてる仕組み
- 例:S3バケット名はデプロイ時に決まる
- トークンは仮の値なのでバリデーションできないということ
- Token.isUnresolved()でトークンかどうかを判断できる
- コンストラクト側では常にトークンを意識する必要がある
- Propsで何が呼ばれるかわからないため
- Token:後で分かる値を仮であてる仕組み
- 公開するプロパティはIXxx型にする(インターフェース型)
- IXxxは読み込み専用のリソースとして定義されている
- 管理外からリソースを参照する仕組み(fromXXXNameArn等のメソッド)
- 書き換え可能なリソースと区別するためにインターフェースを用意している
- IXxxを実装することで更新用のメソッドを追加で定義している
- 書き換え可能なリソースと区別するためにインターフェースを用意している
- 管理外からリソースを参照する仕組み(fromXXXNameArn等のメソッド)
- Ixxxを使うことで
- 読み込み専用リソースも扱えるようになる
- 同じインターフェースをもつ拡張した型を渡せるようになる(ポリモーフィズムによる利点)
- 参照される場合は更新される危険が減る
- IXxxは読み込み専用のリソースとして定義されている
- 公開するプロパティにプリミティブ型を避ける
- Constructを渡すと内部で他の便利な機能を利用できるため
- publicメソッドを用意する
- 利便性を上げるために追加しようという話
- アタッチするメソッドを作るとコンストラクタがシンプルになるしif文がなくなり可読性も上がる
- 例wafにregionalリソースをアタッチ
- バレル(index.ts)でモジュール性向上
- index.tsでexportのみ書かれたファイルのこと
- ファイルでコンストラクトを分けて定義してindex.tsを定義
import {XXX, YYY} from "./xxx
のようにかけるようになりimportが簡素化される*
で読み込むことも可能- index.tsでexportしなければ公開範囲を制御できる
- Construct単位でのユニットテスト
- Constructに分けることでテストがしやすくなる
- 基本的にはスタック単位のテストでOK
- スタックのPropsをそのままConstructに渡さない