echo("備忘録");

IT技術やプログラミング関連など、技術系の事を備忘録的にまとめています。

【DynamoDB】キャパシティモード(オンデマンド/プロビジョンド)の違いを改めて学ぶ

はじめに

DynamoDBのキャパシティーモード(オンデマンド/プロビジョニング)、及びそれによる違いについて書こうと思います。

※自分の備忘録を兼ねてます。*1

前提その1:「キャパシティーモード」って?

ざっくり言うと「DynamoDBの動作モード(みたいなもの)」となります。
DynamoDBには、下記2つのモードがあります。

  • オンデマンド(デフォルト)
  • プロビジョンド

キャパシティーモードにより大きく異なるのは、主に以下2つです。

  • 高負荷時の動作(≒オートスケーリング)
  • 課金体系

前提その2:「リクエストユニット」「キャパシティユニット」って?

オンデマンドとプロビジョンド、どちらのモードにせよ、DynamoDBの課金は「ユニット」で実施されます。
このユニットですが、オンデマンド・プロビジョンドで、それぞれ下記の名称となっています。

モード 名称 書き込み単位 読み込み単位 備考
オンデマンド 要求ユニット(RU) WRU RRU RUのRはRequestのR
プロビジョンド キャパシティユニット(CU) WCU RCU

一見ややこしそうですが、RU/CU共に読み込み・書き込み時の1ユニットの定義はほぼ同じで、下表のようになっています。(詳細は各モードの説明で触れます)

※書き込み/読み込み容量が増えると、その分消費RU/CUも増えます

書き込み時

※1KBまでの書き込みに対して、下記のWRU/WCUを消費する。

書き込みモード 消費WRU/WCU数 備考
標準書き込み 1 デフォルトはこれ
トランザクション書き込み 2
読み込み時

※4KBまでの読み込みに対して、下記のRRU/RCUを消費する。(なお料金計算時には、1未満の端数は1に切り上げられます)

読み込みモード 消費RRU/RCU数 備考
結果整合性 0.5 デフォルトはこれ。
強力な整合性 1
トランザクション 2

オンデマンドモード

オンデマンドモードは、いわゆる「使った(=読み書きした)分だけ料金を支払う」モードです。(サーバーレスっぽい動作)

以下の特徴があります。

細かい設定・管理が不要

「使った分だけ払う」モードなので、事前にあれこれ細かい設定が不要で「とりあえずDynamoDBを使ってみる」のに向いています。
そのため、あらかじめ利用状況の予測が出来なくても使用可能です。

リクエスト数の変化に強い

リクエスト数の急激な変化にもDynamoDB側で柔軟に対応してくれるので(Auto Scalling)、予想外のリクエストにも強いです。(もちろん限度はあります)

課金体系

  • 読み込み・書き込みリクエストで消費したWRU/RRUに対して課金されます。
  • 読み込み・書き込みリクエストで消費するWRU/RRUは「前提その2」の表の通りです。

※キャパシティモードと違い「1秒当たり」という条件はありません。(あくまでも実際に消費したWRU/RRUに対する課金)

プロビジョンドモード

プロビジョンドモードは、想定される消費WRU/RCUを事前に設定しておくモードです。
オンデマンドモードと違い、ある程度運用管理の手間が発生しますが、その分コストはオンデマンドより抑えられる傾向があります。(「で、どっちを使うべき?(ユースケース)」を参照)

なお、厳密にいうと、下記項目を事前に設定する必要があります。(読み込み/書き込み共に)

  • 最小&最大キャパシティユニット
  • 使用率
  • プロビジョンされた最初のユニット*2

特徴としては、以下の通りです。

オンデマンドモードより安価になる傾向がある

単価がオンデマンドモードより安価なため、オンデマンドモードよりコストを抑えられる傾向があります。

中~大規模な使用に向いている

規模が大きくなればなるほど「単価がオンデマンドモードより安価」の影響が大きくなってきます。
そのため規模が大きいほどプロビジョンドモードの恩恵も大きいです。(プロビジョンドモードが使用可能ならば)

課金体系

  • 「事前に設定したWCU/RCU」に対して課金が発生します。
    • 実際に消費したWCU/RCUは関係ありません
  • 「1秒あたり」でWCU/RCUを消費します。
    • オンデマンドモードと違い、時間の条件があります。

なお1秒あたりに消費するWCU/RCUは「前提その2」の表の通りです。

で、どっちを使うべき?(ユースケース)

一番気になる「どちらを使うべきなのか」ですが、個人的には下記ではないかと思います。

オンデマンドモードが良いケース

比較的小規模な場合

プロビジョンドモードの説明で述べた通り「規模が大きくなるほどプロビジョンドモードとオンデマンドモードの差は大きくなりがち」です。

逆にいうと、規模が小さい場合はそこまで差が発生しないので、運用管理コストを考えるとオンデマンドモードの方が良い場合が多いです。

利用状況が予測不可能な場合

プロビジョンドモードはあらかじめWCU/RCUを設定しておく必要があるので、利用状況が予測できないと使用しづらく、スロットリングの発生にもつながってしまいます。

オンデマンドモードはそのあたりをDynamoDB側が柔軟に対応してくれるので、利用状況が予測できない場合も扱いやすいです。

プロビジョンドモードが良いケース

中~大規模な場合

先述の通り、規模が大きくなればなるほどプロビジョンドモードとオンデマンドモードの差は大きくなりがちなので、中~大規模になる(=規模が大きくなる)場合、(利用状況が予測できるなら)プロビジョンドモードのほうが良いことが多いです。

利用状況が予測可能な場合

あらかじめ利用状況が予測できるなら、プロビジョンドモードの方が安価に済むケースが多いです。

