【実務・中級編】CloudFormation Custom Resources(カスタムリソース)を活用して標準外のリソースを制御する – インフラ構成管理(IaC)活用バイブル

CloudFormation Custom Resources:IaCの「最後の聖域」を攻略し、インフラ自動化の限界を突破せよ

AWS環境を構築していて、一度はこんな壁にぶつかったことはないだろうか。

「標準リソース(AWS::S3::Bucketなど)だけでは、どうしても手が届かない領域がある」

例えば、DBのスキーママイグレーション、Auth0のような外部SaaSへのAPI設定、あるいは複雑な依存関係を持つ独自ドメインの設定。これらを「手動でやってください」とドキュメントに残すのは、SREとして敗北を意味する。

CloudFormation Custom Resourcesは、その「敗北」を「自動化」へ変えるための最後の聖域だ。今日は、これを使い倒し、インフラコードの表現力を極限まで高める方法を伝授する。

—

1. Custom Resourcesとは何か?:標準の枠組みを超える「特権」

Custom Resourcesは、簡単に言えば「CFnテンプレートから任意のLambda関数を呼び出すフック」だ。

CFnのスタック操作(Create/Update/Delete)をトリガーにして、Lambda経由で好きな処理を実行できる。

  • 使うべき時: AWSが直接サポートしていないリソースの操作、またはAWSリソースを操作するための「一歩踏み込んだカスタムロジック(例:動的な設定値の計算、外部API連携)」が必要な時。

これを使えば、「手動運用」という名の負債を、コードとしてリポジトリに完全に封じ込めることができる。

—

2. 実装の極意:Lambda連携とライフサイクル管理

Custom Resourcesの心臓部は、CFnから送られてくる `RequestType`(Create/Update/Delete)を正しくハンドリングすることだ。

実践的なハンドラ構成(Python)

ただ処理を動かすだけでは不十分だ。冪等性を担保し、CFn側に結果を確実に返す必要がある。`cfn-response` モジュールを使うのも手だが、大規模運用では自前でハンドリングする方が堅牢だ。

import json
import logging

logger = logging.getLogger()

def lambda_handler(event, context):
request_type = event[‘RequestType’]
props = event[‘ResourceProperties’]

try:
if request_type == ‘Create’:
# DB初期化や外部API登録のロジック
return send_response(event, “SUCCESS”, {“PhysicalResourceId”: “MyCustomResource-001”})
elif request_type == ‘Update’:
# 設定変更時のロジック
return send_response(event, “SUCCESS”, {})
elif request_type == ‘Delete’:
# リソース削除に伴う後処理
return send_response(event, “SUCCESS”, {})
except Exception as e:
logger.error(f”Error: {str(e)}”)
return send_response(event, “FAILED”, {})

def send_response(event, status, data):
# ここにPre-signed URLへPUTするロジックを実装
# 失敗時に確実にシグナルを送るのが「落ちないインフラ」の第一歩

—

3. 現場で震えるほど役立つベストプラクティス

① エラーハンドリングとタイムアウトの鉄則

  • 冪等性の担保: Lambdaが途中で失敗しても、再試行で壊れないように。「既に作成済みなら何もしない」というロジックは必須だ。
  • タイムアウト対策: 外部API連携を含む場合、Lambdaのタイムアウト設定は長めに。ただし、CFn自体のスタック更新も引きずられるため、非同期処理が必要なら「Lambdaから別サービス(Step Functionsなど)を叩いて完了を待つ」設計に切り替える勇気を持て。

② 開発スピードを加速させる「神プラグイン」と設定

VS Code環境なら、以下は必須の「標準装備」だ。

  • CloudFormation Linter (cfn-lint): 設定するだけで、デプロイ前のミスを9割消せる。CIパイプラインにも組み込め。
  • AWS Toolkit for VS Code: スタックのデプロイやログ確認がエディタ上で完結する。
  • YAMLフォーマッタ: インデントの不一致による「謎のバリデーションエラー」を撲滅する。

③ チーム開発での「設定の共有化ルール」

チームの生産性を下げないための鉄則だ。

  • パラメータの外部化: `Parameters`セクションを肥大化させず、`AWS::SSM::Parameter`で値を参照せよ。
  • モジュール化: 汎用的なCustom ResourceはLambdaレイヤーに切り出し、複数のスタックから参照できるようにせよ。

—

4. プロの構成例:YAMLの美学

単なるプロパティの羅列に終わらせるな。構造化せよ。

cfn-template.yaml
Resources:
DatabaseInitializer:
Type: Custom::DatabaseInitializer
Properties:
ServiceToken: !GetAtt MyCustomResourceLambda.Arn
DBName: “prod_db”
Region: !Ref “AWS::Region”
# 変更時に再実行させるためのトリガー
ConfigVersion: “v1.2.0”

ポイント: `ConfigVersion` のようなダミーのプロパティを置くことで、コードを変更した際に強制的にリソースを更新(再実行)させることができる。これは現場で頻出する「修正が反映されない!」というトラブルを防ぐ魔法だ。

—

最後に:SREとしての心構え

Custom Resourcesは強力だが、使いすぎれば「独自のブラックボックス」を生むことになる。「標準リソースで解決できないか?」をギリギリまで検討し、それでもダメな時にだけこの聖域を開くこと。

コードは、読まれるためにあるのではない。「運用負荷を消し去るために」書かれるものだ。

君たちが書くその一行のコードが、深夜の呼び出しから誰かを救うことを願っている。さあ、IaCの極限を目指そう。

タイトルとURLをコピーしました