1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CloudFormationのネストスタックを使用して効率化する

1
Last updated at Posted at 2025-12-18

はじめに

私は現在AWSの設計構築のメンバーとして主にCloudFormationの構築に携わっています。
CloudFormation構築メンバーは他にも3名いましたが、プロジェクトから離脱したり、別のプロジェクトへ異動してしまったりなどがあり、現在では私一人となってしまいました。

そのため、CloudFormationテンプレートの改修が入った場合には全面的に私が対応しています。
(大変な反面全て網羅できるため勉強にはなりますね)

CI/CDを担当していたメンバーも既にいなくなってしまったため、ここ最近で大きな改修が入り、そのコードの書き方の効率が良いと思いましたので今回はその効率性について書き記していきたいと思います。

課題

CodePipeline/CodeBuildを使用して複数の「役割」や「名称」の異なるコンテナにアプリケーションをリリースする際に、複数のResourceをコード内に記述するとコード量が多くなり、無駄が多くなる。

解決策

CloudFormationのネストスタックを使用して親子スタックで定義することで、複数のResourceコードを記述することなく、効率化することができる。

ネストされたスタックとは
AWS Black Belt
image.png
image.png

詳細は上記のAWS Black Beltに記載がありますのでそちらをご覧ください。

構成例

実際の構成例は以下です。

親スタック A
親スタック B
親スタック C
親スタック D
    └子スタック (CodePipelineひな形)

CodePipelineA~Dまでのリソースが存在し、このリソースは全て名称が異なります。

例えば、以下のように各コンテナが機能ごとに分かれており、その各コンテナに対するCodePipelineを定義する場合です。

  • auth
  • login
  • api
  • frontend

上記の各機能ごとのCodePipelineリソースを作成する場合、同じリソースを4つ定義しなければいけないのかな?と思い同じコードを何度も記述しなければいけないのは非効率です。

そこで、親スタックからパラメータだけを渡すコードを書き、子スタック側にはそのパラメータを受け取るコードを一つ定義することで効率化することができます。

実際にコードの例を見ていきましょう。

CloudFormationの例

親スタック

親スタックはParametersセクションで定義している値を子スタックに継承するように記述します。

# 認証用CodePipeline
  CreateCodePipelineA:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: "https://xxxxxxx-${AccountId}.s3.ap-northeast-1.amazonaws.com/cdp-template.yaml"
      Parameters:
        stackPrefix: !Ref stackPrefix
        stackEnvironment: !Ref stackEnvironment
        stackConnectionArn: !Ref stackConnectionArn
        stackCodePipelineName: "auth" # authを名称として子スタックに継承

# ログイン用CodePipeline
  CreateCodePipelineB:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: "https://xxxxxxx-${AccountId}.s3.ap-northeast-1.amazonaws.com/cdp-template.yaml"
      Parameters:
        stackPrefix: !Ref stackPrefix
        stackEnvironment: !Ref stackEnvironment
        stackConnectionArn: !Ref stackConnectionArn
        stackCodePipelineName: "login" # loginを名称として子スタックに継承

# API用CodePipeline
  CreateCodePipelineC:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: "https://xxxxxxx-${AccountId}.s3.ap-northeast-1.amazonaws.com/cdp-template.yaml"
      Parameters:
        stackPrefix: !Ref stackPrefix
        stackEnvironment: !Ref stackEnvironment
        stackConnectionArn: !Ref stackConnectionArn
        stackCodePipelineName: "api" # apiを名称として子スタックに継承

# フロントエンド用CodePipeline
  CreateCodePipelineD:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: "https://xxxxxxx-${AccountId}.s3.ap-northeast-1.amazonaws.com/cdp-template.yaml"
      Parameters:
        stackPrefix: !Ref stackPrefix
        stackEnvironment: !Ref stackEnvironment
        stackConnectionArn: !Ref stackConnectionArn
        stackCodePipelineName: "frontend" # frontendを名称として子スタックに継承

子スタック