ただし先程述べた通り、小規模だとそこまで差が発生しないので、運用管理コストを考えると中~大規模な場合にプロビジョンドモードを使用するのが良いかもしれません。

実際にプロダクトに導入する場合の使い方

実際にプロダクトで導入する場合は、

  1. まずはオンデマンドモードで導入し、しばらく様子を見る
  2. その後メトリクスで消費WCU/RCUを確認し、WCU/RCUの目星が付く&切り替えた方が良い場合は、プロビジョンドモードに切り替える

というステップを踏むのが良いと思います。

ちなみに消費WCU/RCUは、下記メトリクスで確認できます。(このメトリクスはプロビジョンドモードにおいても「実際に消費したWCU/RCU数」を示します)

  • ConsumedWriteCapacityUnits(書き込み)
  • ConsumedReadCapacityUnits(読み込み)

参考: DynamoDB のメトリクスとディメンション

またプロビジョンモードは運用管理の手間もある程度発生しますので、単にコストだけでなく、そういった手間も考慮してどちらにするか決めた方が良いと思います。

(参考)プロビジョンドモードとオンデマンドモードの損益分岐点

一般的に「プロビジョンドモード時の設定WCU/RCUに対して、実際のリクエスト数が14.4%程度の場合にオンデマンドモードとプロビジョンドモードの金額が一致する」そうです。

ざっくり言うと「実際のリクエスト数が、プロビジョンドモード時の設定WCU/RCUから算出したリクエスト数の14.4%以下ならオンデマンドモードの方が、それを超えるならプロビジョンドモードの方が安い」ということです。(詳細な計算方法は下記記事を参照)

dev.classmethod.jp

まとめ

以上、DynamoDBのキャパシティモードの違いでした。

私自身、プロビジョンドモードの仕様は何回扱ってもこんがらがってしまう部分があるので(特に設定や課金体系)、定期的に見直していきたいと思いました。

宣伝

2/1(土)に富山で開催される「BuriKaigi 2025」において「Amazon Aurora バージョンアップについて、改めて理解する ~ バージョンアップ手法と文字コードへの影響 ~」というセッションで登壇させて頂くことになりました。

burikaigi.dev

内容としてはAmazon Aurora のバージョンアップ概要やバージョンアップしないことでの影響、またバージョンアップ時に気を付けることなどをお話しする予定です。

それでは、今回はこの辺で

*1:過去に何回か扱いましたがブログに書いてなかったので、今回いい機会だったのでブログにしました。

*2:テーブルまたはインデックスの開始時にプロビジョニングされる容量。オンデマンドからプロビジョニングされた容量モードに切り替えるとき、テーブルまたはインデックスのトラフィックを処理できるよう、十分に高い要領に設定する必要がある

【ポエム】2024年の振り返り

はじめに

(今更ですが)新年あけましておめでとうございます。今年もよろしくお願いいたします。

新春初ブログですが、2025年が始まりましたので、なんとなく2024年を振り返ろうと思いました。

良かったこと

いろんなご縁があった

2024年はDeNAからPayPayカード、そしてKDDIアジャイル開発センター(KAG)に転職したわけですが、どちらの会社も人とのご縁から採用に繋がったので、そういう意味で「縁」には恵まれているなあ、と感じた一年でした。

また、個人的にそれは色々な技術コミュニティ活動から生まれたものだと思っているので、それは今後も継続したいです。

「地方」イベントへの貢献

私が2024年初頭から標榜していた「地方イベントへの貢献(参加・登壇)」を実現できた点は良かった1年だなと思いました。
主に下記の地方イベントに参加しました。(特に北陸地方)

特に JAWS-UG 北陸新幹線 in 金沢では、CDKワークショップの講師(?)も経験させてもらい、非常に良い経験ができました。

下の「イマイチだったこと」にも書きましたが、2024年は体調&メンタル不調でブログのアプトプットが思うようにできなかったので、その分地方イベントでの登壇を頑張った感じです。

Auroraの知識が深まった

仕事でAurora MySQL5.7→8.0 バージョンアップ業務を経験したことで、Auroraの知識が広まりました。
特に、単にアプリでDBを使用するだけではなかなか分からないバージョンアップ手法や各バージョンアップ手法の課題など、運用面の知識が深まったのは非常に良かったです。

イマイチだったこと

体調&メンタル不調

とにかく2024年はこれに悩まされました。
体調もそうなんですが、メンタル(特に脳)の不調がひどく、日常的に活力が湧かない&頭が回らないという状態で、(業務はもちろん)プライベートでもなかなかスキルアップやアウトプット活動ができませんでした。

これは今後の人生にも支障が出そうなので、1日でも早く治したいと思っています。(仕事・私生活ともに、環境の影響が大きいのかも...何かご存じの方がいらっしゃったら、アドバイス頂けると助かります)

手を動かす機会が減った

業務の関係もあり、2024年は直接手を動かす(=何かを作る)という作業が極端に減りました。(調べものをして終わり、など)
もちろん業務上そういうこともあるのは認識してますが、2024年は本当にそういう業務がほとんどで、ちょっと消化不良な部分がありました。

逆にいうと、それを通して改めて自分は「手を動かす仕事が好きなんだな」と再認識できました。

考えすぎ

2024年は業務でいろんな悩み(自己実現・人間関係など)があり、その結果メンタル不調&転職をしたのですが、今考えてみたら「なんかあれこれ考えすぎだったんじゃね?」と思います。

今はなんとなくわかりますが、そりゃ企業に属している以上100%自分の要求が実現できるわけないですし、色々な人物はいるので、それで自分があれこれ考える必要もなかったのかなあと。

また、自分はついつい

  • ここままで将来食べていけるのか
  • このままコンフォートゾーンにずっとい続けていいのか

