Amazon ECS Service ConnectをAWS CloudFormationでデプロイして削除してみた
こんにちは、シマです。
先日、以下の記事を書きました。今回はそのリソース削除に関するお話です。
背景
そもそも、AWS CloudFormationではスタックを削除することで作成したリソースを削除することが可能です。
今回はタイトル通りAWS CloudFormationにより、Amazon ECS Service Connectを実装しており、テンプレート削除により実装したリソースの削除を行いました。・・行ったつもりでした。実際何が起こっていたかというと名前空間が削除されずに残っていました。
問題はある?
では、名前空間が削除されずに残っていることにより何か問題があるのでしょうか。結論としては影響のあるような問題はなさそうです。
真っ先に気になる料金ですが、名前空間が残っているだけでは、料金の発生はなさそうでした。(よかった)
次に検証のため、AWS CloudFormationによるスタックの作成、削除の繰り返しを行うと思いますが、名前空間が残っていることによるエラー発生はせずに実施できます。これは、スタックの再作成時には、残ってしまっている名前空間に再度関連付けされているのでエラーにならずに作成ができています。
暫定対応
AWS CloudFormationのスタックは削除済みなので、AWS CloudFormationからアクションをすることはできません。単純にAWS マネジメントコンソールから削除すれば削除できます。
ですが、せっかくAWS CloudFormationで作成しているのに手動による削除対応は正直モヤッとします。
AWS CloudFormationの対応
恒久対応としてテンプレートを変更しました。変更内容は以下の追加を行いました。
# Namespace # ------------------------------------------------------------# namespace: Type: AWS::ServiceDiscovery::HttpNamespace Properties: Name: local # Cluster # ------------------------------------------------------------# cluster: DependsOn: namespace Type: AWS::ECS::Cluster Properties: ClusterName: cluster ServiceConnectDefaults: Namespace: local
ECSクラスター作成時の自動生成により名前空間を作成することをやめて、別で定義して作成するようにしました。また、同じ名前空間名を指定することでリソースの関連付けをしているため、依存関係が指定されていません。依存関係が指定されていないと、リソース作成や削除時にエラーが出ます。
そのため、DependsOnで明示的に依存関係を宣言しています。
テンプレート全体
前回のテンプレートに対して、前述の更新内容を反映しました。
template.yml
AWSTemplateFormatVersion: '2010-09-09' Description: Amazon ECS Service Connect Sample # ------------------------------------------------------------# # Input Parameters # ------------------------------------------------------------# Parameters: AZa: Type: AWS::EC2::AvailabilityZone::Name Default: ap-northeast-1a AZc: Type: AWS::EC2::AvailabilityZone::Name Default: ap-northeast-1c Resources: # VPC # ------------------------------------------------------------# vpctest: Type: AWS::EC2::VPC Properties: CidrBlock: "172.16.0.0/16" EnableDnsSupport: true EnableDnsHostnames: true InstanceTenancy: default Tags: - Key: Name Value: "vpc-test" # RouteTable # ------------------------------------------------------------# rtpublic: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref vpctest Tags: - Key: Name Value: "rt-public" # Subnet # ------------------------------------------------------------# snpublica: Type: AWS::EC2::Subnet Properties: VpcId: !Ref vpctest CidrBlock: "172.16.1.0/24" AvailabilityZone: !Ref AZa Tags: - Key: Name Value: "sn-public-a" rtasnpublica: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref snpublica RouteTableId: !Ref rtpublic snpublicc: Type: AWS::EC2::Subnet Properties: VpcId: !Ref vpctest CidrBlock: "172.16.2.0/24" AvailabilityZone: !Ref AZc Tags: - Key: Name Value: "sn-public-c" rtasnpublicc: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref snpublicc RouteTableId: !Ref rtpublic # Internet Gateway # ------------------------------------------------------------# igw: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: "igw" atigw: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref vpctest InternetGatewayId: !Ref igw rtpublicigw: Type: AWS::EC2::Route Properties: RouteTableId: !Ref rtpublic DestinationCidrBlock: "0.0.0.0/0" GatewayId: !Ref igw # Security Group # ------------------------------------------------------------# sgclient: Type: AWS::EC2::SecurityGroup Properties: GroupName: sgclient GroupDescription: sgclient VpcId: !Ref vpctest SecurityGroupEgress: - IpProtocol: "-1" CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: sgclient sgweb: Type: AWS::EC2::SecurityGroup Properties: GroupName: sgweb GroupDescription: sgweb VpcId: !Ref vpctest SecurityGroupEgress: - IpProtocol: "-1" CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: sgweb sgwebfromclient: Type: AWS::EC2::SecurityGroupIngress Properties: IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Ref sgclient GroupId: !Ref sgweb Description: "web from client" # IAM Role # ------------------------------------------------------------# roleecstaskexec: Type: AWS::IAM::Role Properties: Path: / RoleName: "role-ecs-taskexec" AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - sts:AssumeRole Principal: Service: - ecs-tasks.amazonaws.com ManagedPolicyArns: - "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" Policies: - PolicyName: roleecstaskexecpolicy PolicyDocument: Statement: - Effect: Allow Action: - logs:CreateLogGroup Resource: '*' roleecstask: Type: AWS::IAM::Role Properties: Path: / RoleName: "role-ecstask" AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - sts:AssumeRole Principal: Service: - ecs-tasks.amazonaws.com Policies: - PolicyName: roleecstaskpolicy PolicyDocument: Statement: - Effect: Allow Action: - ssmmessages:CreateControlChannel - ssmmessages:CreateDataChannel - ssmmessages:OpenControlChannel - ssmmessages:OpenDataChannel - logs:CreateLogGroup Resource: '*' # LogGroup # ------------------------------------------------------------# ecslogs: Type: AWS::Logs::LogGroup DeletionPolicy: Delete UpdateReplacePolicy: Delete Properties: LogGroupName: "/ecs/logs" RetentionInDays: 30 # Namespace # ------------------------------------------------------------# namespace: Type: AWS::ServiceDiscovery::HttpNamespace Properties: Name: local # Cluster # ------------------------------------------------------------# cluster: DependsOn: namespace Type: AWS::ECS::Cluster Properties: ClusterName: cluster ServiceConnectDefaults: Namespace: local # TaskDefinition # ------------------------------------------------------ taskdefinition: Type: AWS::ECS::TaskDefinition Properties: Family: taskdefinition Cpu: 512 Memory: 1024 ExecutionRoleArn: !GetAtt roleecstaskexec.Arn NetworkMode: awsvpc RequiresCompatibilities: - FARGATE TaskRoleArn: !GetAtt roleecstask.Arn ContainerDefinitions: - Name: container Essential: True Image: "public.ecr.aws/amazonlinux/amazonlinux:2023.0.20230517.1" Command: - "/bin/sh -c \"yum install -y httpd && echo '<html> <head> <title>Sample</title> </head> <body> TEST </body> </html>' > /var/www/html/index.html && /usr/sbin/httpd -D FOREGROUND\"" EntryPoint: - "sh" - "-c" Memory: 512 PortMappings: - ContainerPort: 80 Protocol: TCP AppProtocol: http Name: website LogConfiguration: LogDriver: awslogs Options: awslogs-group: "/ecs/logs" awslogs-region: "ap-northeast-1" awslogs-stream-prefix: ecs awslogs-create-group: true # Service # ------------------------------------------------------------# serviceweb: Type: AWS::ECS::Service Properties: ServiceName: "service-web" Cluster: !Ref cluster DesiredCount: 2 LaunchType: FARGATE EnableExecuteCommand: True TaskDefinition: !Ref taskdefinition PlatformVersion: LATEST ServiceConnectConfiguration: Enabled: true Namespace: local Services: - DiscoveryName: web ClientAliases: - DnsName: "web.local" Port: 80 PortName: website NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - !Ref sgweb Subnets: - !Ref snpublica - !Ref snpublicc serviceclient: Type: AWS::ECS::Service Properties: ServiceName: "service-client" Cluster: !Ref cluster DesiredCount: 2 LaunchType: FARGATE EnableExecuteCommand: True TaskDefinition: !Ref taskdefinition PlatformVersion: LATEST ServiceConnectConfiguration: Enabled: true Namespace: local Services: - DiscoveryName: client ClientAliases: - DnsName: "client.local" Port: 80 PortName: website NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - !Ref sgclient Subnets: - !Ref snpublica - !Ref snpublicc
最後に
今回はスタックの削除で削除しきれていなかった名前空間をスタックの削除で同時に削除されるようにテンプレートを更新しました。
本記事がどなたかのお役に立てれば幸いです。