びくんびくんしながらコードを書く。

いしきひくい系エンジニアのらくがき帳

AWS CloudFormationで構成管理するときに役立つTips その1

本記事は ディップ with 全部俺 AdventCalendar 5日目の記事です。

今回はAWSの構成管理で使われるCloudFormationのtemplateに出てくるMapやParameters、組み込み関数的なモノについて紹介します。

CloudFormationのtemplateはjsonまたはyamlで管理されます。
本記事では基本的にyamlフォーマットを利用して記述していきます。

What is AWS CloudFormation ?

公式より引用

AWS CloudFormation は、クラウド環境内のすべてのインフラストラクチャリソースを記述してプロビジョニングするための共通言語を提供します。CloudFormation では、プログラミング言語またはシンプルなテキストファイルを使用して、あらゆるリージョンとアカウントでアプリケーションに必要とされるすべてのリソースを、自動化された安全な方法でモデル化し、プロビジョニングできます。これは、AWS リソースに真実の単一のソースを与えます。

AWS CloudFormation は追加料金なしでご利用いただけます。お支払いいたくのは、お客様のアプリケーションを実行するために必要な AWS リソース分の料金のみです。

※追加料金なしと書かれていますが、templateがある一定の容量を超える場合、ローカルからCLIでの実行が行えず、templateをS3経由にする必要があり、微々たる金額ですが、お金がかかる場合があります。

外部からパラメーターを受け取りたい場合 [Parameters]

CloudFormationのテンプレートの内容に外部パラメータを利用したい場合はトップレベルの階層に下記要素を用意します。

Parameters:
  ENV:                   # このシンボルは好きな文字を設定出来ます。
    Type: String         # パラメータの型を宣言します。
    Default: development # パラメータ指定しなかった場合のデフォルト値を設定します。※任意項目
    AllowedValues:       # パラメータに入力できるものを限定するときに利用します。  ※任意項目
      - development
      - staging
      - production

パラメータを渡す場合は下記のように指定します。

aws cloudformation deploy \
  --stack-name 【CLoudFormationのスタックネームを指定します。】 \
  --template-file 【テンプレートファイルのパスを指定します。】 \
  --parameter-override ENV=staging

Defaultを記載している場合、 --parameter-override を明記しなければDefault値がセットされますが、Defaultを記載していない場合はエラーとなります。

変数を文字列展開する [!Sub]

ECSクラスターやALBに環境ごとのPrefixをつけたい等あると思います。 前項で受け取った外部パラメータをPrefixとする場合は下記の様な記述になります。

Resources:
  atsHataWeb:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub ${ENV}-nantoka-project

変数によって入力する値を変える[Mappings, !FindInMap]

staging環境と本番環境でCPU, Memoryサイズを変えたいという要望はよくあると思います。
staging用、本番用でテンプレートを用意するのも手ですが、せっかく Parameters で外部から値を受け取れるようになったので一つのテンプレートで管理したくなります。

ただ、上記のように環境で分けたいものをすべて外部Parameterで受け取るようになると大変なことになりますし、設定が毎回変わってしまうことがありえます。

このような場合、Mappings を利用すると環境別の設定をテンプレートに記載することができます。

下記がMappingsの例と呼び出し例です。

Mappings:
  EnvMap: # Mapの名前
    staging: # Map内の要素
      Memory: 512
      CpuUnit: 256
    production:
      Memory: 1024
      CpuUnit: 512

Resources:
  EcsTask:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Sub ${ENV}-ecs-task
      ExecutionRoleArn: "ecsTaskExecutionRole"
      TaskRoleArn: 【Role Name】
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      #Mapの呼び出し、EnvMap内の ENV文字列に該当する要素のMemoryの値を取得
      Memory: !FindInMap [EnvMap, !Ref ENV, Memory]
      #Mapの呼び出し、EnvMap内の ENV文字列に該当する要素のCupUnitの値を取得
      Cpu: !FindInMap [EnvMap, !Ref ENV, CpuUnit]
      ContainerDefinitions:
        - Name: !Sub ${ENV}-ecs-container
          Image: 【ECRリポジトリ】
          Essential: "true"
          PortMappings:
            - ContainerPort: 80
          LogConfiguration:
            LogDriver: awslogs

※まだ紹介していない!Refが出てきたので公式より下記補足です。
組み込み関数 Ref は、指定したパラメータまたはリソースの値を返します。
上記例でいうと外部パラメータENVの内容を返します。

上記テンプレートをENV=stagingで実行した場合、Memoryは512, Cupは256がセットされることになります。

上記以外にもセキュリティグループやサブネットが環境によって異なるというような場合にも利用できます。

本文が長くなってしまったため、本Tipsは2本に分けるこにします。 明日はテンプレート分割時の値の受け渡しについて記事にしたいと思います。