など悲観的になりがち&自問自答をしがちなのですが、もうちょっと「まあ9割のことはなんとかなるから、とりあえずもちつけ」と、気楽な心構えでいいのかもしれません。(焦りは禁物だし、正常な判断を狂わせるので)

もっと自分でもできることあったでしょ

先程「自分の欲求の実現」の話をしましたが、これについては転職後にいろんなイベントでいろいろな方の事例*1を聞くにつれ

  • もっと自分でも出来ることが色々あっただろ
  • 相手を納得させるために、自分で何か改善アクションは起こしたのか?
  • 相手を納得させるだけの材料は用意したのか?

などなど、色々自分に足りなかった部分を認識し、正直自分の認識や考えに至らない部分が多かった...と、今でも反省しています。*2

これについては自分の戒めとし、今後そういうこともちゃんと認識した上で、しっかり成果も残してしていこうと思いました。*3

まとめ

という訳で、2024年の振り返りでした。

2024年を統括すると「メンタル不調&悩みが多く、あまりいい1年ではなかったけど、それでも良かった部分もある」1年でした。

最後に2025年の抱負ですが、あえてあまり大きい目標は掲げず、とりあえず

  • 無理しない
  • 悩みすぎず、楽観的になる
  • 「『今の自分』ができる範囲のベスト」を尽くす

ということを意識していこうと思います。

あと、ブログのアウトプットやコミュニティ活動は今後も継続していきたいと思います。
とりあえず「今年もAWS Community Builderに認定される」というのが当面の目標ですかね。

宣伝

来月 2/1(土) に富山で開催される「BuriKaigi 2025」において「Amazon Aurora バージョンアップについて、改めて理解する ~ バージョンアップ手法と文字コードへの影響 ~」というセッションで登壇させて頂くことになりました。

burikaigi.dev

内容としては

  • Amazon Aurora のバージョンアップ概要
  • バージョンアップしないことでの影響
  • バージョンアップ時に気を付けること

などをお話しする予定です。(「良かったこと」に書いた「Auroraの知識が深まった」に書いた、Aurora MySQLバージョンアップ作業で得た知識がベースになっています)

それでは、今回はこの辺で。
改めまして、今年もよろしくお願いいたします。

*1:特に、JAWS Festa 2024 懇親会1次会でのAWS Hero 三浦さんの話はめちゃめちゃ刺さりました

*2:正直、1年経った今でも思い出したり、夢に出てくるくらい後悔しています...

*3:それこそ、場合によっては以前在籍した企業にまたお声をかけて頂けるくらいに

【AWS CDK】CDK Pipelinesのself-mutateについて理解する

はじめに

お久しぶりです。
以前の記事で書いた通り、なかなか体調不良が良くならず、また前回から間が空いてしまいました。

で、半年ぶりの技術ブログですが、今回はCDK Pipelinesのself-mutateについてになります。

なおこの記事は AWS CDK Advent Calendar 2024 22日目の記事のはずでしたが、私が先週に軽い肺炎を患ってしまった関係で、投稿が遅くなってしまいました。大変失礼いたしました。

前提:CDK Pipelinesって?

CDK Pipelinesとは、AWS CodePipeline(以下「CodePipeline」)を利用したデプロイパイプラインをCodeBuildやCodeDeployなどを個別に定義することなく作成できる、AWS CDKのライブラリになります。*1

CDK的にはL3コンストラクタとなっており、より少ない定義でデプロイパイプラインを構築できるので、下記のようなケースに向いています。

  • CodePipelineについて詳しく知らないけど、とりあえずデプロイパイプラインを構築したい
  • あまり細かい制御はいらないから、細かい管理はしたくない

なお「CDK Pipelinesの概要を理解したい!」という方は、私が「JAWS-UG CDK支部 #16 ~CDK Conference 2024 Extra~」で発表した資料がありますので、よろしければそちらを参照ください。*2

speakerdeck.com

self-mutateって?

self-mutateとはCDK Pipelinesの機能の1つで、「デプロイが実施された際にCodePipelineの定義を再構成する(≒CodePipelineの部分だけを先にデプロイする)」という仕組みです。

が、この仕組みが結構分かりにくいので、その仕組みを説明します。(これがCDK Pipelinesが敬遠される理由の一つになってます...)

self-mutateの背景

CodePipelineでデプロイを行った場合、CodePipelineの定義は「デプロイを行った時点の定義」が適用されます。
ちょっと分かりにくいのですが、最新のデプロイでの変更内容に「CodePipeline自体の変更」が含まれていたとしても、最新のデプロイの実行にその変更は適用されません。(あくまでも「デプロイを行った時点の定義」でデプロイが行われる)

これの何が不便かというと、最新デプロイにCodePipeline以外のリソース(Lambdaとか)の変更も含まれており、デプロイ時に「変更したCodePipeline定義を適用したい(=最新のCodePipeline定義でデプロイしたい)」という場合、

  • 最初にCodePipelineとLambdaをデプロイする
    • このデプロイでは「変更したCodePipeline定義」は適用されない
  • 次にLambdaのみデプロイする
    • このデプロイで「変更したCodePipeline定義」が適用される

という2ステップを踏まねばならず、2度手間になってしまいます。

self-mutateの仕組みとメリット

上記の問題を解決するための仕組みがself-mutateです。 self-mutateでは上記の問題を「CodePipeline定義だけを先にデプロイする」ことで解決しています。

つまり、最新デプロイにCodePipeline以外のリソースの変更が含まれていても、下記の挙動を取ることで、常に最新のCodePipeline定義でデプロイが実行されるようになっています。
これがself-mutateのメリットです。

  1. まずCodePipelineの変更だけを先にデプロイする
  2. 1が完了後、CodePipeline以外のリソースをデプロイする

簡単に図解すると、下記のような感じです。

self-mutateのデメリット

