はじめに
こんにちは。SCSKのふくちーぬです。
前回・前々回の記事では、CI/CD配下でネストされた AWS CloudFormation スタックに対してパイプラインを構築してきました。こちらの記事を読んでいない方は、是非ご一読していただけると幸いです。
CI/CDパイプラインの構成
前回作成したスタックを更新します。スタックを作成していない方は、新規にスタックを作成してください。
Cloud9及びCodeCommitのディレクトリ構成について
ディレクトリ構成は前回から、”ec2.yaml”が追加されました。ファイルの中身は、子スタックとしてEC2を記述したものとなります。
以下のファイルに対して更新があります。
-param.json
-cfn.yaml
-ec2.yaml
param.json
インスタンススタックで使用する、AMIIdを追加しています。
[ { "ParameterKey": "Environment", "ParameterValue": "dev" }, { "ParameterKey": "VPCCidrBlock", "ParameterValue": "192.168.0.0/16" }, { "ParameterKey": "AMIId", "ParameterValue": "ami-012261b9035f8f938" } ]
cfn.yaml
AWSTemplateFormatVersion: 2010-09-09 Description: Parent Stack Parameters: Environment: Type: String VPCCidrBlock: Type: String AMIId: Type: String Resources: # ------------------------------------------------------------# # Network Stack (VPC Subnet RouteTable InternetGateway) # ------------------------------------------------------------# NW: Type: AWS::CloudFormation::Stack Properties: TemplateURL: src/network.yaml Parameters: Environment: !Ref Environment VPCCidrBlock: !Ref VPCCidrBlock # ------------------------------------------------------------# # Security Stack (SecurityGroup) # ------------------------------------------------------------# SECURITY: Type: AWS::CloudFormation::Stack Properties: TemplateURL: src/securitygroup.yaml Parameters: Environment: !Ref Environment VpcId: !GetAtt NW.Outputs.VpcId # ------------------------------------------------------------# # Instance Stack (EC2) # ------------------------------------------------------------# INSTANCE: Type: AWS::CloudFormation::Stack Properties: TemplateURL: src/ec2.yaml Parameters: Environment: !Ref Environment AMIId: !Ref AMIId SubnetId: !GetAtt NW.Outputs.SubnetId SGId: !GetAtt SECURITY.Outputs.SGId
ec2.yaml
ここでは、EC2を1台作成する記述がされています。
AWSTemplateFormatVersion: 2010-09-09 Description: EC2 Stack Parameters: Environment: Type: String AMIId: Type: String SubnetId: Type: AWS::EC2::Subnet::Id SGId: Type: AWS::EC2::SecurityGroup::Id # ------------------------------------------------------------# # EC2 # ------------------------------------------------------------# Resources: EC2Instance: Type: AWS::EC2::Instance Properties: ImageId: !Ref AMIId InstanceType: t2.micro SubnetId: !Ref SubnetId SecurityGroupIds: - !Ref SGId
CodeCommitへのプッシュ
更新済みの以下のファイルをCodeCommitにプッシュします。
-param.json
-cfn.yaml
-ec2.yaml
EC2の作成
承認ステージにて、変更セットの内容を確認します。インスタンススタックが追加されて、EC2が新規作成されることが分かります。
問題なければ、”承認します”を押下してデプロイしてください。
セキュリティグループの更新
ここから本題です。依存関係による変更セットの挙動を検証するために、セキュリティグループを更新してみます。
今回は、以下のようにインバウンドルールを更新します。
AWSTemplateFormatVersion: 2010-09-09 Description: Security Group Stack Parameters: Environment: Type: String VpcId: Type: AWS::EC2::VPC::Id Resources: # ------------------------------------------------------------# # SecurityGroup # ------------------------------------------------------------# SG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enable ssh and web access VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 192.168.0.0/26 #変更 - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 192.168.0.0/26 #変更 Tags: - Key: Name Value: !Sub ${Environment}-sg Outputs: SGId: Value: !Ref SG
更新済みの”securitygroup.yaml”をCodeCommitにプッシュしてください。
変更セットの確認
数分待つと承認ステージまで進んでいるので、通知されたメールから変更セットを確認してください。
親スタックの変更セットの確認
親スタックの変更セットを確認してみると、”INSTANCE”,”SECURITY”に更新があります。セキュリティグループのみ変更しているはずが、セキュリティスタックに加えてインスタンススタックも更新されるように判断してしまいますね。
子スタックの変更セットの確認(INSTANCE)
子スタックの変更セットの中身を確認します。やはり、EC2の更新(置き換えまで)が発生しそうです。
子スタックの変更セットの確認(SECURITY)
こちらは意図した挙動になっていますね。セキュリティグループが更新されることが分かります。
承認とデプロイ
上記の変更セットの中身を確認したら、”承認します”を押下してデプロイしてください。
デプロイが完了しました。
スタックの挙動の確認(INSTANCE)
子スタックのイベントをみてみます。ここでリソースの作成・更新・削除の順序を確認することができます。
どうやら子スタック(INSTANCE)全体の更新はされているようですが、論理IDであるEC2Instanceの更新はされていないですね
➡EC2に対しての更新はされていないことが明らかになりました。
EC2の置き換え等発生していないことが分かって、安心しましたね!
スタックの挙動の確認(SECURITY)
上記と同様に確認します。論理IDであるSGの更新がされていて、子スタック(SECURITY)全体の更新もされたことが分かります。
➡セキュリティグループに対して更新されたことが明らかになりました。
まとめ
今回の検証で、子スタック間で依存関係がある際に、変更されていない子スタックの変更セットにおいて誤検知が発生していることが判明しました。
以下の注意点を理解した上で、ネストされたスタックを利用する必要があります。下記の理由としては、!GetAtt等で取得する値については変更セットの作成時点では、変更の有無を判断できない仕様によるものとなります。すなわち変更の有無は、変更セットの実行(デプロイ)時に決定されるということですね。
最後に
いかがだったでしょうか。
CI/CD配下のネストされたスタックに対して、変更セットの挙動を検証してみました。ネストされたスタックを利用する際に依存関係が複雑な場合、適切な差分を把握することができず、デプロイに少々不安が残る結果になりました。
特にネストされたスタックを利用する場合は、子スタックを分割しすぎないことで子スタック間の依存関係を減らすことが可能なことを念頭においていただければと思います。
本記事が皆様のお役にたてば幸いです。
ではサウナラ~🔥