ひぃ(hixi)の技術雑記ブログ

事実や解決策というよりも自分が思ったことをつらつらと書いていく所存。文章構成とかそういうのあまり気にせずに書きます

CloudFormation の分け方/作り方 (05/09追記)

今まで CloudFormation (CFn) を細分化して管理していた。 例えば標準的なWebアプリの場合はこんな感じ。

./
├── cloudfront.yaml
├── fargate_cluster.yaml
├── fargate_service.yaml
├── loadbalancer.yaml
├── rds.yaml
├── acm.yaml
├── vpc.yam
└── subnet.yaml

CloudFormation で管理されてるので、インフラ構成がわかりやすいし、分けてあることによって修正箇所などが明確でよかった。 けども、順序通り実行しないといけないなどというデメリットがあった。 例えば、まず vpc を作って、 subnet を作って、そして次に... みたいな感じ。

それを解決するソリューションとして AWS::CloudFormation::Stack っていうのがあって、これはとてもいい。

以下のような fargate.yaml があったときに See also

AWSTemplateFormatVersion: 2010-09-09
Resources:
  Bucket:
    Type: Custom::Value
    Properties:
      ServiceToken: !ImportValue cfn-lambda-value:LambdaArn
      Value:
        Fn::Join:
          - ""
          - - "https://"
            - !ImportValue cfn-template-s3:DomainName
  Vpc:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub '${Bucket}/component/vpc/vpc-2az.yaml'
      Parameters:
        VpcCidrBlock: 10.1.0.0/16
        VpcDomain: vpc.local
        AzOne: !Select [0, !GetAZs '']
        AzTwo: !Select [1, !GetAZs '']
        SubnetPublicOneCidr: 10.1.10.0/24
        SubnetPublicTwoCidr: 10.1.20.0/24
        SubnetPrivateOneCidr: 10.1.11.0/24
        SubnetPrivateTwoCidr: 10.1.21.0/24
      TimeoutInMinutes: 60
   CloudFront:
.....

fargate.yaml を deploy するだけで、 VPC を作ってー、CloudFront 作ってーみたいな感じで全部作ってくれる。 この様なユースケースyaml を作っておけば、fargate の環境を構築したいときに順序など気にせずに deploy 可能。 f:id:hixi-hyi:20190507175535p:plain

ってことで、とても良いソリューションではあるものの、 CloudFront (CF) + Certificate Manager (ACM) を使って HTTPS を構築しようとしたときにハマる時がある。 僕たち日本人は往々にして ap-northeast-1 リージョンを使うことが多いと思う。 ここからは複雑っていうか前提がいろいろめんどくさくなるが、

  • CF は us-east-1 に作られるが、他リージョンの CFn からも作成可能 (逆に言うと CF は他リージョンから作っても US リージョンになる)
  • ACM はリージョンに紐付いて作成される( ap-northeast-1 の CFn から us-east-1 などに作れない)
  • CF に設定できる SSL 証明書は US リージョンの ACM しか使えない

ってことで、 us-east-1 以外のリージョンの CFn では CF を SSL 対応するまでを自動化できないわけである。 ここだけ手動が必要になるってこと。

CFn を使いたい人にとってそんなことはしたくないはずなので、解決する必要がある。 ということで、以下のようなものを作ってみた。 GitHub - hixi-hyi/aws-cloudformation-lambda-cloudformation-stack

これを使えば別リージョンに CloudFormation::Stack ができる。(※ 「ネスト」といったタグは残念ながらつかない) 正直いいアプローチなのかはわからない。そして、プロダクション環境では試していない。(2019/03/07現在)

CloudFormation はとてもいいソリューションだし、プラットフォームが標準でサポートしてるっていうのはいいことではあるものの、自分の経験則的には「標準で提供されている機能には限界があるので Custom Lambda を作る勇気が必要」だと思われる。

CloudFormation::Stack については本番環境を構築するにあたって時間が足りないという自分の怠慢で実現できなかったが、やっておけばよかったなとおもった。それほどよいものだとおもう。

すごい細かいこと含めて書くと以下のメリットがある。

  • 順序を気にする必要がなく、手順が単純化される
  • どのスタックがどの Output を利用するのかが親スタックを見るだけで明確になる。
  • CREATE FAILED したときに一旦 delete-stack しないと同じスタックは作れない。そしてそれで無駄に時間取られることがある。けど Stack の場合は Stack の親が一回成功してればそんなことがない

FAQ

  1. 今まではどうしてたの? 今まではスタックが細分化されていたので、 acm.yaml だけを us-east-1 に deploy して、 AWS Systems Manager パラメータストア - AWS Systems Manager を使って連携させてた

  2. 他に方法はないの? たぶん次のブログネタだけども、 AWS Lambda-backed カスタムリソース - AWS CloudFormationACM の multi-region バージョンを作るとか。 GitHub - hixi-hyi/aws-cloudformation-lambda-ssm-put-parameter こんな雰囲気で。 ACM の Custom Lambda を作るのと CloudFormation::Stack の Custom Lambda を使うべきかはまだ答えは出ていない。


03/09 追記 以下のコメントをいただきました

"AWS::CloudFormation::Stack"を使ったいわゆるNested Stack、初回デプロイには便利ですがUpdate StackするときにChangeSetを作っても、Nested Stackの内の差分確認ができないところは注意です。 "AWS::CloudFormation::Stack"という単位のリソースになってしまうのでその中身で何が変更/再作成/削除になるのかまで表示してくれないのです。。やるとしたらCFnを初回デプロイ時のみに利用する場合か、ステートレスなリソースのみ含めるようにして、データを保持するようなDBやEC2インスタンスはNestしないで外に出すように個人的にはオススメしたりします。

自分そういえば ChangeSet をちゃんと使ってないなーっておもった。 基本的に aws cloudformation deploy コマンド使っちゃってる