ただし、当然self-mutateにもデメリットはあり、具体的には以下の点が挙げられます。

デプロイに時間がかかる

先述の通り、self-mutateでは「CodePipeline」と「それ以外のリソース」でデプロイが分かれるため、内部的には2回デプロイが実行されます。
その結果、デプロイにより多くの時間がかかってしまいます。

本番環境ならともかく、開発環境だと煩わしく感じてしまうかもしれません。

※なおself-mutateは設定でOFFにすることもできますが、あくまでも開発用途での一時的なものであり、本番環境でOFFにすることは推奨されていません。

分かりにくい

上記の「2回デプロイが実行される」だったり「CodePipeline以外のリソース用のスタックを別で作成する」など複雑な部分があり、最初はどうしても分かりにくいと思います。(実際、それが理由でCDK Pipelinesを敬遠してしまう、というケースも多いと聞きます)

CodePipelinesの変更頻度

(これはself-mutate自体のデメリットではないですが)実際のところ、CodePipelineの変更が発生するのは開発初期の期間のみで、それが終わればあまり変更は発生しないことが多いです。
また仮に変更が発生したとしても、CodePipeline以外のリソースのデプロイに影響がなければ別に問題ないので、デプロイ時間や手間などのことを考えると「そこまでして導入するメリットが...」となるかもしれません。

まとめ

以上、CDK Pipelinesのself-mutateについての説明でした。

正直CDK Pipelinesやself-mutateは最初は分かりにくい部分が多く敬遠されがちですが、慣れると「より少ない定義でデプロイパイプラインを構築できる」「常に最新のデプロイ定義でデプロイを実行できる」などのメリットもあるので、もしデプロイパイプラインを構築で課題を抱えている場合は、一度導入を検討をしてみるのもよいのではないかと思います。

宣伝

ちょっと先の話になりますが、来年2/1(土)に富山で開催される「BuriKaigi 2025」において「Amazon Aurora バージョンアップについて、改めて理解する ~ バージョンアップ手法と文字コードへの影響 ~」というセッションで登壇させて頂くことになりました。

burikaigi.dev

内容としてはAmazon Aurora のバージョンアップ概要やバージョンアップしないことでの影響、またバージョンアップ時に気を付けることなどをお話しする予定です。

宣伝その2

私事になりますが、12月よりKDDIアジャイル開発センター(KAG)に入社しました。

kddi-agile.com

主に名古屋オフィスにて、

  • ITを活用した地方の発展への貢献
  • 各種コミュニティ活動&貢献(特に地方)
  • 名古屋オフィスの事業拡大

に貢献していきたいと思っていますので、これからもよろしくお願いいたします。(それ以前に、まずは自分の体調を治すことが最優先かもしれませんが...)

なおカジュアル面談を随時募集中ですので「KAGについて詳しく知りたい」「KAG応募したいけど、ちょっと不安がある」などある場合は、ぜひ遠慮なくお声がけください。

それでは、投稿遅れてしまってすいませんが、今回はこの辺で。
皆様、良いお年を!

*1:なおCDK Pipelinesはaws-cdk-lib/pipelinesモジュールに属しています。ちなみにCodePipelineはaws-cdk-lib/aws-codepipelineモジュールに属していますが、これとは別物です

*2:本当はCDK Pipelinesについて詳しく書こうとしたのですが、今年はオフラインイベントで結構CDK Pipelinesの事を話しているので、今回はself-mutateにのみフォーカスを当てました

【JAWS】JAWS FESTA 2024 in 広島に参加しました

今回のお題

10/11(金)~10/13(日)に開催された「JAWS FESTA 2024 in 広島」に参加してきましたので、その感想です。

公式サイトはこちら

jawsfesta2024.jaws-ug.jp

JAWS FESTAって何?

JAWS-UG(Japan AWS User Group)が開催する、大きなカンファレンスイベントの一つ。

JAWS-UGが開催する大きなカンファレンスイベントとして

  • JAWS DAYS(春頃に開催)
  • JAWS FESTA(秋頃に開催) ※今回はこっち

の2つがあり、今回のJAWS FESTAは広島で開催されました。(去年は福岡)

前夜祭

前夜祭はEight SupperClubという豪華なクラブで立食パーティー形式で開催され、LT大会で盛り上がりました。

個人的には アイレット株式会社のこまきちさん (@komakichidev) の 「実家の娘情シス」の発表 が印象的でした(アーキテクチャが完全にガチ勢のそれ)

その後(非公式の)2次会では、ジャニさん(@beajourneyman)、三戸さん(@mito_tetsuya)、市野さん(@kazzpapa3)と一緒に(人生初の)コンカフェに行ったり、汁なし担担麺を食べたりしました。(こういう時じゃないと行かないからなあ)



本編

会場は広島大学で、敷地が広い&自然豊かで、非常にキャンパスライフを過ごしやすい大学だなあと思いました。

キーノートでは現職の広島県知事である湯崎 英彦氏が登場し、広島県における AI 活用の事例を紹介してくれました。
「失敗を許す」「失敗を活かす」など、いわゆる最新のIT系の考えをバリバリの公官庁(しかも中国地方の中核である広島県で)で積極的に取り入れているのはすごいなあと思いました。

なお本編に関しては、僕自身は当日ボランティアとしてDトラックの午後セッションの司会を担当していたため、正直あまりセッションは聞けませんでした(ここは今回残念な部分)

ただ、たまたまDトラックの午後セッションがCloudFormationやAmplify Gen2(内部的にAWS CDKを使用)といった、個人的に大好きなInfrastructure as Codeに関係する内容だったため、結果的には非常に有意義な時間を過ごせました。

あとこの日の夜、ホテルのエレベータで参加者の方に「本日は司会、お疲れさまでした」と言われたのがとてもうれしかったです。


