Posts for: #Cdk

cdk の cloudfront の distribution 設定の移行

0時に寝て5時過ぎに起きた。

フロントエンドのインフラ作業の続き

昨日、cloudfront の distribution 設定のビヘイビアのキャッシュ設定が誤っていることに気付いたので cdk のコードを修正していく。Amazon CloudFront キャッシュポリシーとオリジンリクエストポリシーを発表 によると、2020年ぐらいに distribution ごとに個別設定していたのをマネージドポリシーというリソースを参照することで一元管理できるようになったらしい。cdk のコードで言えば、次の issue で対応されているが、これらの機能は aws_cloudfront.Distribution のみに追加されている。従来の CloudFrontWebDistribution では使えないので distribution 設定そのものを新しいやり方に移行する必要がある。

基本的には同じ設定を行うので新しいクラスのメンバーや構造にあわせて移行するだけなので難しくはないけれど、1つずつ設定内容の移行方法を確認していかないといけないから手間暇はかかる。cdk のドキュメントをみると、型に対してどういった設定をすればよいかが書いてあって、あとはメソッドの定義などもみながら自分たちの設定に近いものを選択していくといった作業になる。難しくはないけど時間はかかる。半日ほどやって移行のための pr を作成した。

cdk/cf の Stack とライフサイクル

0時に寝て5時に起きた。

インフラ変更の本番作業

先週やっていた様々なインフラ構築の改善を本番環境に適用する。cf の changeset は23とかになっていた気がする。大きな括りで次の3つの移行作業をした。

  • rds をスタックから切り離す
  • cdk の v1 から v2 へのアップグレード
  • ポリシーとセキュリティグループのドリフト解消

私は本番環境へのアクセス権限をもっていないので社員さんの作業内容を伝えてやってもらう。cf のテンプレートの更新やドリフトの解消など、テスト環境で10時間以上は費やした検証結果が功を奏して、本番作業は想定外の事象も発生せず1.5時間で完了した。cdk のコードも意図した設定になるように修正済みだし、なにも問題は発生しない。cdk のコードを書くときは cf のイベントログやドリフト結果と実際のインフラの振る舞いを確認するといった検証には時間がかかるが、それができてしまえば本番環境の構築はうまくできる。それがわかっているインフラ担当者がいなくなると、また1から担当者が検証する必要があって保守は大変かもしれないけど。

同じ Stack でどういったリソースを管理するかというライフサイクルは難しい問題かもしれない。今回 rds を削除したのは、なんらかの理由で手動運用で rds を変更することがあって、アプリケーション Stack から外してしまった方が保守しやすいのではないかという意見が出たため。それが正しいかどうかはわからないが、一度作ったリソースを削除しないもの (vpc や s3 bucket など) をアプリケーション Stack で管理すると、再作成できなくて面倒くさいことがある。というのは、再作成は新規に作成 → 古いリソースを削除の順番で処理されるため、一意な名前をもつリソースは基本的に再作成できない。

壊れた cf スタックのリストアと cdk の再同期

2時に寝て6時半に起きた。インフラエンジニアになったのでみんなが作業していない時間にインフラの保守作業をするようにしている。昼はアプリケーションエンジニア、夜はインフラエンジニアみたいな生活になっていてしんどい。

壊れた cf スタックの更新

テスト環境の cf スタックを手動で更新して壊れているのを cdk で管理できるように直した。壊れていたのは次の3つ。

  • rds をスナップショットからリストアしたので cf が管理している rds リソースが存在しない
  • iam の acl 設定が異なる
  • セキュリティグループのインバウンドルールが異なる

aws 的にもそういった状況は認識していて cdk で同期できなくなった cf スタックを更新する手順を提供している。

ざっくり手順をまとめると次になる。

  1. 対象のリソースに DeletetionPolicy=Retain にセットする
  2. テンプレートからリソースを削除して、スタックの更新を実行する
  3. テンプレート内のリソースの実際の状態を describe して、スタック内に既存のリソースをインポートする

リソースの設定ぐらいなら既存のリソースからインポートしなくても cf のテンプレートを直接書き換えたものをアップロードしてスタックを更新するのでも大丈夫だったりする。しかし、cdk もそのテンプレートにあうように修正しないといけないため、cdk のコードとテンプレートのコードの両方をチェックしながら検証する必要がある。cdk でリソース管理ができるようになったからといって、それが変更前の既存のリソースの設定と同じかどうかは人間が目でみて検証しないといけない。これがあちこちで参照されているリソースだと追跡するのが面倒くさいといった手間暇がかかる。

cdk がよいものかどうか、私はまだ判断がつかないけど、cf を抽象化して便利になっているところは認めるものの、cf のスタックが壊れたときのトラブルシューティングが必要以上に複雑で厄介というのも事実ではある。一方で壊れた cf スタックを5時間ぐらいかけて直したのではまりポイントはいくつかも学ぶことができた。しんどかったけど。例えば、あるセキュリティグループのインバウンドルールに別のセキュリティグループを関連付けるとき、1つの設定ではうまくいかなくて次の2つの設定を追加した。これが適切かどうかわからないが、この設定で cdk でデプロイしたスタックの環境と既存リソースとの環境が整合した状態 (ドリフトが解消される) になった。こういうのが cdk の抽象化による訳のわからないところの1つ。

otherSecurityGroup.addIngressRule(
  ec2.SecurityGroup.fromSecurityGroupId(this, 'my security group', mySgId),
  ec2.Port.tcp(80),
  "my inboud rule",
)
otherSecurityGroup.addIngressRule(
  ec2.Peer.securityGroupId(mySgId),
  ec2.Port.tcp(80),
  "my inboud rule",
)

cdk のメジャーバージョンのマイグレーション

0時に寝て5時に起きた。開発者にインフラ変更の影響を出さないように6時半からインフラのお仕事してた。

cdk v1 と v2 の違い

AWS CDK Versions には v1 と v2 の2つがある。新規で作るものは v2 を選択すればよいけど、既存のスタックが v1 だとマイグレーションが必要になる。cdk は bootstrap したときに CDKToolkit というスタックを生成する。cdk をアップグレードするというのはこのスタックの設定も更新する必要がある。デフォルト設定をそのまま使っていればマイグレーションはそんなに難しくはないはずだけど、設定をカスタマイズしていたりするといくつかパラメーターを調整したりしなかったりしてややこしいかもしれない。

また v2 は v1 の experimental な機能は移行されていないため、v1 のライブラリを直接使うか、自前でその機能を実装するといったことも必要になる可能性がある。

例えば、v1 の apigwv2.VpcLink というメソッドは experimental で v2 に移行されていないため、v2 に移行されている stable な CfnVpcLink という機能を使って次のように実装した。これは v1 の cdk の実装をみて同じように実装しただけ。

-    const apiGwVpcLink = new apigwv2.VpcLink(this, 'ApiGwVpcLink', {
-      vpc: vpc,
-      vpcLinkName: 'my-vpc-link',
-      securityGroups: [mySecurityGroup]
+    const apiGwVpcLink = new  apigwv2.CfnVpcLink(this, 'ApiGwVpcLink', {
+     name: 'my-vpc-link',
+     subnetIds: vpc.privateSubnets.map(sb => sb.subnetId),
+     securityGroupIds: [mySecurityGroup.securityGroupId]