こんにちは、シマです。
先日、以下の記事を書きました。今回はそのリソース削除に関するお話です。
背景
そもそも、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
最後に
今回はスタックの削除で削除しきれていなかった名前空間をスタックの削除で同時に削除されるようにテンプレートを更新しました。
本記事がどなたかのお役に立てれば幸いです。