懇親会

懇親会は1次会は近くの西条HAKUWAホテル、2次会はたまたま同じタイミングで開催されていた西条酒まつりでした。(3次会もあったんですが、こちらは店員オーバーで参加できず)

正直、JAWS FESTA開催前は「さすがに懇親会多すぎ&長すぎじゃね?」と思っていたんですが、いざ参加したら「まあ、これはこれでこういうのもありか」と思いました。

特に(後で知ったんですが)広島県西条市は「日本三大酒どころ」の一つだけあって、西条酒まつりってめちゃくちゃ有名なんですね。
それを知って「そりゃあえて酒まつりをイベントに組み込むわな」と納得。

あと、1次会でのAWS HERO三浦さん(@miu_crescent)のLTが、自分にとって(足りなかった部分&反省する部分があるという意味で)すごい刺さる内容であり、とても心に残りました。(あと北海道の酪農の歴史も学べて、すごく良かったです)

その後、広島市で知人と個人的に3次会を...と思ったんですが、タイミングが合わなかった&前日かなり寝不足だったのもあり、この日は早めに就寝。


おとなの遠足

最終日は参加希望者のみで、「おとなの遠足」という(健全な)イベントに参加。

午前に厳島神社参拝、午後はOKOSTA(オタフクソースさん直営の施設)でお好み焼きハンズオン(=自分で作る体験)をしてきました。

厳島神社は半年前のYAPC::Hiroshima で来て以来でしたが、半年前と違って今回は鳥居まで歩いて行けたので、また違った体験ができました。(前回は満潮で眺めるしかできなかった)

そしてOKOSTAのお好み焼き体験では、正直「どうせ失敗するだろうし、帰りに別の場所で締めのお好み焼き食べていくか...」くらいな感覚でしたが、(講師の方の教えもあり)やってみたら意外とうまくできたので(作るのも味も)、思いがけずいい体験ができましたし、結果的にこれが締めのお好み焼きとなって、いい思い出になりました。



その他

そしてその後すぐに帰宅...しようと思いましたが、少しだけ時間があったので、電車で呉市へ。
あまり時間はなかったのですが、大和ミュージアムに行ってきました。(たまたま艦これのイベントもやってましたが、僕は全く分からないのでスルー)

そして広島駅に戻り、そのまま岐路につきました。

まとめ

昨年同様、今回もとても有意義な時間を過ごせました。

正直最初は先述の通り「懇親会多すぎ&長すぎじゃね?」と思っていたんですが、これはこれでありかもな...と思いましたし、広島のことをよく知るきっかけにもなったので「地方のITでの発展に貢献する」というのをここ数年で真剣に考えるようになった自分にとって、結果的に非常に有意義な機会となりました。

正直メンタル不調など諸々の理由で参加を結構悩んでいたんですが、今は参加して本当に良かったと思っています。

ただ残念ながら、今回はCFP落選してしまったので、次回はぜひ登壇者として参加出来たらなと思いました。

また「地方のITでの発展に貢献する」ためにも、こういう地方での大きいイベントには積極的に何かしらの形で貢献しようと思います。

それでは、少々長くなりましたが、今回はこの辺で。

【JAWS】JAWS Pankration 2024で登壇しました

はじめに

めちゃくちゃお久しぶりです。
体調不良(特にメンタル不調。自律神経失調症?)がひどく、数か月間まともにブログすら書けませんでした。

久々のブログとなる今回は、まさに本日「JAWS Pankration 2024」で登壇したので、その話です。

JAWS Pankration 2024って何?

JAWS-UG(Japan AWS User Group)による、地球規模の交流イベント。
2024/8/24 12:00~2024/8/25 12:00まで24時間ぶっ通しで行われる、完全オンラインイベントです。

最近は嬉しいことにオフラインイベントが増えてきたのですが、このJAWS Pankration 2024は完全オンラインイベントです。

また「地球規模の」というだけあり、日本のみならず、世界各地の方が発表者です。(例えばアメリカ、イギリス、ドイツ、インドネシアなど)

前回は3年前の2021年に開催されましたが、それ以来3年ぶりの開催になります。(ちなみに、私は前回も登壇しています)

jawspankration2024.jaws-ug.jp

発表内容は?

8/25(日) AM8:00より「What is Lambdaless Serverless」という、AWSの淡路さんがAWS Summit Japanで発表されていた「Lambdaレスなサーバーレス」に関する私なりの考察を発表しました。

speakerdeck.com

内容的には、JAWS-UG Okayama 2024の懇親会LTで発表した内容をベースに(このあたりはまたブログに書きます) 、アドバイスを頂いた点などを加筆修正したもので、概要としては以下になります。

  • Lambdaがなくてもできる処理ではLambdaを無くすことで、構成をシンプルに出来るよ
  • ただしそれ相応のデメリットもあるから、うまく使い分けようね(お約束の「銀の弾丸はない」)
  • 「Lambdaを使うのがアンチパターン」なんてことは100%ありえないよ

JAWS Pankration 2024ですごいなあと思ったこと

修正対応が早い

「ライブ動画見てるとブラックアウトする」「前の人の翻訳がずっと残ってる」「翻訳の増加に合わせて、自動スクロールしてほしい」など、開催中に色々不都合や要望が出たのですが、それへの対応が早くてびっくりしました。
早急に実装して本番デプロイするのもそうなのですが、 「ライブ動画見てるとブラックアウトする」について、原因を早急に見つけられることもすごいなあと思いました。

ダウンタイム0

これだけ世界中から数多くの方が視聴し、リアルタイム翻訳も実施する中、1回も遅延らしい遅延やサイトダウンが発生しませんでした。
これは本当にすごいと思いました。

タイムキーピングが完璧