## ::RESOURCES::
# Resource Section: Defines AWS resources included in the stack
Resources:

  # CodePipeline作成
  CodePipeline:
    Type: "AWS::CodePipeline::Pipeline"
    Properties:
      Name: !Sub "${stackPrefix}-${stackEnvironment}-codepipeline-${stackCodePipelineName}"
      PipelineType: V2
      ExecutionMode: QUEUED
      RoleArn: !Sub "arn:aws:iam::${AWS::AccountId}:role/${stackPrefix}-${stackEnvironment}-role-codepipeline"
      ArtifactStore:
        Type: "S3"
        Location: !Sub "${stackPrefix}-${stackEnvironment}-s3-codepipeline-artifact-${AWS::AccountId}"
      Stages:
        - Name: "Source"
          Actions:
            - Name: "From_GitHub"
              ActionTypeId:
                Category: Source
                Owner: AWS
                Provider: CodeStarSourceConnection
                Version: "1"
              OutputArtifacts:
                - Name: SourceArtifact
              Configuration:
                ConnectionArn: !Sub "arn:aws:codeconnections:ap-northeast-1:${AWS::AccountId}:connection/${stackConnectionArn}"
                FullRepositoryId: !Sub "infra/${stackPrefix}-${stackEnvironment}-git-${stackCodePipelineName}"
                BranchName: "main"
                DetectChanges: true
            - Name: "From_S3"
              ActionTypeId:
                Category: Source
                Owner: AWS
                Provider: S3
                Version: "1"
              OutputArtifacts:
                - Name: S3SourceArtifact
              Configuration:
                S3Bucket: !Sub "${stackPrefix}-${stackEnvironment}-s3-${AWS::AccountId}"
                S3ObjectKey: !Sub "application/${stackPrefix}/${stackCodePipelineName}/${stackCodePipelineName}.zip"
                PollForSourceChanges: "false"
        - Name: Build
          Actions:
            - Name: Build
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: "1"
              InputArtifacts:
                - Name: SourceArtifact
                - Name: S3SourceArtifact
              Configuration:
                ProjectName: !Sub "${stackPrefix}-${stackEnvironment}-codebuild"
                PrimarySource: SourceArtifact
                EnvironmentVariables: !Sub |
                  [
                    {"name":"AWS_DEFAULT_REGION", "value":"ap-northeast-1", "type":"PLAINTEXT"},
                    {"name":"FILENAME", "value":"${stackCodePipelineName}", "type":"PLAINTEXT"},
                    {"name":"TARGET_ACCOUNT", "value":"${AWS::AccountId}", "type":"PLAINTEXT"},
                    {"name":"ECR_REPOSITORY", "value":"${stackCodePipelineName}", "type":"PLAINTEXT"},
                    {"name":"TARGET_ECR_REPOSITORY", "value":"${stackCodePipelineName}", "type":"PLAINTEXT"},
                    {"name":"IMAGE_TAG", "value":"${stackImageTag}", "type":"PLAINTEXT"},
                    {"name":"S3BUCKET", "value":"${stackPrefix}-${stackEnvironment}-s3-${AWS::AccountId}/dev", "type":"PLAINTEXT"}
                  ]

継承の仕組み

親スタックの論理IDはCodePipelineA~Dが定義されています。
また、各リソースに定義されているParametersには以下のように名称の異なるパラメータを定義しています。

  • stackCodePipelineName: "auth"
  • stackCodePipelineName: "login"
  • stackCodePipelineName: "api"
  • stackCodePipelineName: "frontend"

このパラメータを子スタックへ継承することで、上記パラメータを受け継いだ子スタックが、それぞれのCodePipelineを構築する仕組みです。

子スタックのCodePipelineのリソースの一部を再掲します。

  # CodePipeline作成
  CodePipeline:
    Type: "AWS::CodePipeline::Pipeline"
    Properties:
      Name: !Sub "${stackPrefix}-${stackEnvironment}-codepipeline-${stackCodePipelineName}"

Properties.Nameに記述されている!Sub "${stackPrefix}-${stackEnvironment}-codepipeline-${stackCodePipelineName}"の箇所で${stackCodePipelineName}が親スタックからパラメータを受け取って、authfrontendの名前のCodePipelineを構築します。

イメージは以下です。

上記のようにしておくことで、別のCodePipelineが増えたときに、子スタックをいじることなく、親スタック側に増えた分のパラメータの異なる情報を定義してやれば良いわけです。

まとめ

CloudFormationも書き方次第で色々と応用できることがわかりました。
私自身IaCの実務はCloudFormationでしか触ったことがないのですが、今後も新たな発見があれば記事にまとめたいと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?