個人的によくやるCloudFormationテンプレート小技と+α

記事タイトルとURLをコピーする

こんにちは!EC部の篠﨑です。

今日は個人的によくやるCloudFormationの小技を紹介していきます。

ほんのちょっと小慣れ感が出せると思いますので、これからCloudFormation使っていくぜという方の参考になれば幸いです。

Output/ImportValue

こちらはおなじみの方も多いかと思いますが、スタック間で値の受け渡しを行うものです。

例えば、EC2インスタンスを構築するスタックとInstance Profileを構築するスタックが異なる場合、以下のような書き方をします。

↓Instance Profileテンプレート

Resources:
  InstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    DeletionPolicy: "Delete"
    Properties:
# ~~
# 詳細省略
# ~~

Outputs:
  InstanceProfile:
    Value: !Ref InstanceProfile
    Export:
      Name: instance-profile-name

↓EC2インスタンステンプレート

Resources:
  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: aa-example-1a
      ImageId: ami-1234567890abcdef0
      # Instance Profileの名前をインポート
      IamInstanceProfile: !ImportValue instance-profile-name
# ~~
# 詳細省略
# ~~

Importした値をSubでくっつける

ImportValueで取得した値を使って、Refで利用したい場合に利用します。

例えば、EC2からS3オブジェクトへのアクセスが必要なケースを考えます。 EC2へアタッチするInstance ProfileとS3バケットのテンプレートが異なる場合、ロール記載のCloudFormationテンプレートにS3バケットARNをImportして記載します。

↓S3バケットテンプレート

Resources:
  ArtifactBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "bucket-${AWS::AccountId}"

Outputs:
  BucketArn:
    Value: !GetAtt S3Bucket.Arn
    Export: 
      Name: arn-s3-bucket

↓EC2 Instance Profileテンプレート

Resources:
  EC2Role:
    Type: "AWS::IAM::Role"
    DeletionPolicy: "Delete"
    Properties:
# ~~
# 詳細省略
# ~~
      Policies: 
        - PolicyName: policy-test
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "s3:Get*"
                  - "s3:List*"
                Resource:
                  # バケットARN
                  - !ImportValue arn-s3-bucket
                  # バケット内オブジェクトのARN
                  - !Sub
                    - "${BucketArn}/*"
                    - BucketArn: {'Fn::ImportValue': 'arn-s3-bucket'}

パラメーターの値をSubでくっつけてImport

例えば、環境ごとにInstance Profileを作成し、それぞれの環境ごとにEC2インスタンスのテンプレートをInstance Profileとは別で作成するとします。 Instance Profileのテンプレートでは環境それぞれに以下のようなキーでOutputをすることとします。

  • instance-profile-prd
  • instance-profile-stg
  • instance-profile-dev

EC2(Instance Profile含む)のテンプレートは環境ごとに作成したくないので、同じテンプレートでどうにかしたいときにはEC2のテンプレートは以下のようにします。

Parameters:
  Environment:
    Type: String
    AllowedValues:
      - prd
      - dev
      - stg
Resources:
  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: aa-example-1a
      ImageId: ami-1234567890abcdef0
      IamInstanceProfile:  { "Fn::ImportValue": {"Fn::Sub": "instance-profile-${Environment}"}}
# ~~
# 詳細省略
# ~~

これで全て同じテンプレートが使えてすっきりですね!

AWS CLIを使ってスタックデプロイをするときのパラメータファイルを少し楽して作成する

AWS CLIを使ってCloudFormationスタックのデプロイをする方法は日高さんが書いてくれていますので、詳細についてはこちらをご確認ください。

blog.serverworks.co.jp

JSONファイルでパラメータを指定するのですが、パラメータファイルを作るのが面倒です。 そこで、テンプレートファイルにDefault値が付いている場合はコマンドを使って少し楽しましょう。 使うのはAWS CLIとjqコマンドです。

aws cloudformation validate-template \
--template-body file://{ファイル名} \
|jq '.Parameters[]|[{ "ParameterKey": .ParameterKey, "ParameterValue": .DefaultValue}]' \
|jq -s -c add| jq . > resource-params.json

テンプレートでDefaultを指定していない場合、以下コマンドでチョットだけ楽できるかもしれないです。

aws cloudformation validate-template \
--template-body file://{ファイル名} \
|jq '.Parameters[]|[{ "ParameterKey": .ParameterKey, "ParameterValue": ""}]' \
|jq -s -c add \
| jq . > resource-params.json

ちなみにvalidate-templateコマンドを使うことによって、deployコマンドでデプロイする際に--capabilityオプションの要否確認やフォーマットチェックをしてくれます。 deployコマンドを使う前に一回やっておくと手戻りが減ります。

スタック作成失敗時に毎回スタックの削除をしないためにロールバックを無効にする

CloudFormationスタックを作成して、失敗したらスタックを削除してもう一回、、また失敗したからもう一回削除して、、、 特にCloudFormationスタックの作成をして検証するときこんな感じになってませんか????

せっかくAWS CLIでやっているのに、結局コンソールで毎回削除していたり、、、、ということになりかねません。 嫌ですね~

ということで、そんなことを回避するためにスタックを作成するときに「ロールバックしない」を選択してスタックの作成をしてみましょう。 そうすると、スタックを毎回削除して~~~ということがなくなります。

コンソールでは、「スタックの失敗オプション」で[正常にプロビジョニングされたリソースの保持]にチェックを入れます。

AWS CLIでデプロイする場合は--disable-rolebackオプションを追加します。

AWS CLIでやる場合は特に、スタックが失敗した場合、テンプレートの修正をしてそのままもう一回デプロイコマンドを叩くとスタックのアップデートが走ります。 コンソールでの場合は、テンプレート修正後、「更新」からアップデートが可能です。

おわりに

できなくても困らないですが、あると便利だなぁというものを載せてみました。

Output/ImportValueはスタックの密結合にもつながるので、なんでもかんでもやればいいというわけでもなかったり、時と場合によって使っていただけるとよいかなと思います!

CloudFormationマスターになりたいぜという方はぜひ利用してみてください!

篠﨑 勇輔(書いた記事を見る)

クラウドインテグレーション部 SRE2課

入社4年目