今回のイベント、もちろんタイムテーブルが決められていたのですが、完全に時間通りで、遅れが全く発生しませんでした。
もちろん(私含め)登壇者が気を付けていたのもあるのですが、運営の方のタイムキーピングが完璧だなあと思いました。

ちなみに今回は「15分経過したらたとえ発表途中でも強制終了」というスタンスだったのですが、個人的にこのスタンスはメリハリがついて、とても良いなと思いました。(ちなみにNGK(名古屋合同懇親会)もこのスタンスです。なんならNGKは持ち時間より早く終わるのもNGで、その場合は時間まで何とかして間をつなぐ必要があります)

個人的に良かったこと

モチベーションアップ

「はじめに」に書いた通り、ここ半年以上体調不良(特にメンタル不調)がひどく、なかなか気力もわかなかったのですが、今回久々にこういう大きなイベントで登壇させて頂いて、元気・気力をもらった感じがしました。
またモチベーションアップにもつながりました。

やりたいことが明確になった

今年に入ってから、自分がやりたいことや進むべき方向についてかなり悩んでおり(転職もしてしまったほどですし)、まだそれが続いていたのですが、今回色々な方のセッションを聞くことで「なんだかんだで自分は『アプリ』(のバックエンドやアーキテクチャ、IaC、CI/CDなど)がやりたかったんだ」ということが明確に分かりました。

AWS Summit Japan同様、こういう大きいイベントに参加したからこそ分かったことだと思います。

個人的な反省点

集合時間に間に合わなかった

登壇者は発表時間の30分前に「VoicePing」という控室みたいな場所にログインする必要があったのですが、直前にバタバタしてしまったこと、そして最初なぜかログインできなかったことがあり(Chromeを再起動したら直った)、集合時間にログインできず、しかも運営の方からの「ログインお願いします」という連絡にも気づいていませんでした。
この点は反省し、次回はちゃんと時間厳守で行動しないといけないと感じました。

なお補足すると、AM8:00という早い時間なので「実は寝坊してる?」的なことを思われた方もいるかもしれませんが、ちゃんと朝6:30に起床してます。

セッションが短かったかも

前述の通り持ち時間は15分で「時間オーバーは絶対NG」だったので、それだけはしないようにと意識しすぎたのか、10分もかからず終了する結果になり、さすがに短すぎたかもと個人的には感じました。

一応、前日にリハをやった際に時間が短かったので内容を追加したのですが、もう少し長くても(せめて10分)良かったかなと思いました。(NGKなら勝手に質疑応答タイムしてたかも)

まとめ

今回は「発表資料はすべて英語」ということで大変だった部分もありますが、なんだかんだで非常に充実した時間を過ごせました。
やはりこういうコミュニティイベントに参加したり、自分の知見をアウトプットするのは勉強になるし、充実するし、なにより気力アップやモチベーションアップにつながるので、これからも(時間とお金が許す限り)継続して行いたいと思いました。

最後に(朝早いにもかかわらず)私の発表を聴いてくれた方、ありがとうございました。
そして参加者の皆さん、お疲れさまでした。

そして何より運営の皆さん、「JAWS Pankration 2024」という素晴らしい機会を作って頂きまして、本当にありがとうございました&24時間お疲れさまでした。
とりあえず今日は無理せず、ゆっくり休んでください。(明日は有休を取っているはずだと信じてますが...)

という訳で、今回はこの辺で。

【AWS CDK】IAMロールにIAMポリシーをアタッチする際の挙動について調べてみた

今回の記事の概要

AWS CDK(以下「CDK」)でIAMロールにIAMポリシーをアタッチする際のアタッチ方法による挙動の違いを検証する

はじめに

IAMロール(以下「ロール」)を使用する際、「ロールにIAMポリシー(以下「ポリシー」)をアタッチして権限を設定する」ということを行います。(=ロールを割り当てたAWSリソースに適用する権限を設定する)

もちろんCDKでもそうなのですが、CDKではロールにポリシーをアタッチする方法が複数用意されています。

そこで、今回はこれらの方法による挙動の違いを検証したいと思います。

検証内容

具体的に、CDKでロールにポリシーをアタッチする手段として、下表のものがあります。(「説明」「備考」は AWS CDK Reference Documentation の説明を和訳したものです)

方法 説明 備考
inlinePolicies(props) このロールにインライン化する名前付きポリシーのリスト これでポリシーを設定した場合、CloudFormation(以下「CFn」)テンプレートで AWS::IAM::Policy の定義は作成されず、AWS::IAM::Role の1プロパティとして設定される
addToPolicy(メソッド) このプリンシパル(=ロール)のポリシーを追加する
addToPrincipalPolicy(メソッド) ロールのデフォルトのポリシーDocumentに権限を追加 デフォルトポリシーが未設定の場合、自動作成する
attachInlinePolicy(メソッド) このロールにポリシーをアタッチする

なお managedPolicies props、及びaddManagedPolicy メソッドなどの「『AWS管理ポリシー』をアタッチする処理」は下記の挙動が明確なため、今回は除外します。

  • ポリシーが新規に作成されない
  • 「AWS管理」としてポリシー単位で個別にアタッチされる

また applyRemovalPolicy メソッドは、(「Policy」とあるけど)「下記のケースにおいて、そのロールを残すかどうか」の設定であり、IAMポリシーとは無関係です。

  • このロールを定義しているスタックが削除された
  • CDKの定義からこのロールが削除された
  • 上書き不可の変更が発生したため、リソースを削除→再作成する必要がある

CDKコード

検証用に、下記CDK定義を作成してデプロイします。(関係部分のみ抜粋)

import { Role, Effect, ServicePrincipal, PolicyStatement, PolicyDocument, Policy, ManagedPolicy } from "aws-cdk-lib/aws-iam";  
  
