ENGINEER BLOG ENGINEER BLOG
  • 公開日
  • 最終更新日

CloudFormationで環境差分を解決する:よく使うテクニック4選

この記事を共有する

目次

はじめに

こんにちは!パーソル&サーバーワークスの野間です。

AWS CloudFormation(以下、CloudFormatin)で複数環境(dev / stg / prd)を別々のテンプレートで管理していると、設定変更時の手間が増えたりオペレーションミスの原因にもなります。
本記事では CloudFormationテンプレートの環境差分を吸収し、運用効率化をするためによく使うテクニックをまとめます。

よく使うテクニック4選

個人的によく使うテクニックを、以下の AWS Lambda 関数を作成するテンプレートを使って紹介します!
テンプレートではParametersで環境を選択できるようにしています。
cloudformation_parameters.png

CloudFormationテンプレート
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Parameters:
  Env:
    Type: String
    AllowedValues: [dev, stg, prd]
  Project:
    Type: String
  Handler:
    Type: String
Mappings:
  EnvMapping:
    dev:
      MemorySize: 128
      Timeout: 5
    stg:
      MemorySize: 256
      Timeout: 10
    prd:
      MemorySize: 256
      Timeout: 10
Conditions:
  IsPrd: !Equals [!Ref Env, prd]
Resources:
  LambdaSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub lambda-sg-${Project}-${Env}
      VpcId: !ImportValue LambdaVpcId
  LambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub api-${Env}
      Role: !Sub arn:aws:iam::${AWS::AccountId}:role/${Project}-${Env}-lambda-exec
      Handler: !Ref Handler
      Runtime: python3.12
      MemorySize: !FindInMap [EnvMapping, !Ref Env, MemorySize]
      Timeout: !FindInMap [EnvMapping, !Ref Env, Timeout]
      ReservedConcurrentExecutions: !If [IsPrd, 20, !Ref AWS::NoValue]
      VpcConfig:
        SecurityGroupIds:
          - !Ref LambdaSG
        SubnetIds:
          - Fn::ImportValue: !Sub ${Project}-PrivateSubnet1
          - Fn::ImportValue: !Sub ${Project}-PrivateSubnet2
      Environment:
        Variables:
          STAGE: !Ref Env
      Events:
        Api:
          Type: HttpApi

1.環境毎に設定値が異なる場合は Mappings 使う

環境ごとに設定値が異なっている場合は Mappings を使って差分を吸収します。
今回の場合は、メモリ/タイムアウトの値を環境別に切り替えるようにしています。

Mappings:
  EnvMapping:
    dev:
      MemorySize: 128
      Timeout: 5
    stg:
      MemorySize: 256
      Timeout: 10
    prd:
      MemorySize: 256
      Timeout: 10

また、AWS::Serverless::Functionで呼び出す際は、以下のように記載します。

      MemorySize: !FindInMap [EnvMapping, !Ref Env, MemorySize]
      Timeout: !FindInMap [EnvMapping, !Ref Env, Timeout]

2.アカウントIDなどは疑似パラメーターを使う

アカウントIDやリージョンなどは疑似パラメーターを利用することで差分を吸収します。
今回は IAM Role の ARN の記載に利用しています。

      Role: !Sub arn:aws:iam::${AWS::AccountId}:role/${Project}-${Env}-lambda-exec

参考:https://docs.aws.amazon.com/jajp/jajp/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html#available-pseudo-parameters

3. 固有のリソースIDはハードコードしない

リソース固有のIDはハードコードせずに組み込み関数(!Ref、!ImportValue など)を利用することで差分を吸収します。
同じテンプレート内にある場合は !Ref や !GetAtt を使って記載します。

      VpcConfig:
        SecurityGroupIds:
          - !Ref LambdaSG

別テンプレートファイルに存在するリソースは !ImportValue を使って記載します。

    Properties:
      GroupDescription: !Sub lambda-sg-${Project}-${Env}
      VpcId: !ImportValue LambdaVpcId

!Sub と !ImportValue を組み合わせることも可能です。

        SubnetIds:
          - Fn::ImportValue: !Sub ${Project}-PrivateSubnet1
          - Fn::ImportValue: !Sub ${Project}-PrivateSubnet2

4. 環境差分は Conditions や AWS::NoValue を使う

prd環境のみ同時実行数の設定を追加する場合など、環境差分は Conditions や AWS::NoValue を利用することで差分を吸収します。
まずは Conditions セクションに条件を記載します。今回の場合は「prd環境のみ」なので以下のように記載しました。

Conditions:
  IsProd: !Equals [!Ref Env, prd]

また、AWS::Serverless::Function の中では、以下のように記載します。
20 がprd環境の同時実行数で、それ以外の環境の場合は !Ref AWS::NoValue が適用されます。
つまり、dev、stg環境では同時実行数の設定自体行わないという意味になります。

      ReservedConcurrentExecutions: !If [IsPrd, 20, !Ref AWS::NoValue]

参考:https://docs.aws.amazon.com/jajp/jajp/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html#pseudo-parameter-novalue-example

まとめ

複数環境 を"1枚のテンプレート"で運用できるのは、運用効率化に大きく貢献するアプローチだと感じました。
CloudFormation を複数環境で運用している方の参考になれば幸いです!

この記事は私が書きました

野間 太一

記事一覧

猫とCloudFormationが好きです。

野間 太一

この記事を共有する

クラウドのご相談

CONTACT

クラウド導入や運用でお悩みの方は、お気軽にご相談ください。
専門家がサポートします。

サービス資料ダウンロード

DOWNLOAD

ビジネスをクラウドで加速させる準備はできていますか?
今すぐサービス資料をダウンロードして、詳細をご確認ください。