// inlinePoliciesで適用するポリシー
const inlinePolicy = new PolicyDocument({
  statements: [new PolicyStatement({
    actions: ['dynamodb:Scan'],
    effect: Effect.ALLOW,
    resources: ['*']
  })]
});
  
// addToPolicyで適用するポリシー
const policy = new PolicyStatement({
  actions: ['dynamodb:Query'],
  effect: Effect.ALLOW,
  resources: ['*']
});
      
// addToPrincipalPolicyで適用するポリシー
const principalPolicy = new PolicyStatement({
  actions: ['dynamodb:GetItem'],
  effect: Effect.ALLOW,
  resources: ['*']
});
      
// attachInlinePolicyで適用するポリシー(ドキュメント)
const attachInlinePolicyDocument = new PolicyDocument({
  statements: [new PolicyStatement({
    actions: ['dynamodb:DescribeTable'],
    effect: Effect.ALLOW,
    resources: ['*'],
  })]
});
    
const attachInlinePolicy = new Policy(this, 'RoleAttachInlinePolicyId', {
  document: attachInlinePolicyDocument,
  policyName: 'RoleAttachInlinePolicy',
});
    
// ロール&ポリシーの設定
// managedPoliciesは個人的検証で使用しただけなので、スルーしてください
const role = new Role(this, 'LambdaRole', {
  assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
  roleName: 'RoleForPolicyAttachmentTest',
  managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName('AmazonDynamoDBReadOnlyAccess')],
  inlinePolicies: {
    'RolePropsInitialPolicy': inlinePolicy,
  },
});
    
role.addToPolicy(policy);
role.addToPrincipalPolicy(principalPolicy);
role.attachInlinePolicy(attachInlinePolicy);

検証結果

上記コードをデプロイした結果は、下図の通りで、概要としては以下の通りです。(下2つは画像はないですが、目視で確認)

  1. すべて「カスタマーインライン」として扱われる(「カスタマー管理」ではない)
  2. addToPrincipalPolicy と addToPolicy のポリシーは1つにまとめられる
  3. 逆に inlinePolicies propsとattachInlinePolicy のポリシーはそれぞれ個別に扱われる
  4. inlinePolicies props のポリシーは、CFnテンプレートで AWS::IAM::Policy の定義は作成されない(「検証内容」の表に記載した通り)
  5. 他のポリシーはAWS::IAM::Policy の定義はあるが、実際に「ポリシー」として作成はされない(「カスタマーインライン」だから?)

個人的に2と3は逆の感覚だったので、ちょっと意外でした。

まとめ

上記を踏まえ、CDKでロールにポリシーをアタッチする際は、下記のようにするのがいいのではないかと思いました。(あくまで個人の見解です)

  • InlinePolicy 系は、1つの手段にまとめる。
    • CFnのクオータ(最大500個)を考えると、テンプレートが作成されない inlinePolicies props にまとめるのが良い?
  • それ以外は、コードの可視性とか管理のしやすさなどで決めると良い
    • 正直、あまり深く考える必要はなさそう(CFnテンプレートでも1定義に集約されるので)

告知

今週土曜日の2024/06/08(土)に石川県金沢市で「JAWS-UG金沢 #99 CDKワークショップやってみよう」というAWS CDKのイベントが開催されます。

jawsug-kanazawa.doorkeeper.jp

こちらのイベントにゲスト(講師?)として参加させて頂くことになりましたので、よろしくお願いします。(ちなみにワークショップの内容も私が作成しています)

まだ数名ほど参加可能のようなので、興味がある方はぜひ参加してみてください。

それでは、今回はこの辺で。

【Bun.js】Bun がメジャーリリースされたけど、本当にBun はNode.js に取って代わるのか?の最新状況

今回のお題

Bun.js v1.0.12時点で出来なかった一部機能について、Bun.jsの最新版ではどうなったか...の検証記事

はじめに&宣伝

いきなり宣伝になってしまうのですが、本日(2024/05/19(金))発売の「Software Design 2024年6月号」誌において、「第2特集:[実証]Bun 次世代JavaScriptランタイムの実体に迫る」の記事を担当させて頂きました。

※ちなみに、担当したのは第1章と第3章です。

gihyo.jp

また記事内に記載の通り、「第3章:BunとNode.jsの徹底比較」の内容は、私が2023/11/19(日) に開催された、JSConf JP 2023 において発表した「Bun がメジャーリリースされたけど、本当にBun はNode.js に取って代わるのか?をAWS Lambda で検証してみた」の内容がベースになっています。(資料は以下)

speakerdeck.com

なおこの資料の中で「困った点」として、当時のBun.jsでは出来なかった点を挙げています。(当時のバージョンはv1.0.12)

しかしあれからBun.jsは頻繁にアップデートが行われ、日本時間で今年の4/1(月)に(マイナーアップデートバージョンである)v1.1.0がリリースされました。*1 *2

そこで今回は「Software Design記事のおまけ」的な感じで、上記の「困った点」について『最新のBun.jsではどうなっているか』の検証結果を記事にしようと思います。

アジェンダ

上記「困った点」の3つについての検証です。

前提

Bun.jsはv1.1.2で検証しています。(最新版でも同じ結果になるはず)

最新版が使えない(packages/bun-lambdaが動かない)

どんな現象?

Bun.js公式リポジトリ には、packages/bun-lambdaという、Bun.jsをAWS Lambdaで動かす際に必要なパッケージがあるのですが*3、これがエラーになってしまい動かない、という現象です。

最新版では?

最新版では上記現象は改修されており、問題なく動作します。(なお権限系のエラーは別途対応が必要です。Software Designの記事にも対応方法を記載しています)

ビルドファイルが動かない

どんな現象?

ビルド時(bun build) にnpmモジュールをバンドルすると、ビルド後のjsファイル実行時にエラーが発生してしまい、動かないというものです。

正常に動かすためには、ビルド後のjsファイルの先頭に以下2行を明示的に追加する必要がありました。

outputFile.write('import { createRequire as createImportMetaRequire } from "module";   
import.meta.require ||= (id) => createImportMetaRequire(import.meta.url)(id);\n\n');  

最新版では?

こちらも最新版では上記現象は改修されており、上記2行を追加しなくても問題なく動作します。

モジュールモック未対応

どんな現象?

Bun.jsのテスト用モジュール(bun:test)で、npmモジュールなどのモジュールモックは未対応だった。

最新版では?

最新版ではモジュールモックにも対応しており、npmモジュールのモックも可能です。(詳しくは公式ドキュメント を参照。またサンプルソースを末尾に記載しておきます)

またマッチャーのJest互換性について、かなりの数のマッチャーが対応済ですが、まだ未対応のマッチャーも存在します。

ちなみに、bun:test でLambda関数のテストを実施する際の注意点について、以下に記載しておきます。

レスポンスをtoEqual() するだけではダメ

単体テスト時のレスポンスについて、await expect(response).toEqual(expected) みたいに、単に戻り値をtoEqual()しただけでは正しく判定できません。(おそらく、レスポンスがResponseクラス(のインスタンス)であることに関係していると思われます。) *4

とりあえずの回避策として、APIGatewayProxyResultなど、別の形式に変換することで対応できます。(末尾のサンプルソースを参照)

aws-sdk-client-mock-jest のマッチャーが使えない

Lambda関数内でAWS SDKを使用している場合、単体テストに aws-sdk-client-mock-jest を使用するケースも多いと思いますが、aws-sdk-client-mock-jest の一部マッチャーが使えません。*5

これはBunとJestで、expect関数の戻り値の型が違うのが原因です。

  • Bun:Expect<T>åž‹
  • Jest:JestMatchers<T>åž‹

また、そもそもBun読み込んだ時点でJestのexpect(declare const expect)が上書きされてしまい、aws-sdk-client-mock-jestとの整合性が取れなくなってしまうようです。

これについては今のところ有効な対策がなさそうで、強いて言えば「bun:test を使わない(Jestを使う)」くらいしかありません。(もしわかる人がいましたら教えてください)

まとめ

以上、最新のBun.jsによる検証結果でした。
基本的に「困ったこと」の現象は全て改修されており、最新版では問題なく使えることが確認できました。

実際Bun.jsは今でも頻繁にアップデートが実施されているので、これからもどんどん使い勝手が良くなっていくでしょうね。
今後のBun.jsの進化に期待です。

最後に繰り返しになりますが、Software Design 2024年6月号、よろしくお願いいたします。

それでは、今回はこの辺で。

参考:npmモジュールモック&レスポンス変換のサンプルソース

import { expect, test, describe, mock, jest as bun_jest } from 'bun:test';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, GetCommand } from '@aws-sdk/lib-dynamodb';
import { mockClient } from 'aws-sdk-client-mock';
import { handler } from '../lambda/index_bun';
import { APIGatewayEvent, APIGatewayProxyResult } from "aws-lambda";
  
// npmモジュールをモックする例。  
// ここでは「uuid」をモックしています。
mock.module('uuid', () => {
  return {
    v4: bun_jest.fn(() => '1111-2222-3333-4444'),
  };
});
  
const dynamoDbOutput = {
  Type: 'treasure',
  Floor: '100'
};
  
// aws-sdk-client-mock やRequest、Responseなどで必要になる設定  
const testUrl = 'https://dummy.example.com';
const ddbMock = mockClient(DynamoDBDocumentClient);
const dynamodb = new DynamoDBClient({});
DynamoDBDocumentClient.from(dynamodb);
  
const eventData: APIGatewayEvent = {
  queryStringParameters: {
    "floor": "3"
  } 
} as unknown as APIGatewayEvent;
  
const headers = new Headers({
  'Content-Type': 'application/json'
});
  
const responseOptions = {
  status: 200,
  headers
};
  
const responseString = JSON.stringify({
    uuid: '1111-2222-3333-4444',
    item: dynamoDbOutput,
});
  
const expectedResponse = new Response(responseString, responseOptions);
  
describe('index_bun.handlerのテスト', () => {
  test('レスポンスが正しい事', async () => {
    ddbMock.on(GetCommand).resolves({
      Item: dynamoDbOutput,
    });
    
    const res = await handler(new Request(testUrl));
    
    // ResponseインスタンスをAPIGatewayProxyResult型に変換
    const [resResult, expectedResult] = await Promise.all([createApiGatewayProxyResultResponse(res), createApiGatewayProxyResultResponse(expectedResponse)]);
    
    expect(resResult).toEqual(expectedResult);
  });
});
  
// ResponseインスタンスをAPIGatewayProxyResultに変換する関数
async function createApiGatewayProxyResultResponse(res: Response): Promise<APIGatewayProxyResult> {
  const contextType = res.headers.get('Content-Type');
  const body = await res.json();
  const result = {
    statusCode: res.status,
    headers: {
      "Content-Type": contextType,
    },
    body: JSON.stringify(body),
  } as APIGatewayProxyResult;
  
  return result;
}

*1:なお執筆時点での最新版はv1.1.8です。

*2:4/1という日付から「エイプリルフールネタなんじゃね?」という噂も流れました

*3:正確には「Bun.jsをAWS Lambdaで動かす際に必要になるLambda Layerを作成する」処理です

*4:レスポンスの内容が異なっていてもtoEqual()の結果がtrueになる。

*5:toHaveReceivedCommandWith()で確認

' } }) e.innerHTML = codeBlock; });