この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
안녕하세요 클래스메소드 김재욱(Kim Jaewook) 입니다. 이번에는 CloudFormation으로 CloudWatch Alarms를 설정하고, Amazon SNS를 통해 경보를 이메일로 받아보는 과정까지 정리헤 봤습니다.
CloudFormation 작성
VPC 생성
AWSTemplateFormatVersion: "2010-09-09"
Description: VPC Network set
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "Network Configuration"
Parameters:
- VPCCIDR
- PublicSubnetACIDR
- PublicSubnetCCIDR
- PrivateSubnetACIDR
- PrivateSubnetCCIDR
ParameterLabels:
VPCCIDR:
default: "VPC CIDR"
PublicSubnetACIDR:
default: "PublicSubnetA CIDR"
PublicSubnetCCIDR:
default: "PublicSubnetC CIDR"
PrivateSubnetACIDR:
default: "PrivateSubnetA CIDR"
PrivateSubnetCCIDR:
default: "PrivateSubnetC CIDR"
#-------------------------------------------------------------------
#Input VPC, Subnet Parameters
#-------------------------------------------------------------------
Parameters:
VPCCIDR:
Type: String
Default: "10.0.0.0/16"
PublicSubnetACIDR:
Type: String
Default: "10.0.0.0/24"
PublicSubnetCCIDR:
Type: String
Default: "10.0.64.0/24"
PrivateSubnetACIDR:
Type: String
Default: "10.0.128.0/24"
PrivateSubnetCCIDR:
Type: String
Default: "10.0.192.0/24"
#-------------------------------------------------------------------
#Set VPC, InternetGateway, Subnet
#-------------------------------------------------------------------
Resources:
VPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: "true"
EnableDnsHostnames: "true"
InstanceTenancy: default
Tags:
- Key: Name
Value: !Sub "test-vpc"
InternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: !Sub "test-igw"
InternetGatewayAttachment:
Type: "AWS::EC2::VPCGatewayAttachment"
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PublicSubnetA:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: !Ref PublicSubnetACIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-front-subnet-1a"
PublicSubnetC:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1c"
CidrBlock: !Ref PublicSubnetCCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-front-subnet-1c"
PrivateSubnetA:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: !Ref PrivateSubnetACIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-application-subnet-1a"
PrivateSubnetC:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1c"
CidrBlock: !Ref PrivateSubnetCCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-application-subnet-1c"
#-------------------------------------------------------------------
#Route Tables
#-------------------------------------------------------------------
FRONTRTB :
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-front-rtb"
APPRTB1A:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-application-rtb-1a"
APPRTB1C:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-application-rtb-1c"
FRONTRTBroute:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref FRONTRTB
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref InternetGateway
#-------------------------------------------------------------------
#Route Tables Subnet Association
#-------------------------------------------------------------------
FRONTRTBAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnetA
RouteTableId: !Ref FRONTRTB
FRONTRTB2Association:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnetC
RouteTableId: !Ref FRONTRTB
APPRTB1AAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PrivateSubnetA
RouteTableId: !Ref APPRTB1A
APPRTB1CAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PrivateSubnetC
RouteTableId: !Ref APPRTB1C
#-------------------------------------------------------------------
#OutPut
#-------------------------------------------------------------------
Outputs:
# VPC
VPC:
Value: !Ref VPC
Export:
Name: !Sub "test-vpc"
VPCCIDR:
Value: !Ref VPCCIDR
Export:
Name: !Sub "test-vpc-cidr"
# Subnet
PublicSubnetA:
Value: !Ref PublicSubnetA
Export:
Name: !Sub "test-front-subnet-1a"
PublicSubnetACIDR:
Value: !Ref PublicSubnetACIDR
Export:
Name: !Sub "test-front-subnet-1a-cidr"
PublicSubnetC:
Value: !Ref PublicSubnetC
Export:
Name: !Sub "test-front-subnet-1c"
PublicSubnetCCIDR:
Value: !Ref PublicSubnetCCIDR
Export:
Name: !Sub "test-front-subnet-1c-cidr"
PrivateSubnetA:
Value: !Ref PrivateSubnetA
Export:
Name: !Sub "test-application-subnet-1a"
PrivateSubnetACIDR:
Value: !Ref PrivateSubnetACIDR
Export:
Name: !Sub "test-application-subnet-1a-cidr"
PrivateSubnetC:
Value: !Ref PrivateSubnetC
Export:
Name: !Sub "test-application-subnet-1c"
PrivateSubnetCCIDR:
Value: !Ref PrivateSubnetCCIDR
Export:
Name: !Sub "test-application-subnet-1c-cidr"
# Route
FRONTRTB:
Value: !Ref FRONTRTB
Export:
Name: !Sub "test-front-rtb"
APPRTB1A:
Value: !Ref APPRTB1A
Export:
Name: !Sub "test-application-rtb-1a"
APPRTB1C:
Value: !Ref APPRTB1C
Export:
Name: !Sub "test-application-rtb-1c"
다음 코드를 이용해서 VPC를 생성합니다.
EC2 생성
AWSTemplateFormatVersion: "2010-09-09"
Description:
Create EC2
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "EC2 Configuration"
Parameters:
- BastionEC2KeyPair
- AppEC2KeyPair
ParameterLabels:
BastionEC2KeyPair:
default: "tokyo-ec2-key"
AppEC2KeyPair:
default: "AppEC2KeyPair"
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
BastionEC2KeyPair:
Type: String
Default: "tokyo-ec2-key"
AppEC2KeyPair:
Type: String
Default: "AppEC2KeyPair"
# ------------------------------------------------------------#
# Create Security Group
# ------------------------------------------------------------#
Resources:
FrontBastionSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "test-front-bastion-sg"
GroupName: test-front-bastion-sg
SecurityGroupIngress:
IpProtocol: tcp
FromPort : 22
ToPort : 22
CidrIp: 0.0.0.0/0
VpcId: { "Fn::ImportValue": !Sub "test-vpc" }
Tags:
- Key: "Name"
Value: test-front-bastion-sg
APPSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "test-app-sg"
GroupName: test-app-sg
SecurityGroupIngress:
-
IpProtocol: tcp
FromPort : 22
ToPort : 22
SourceSecurityGroupId: !GetAtt FrontBastionSecurityGroup.GroupId
VpcId: { "Fn::ImportValue": !Sub "test-vpc" }
Tags:
- Key: "Name"
Value: test-app-sg
# ------------------------------------------------------------#
# Create EC2 Instance
# ------------------------------------------------------------#
# Bastion EC2
BastionEC2:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-02c3627b04781eada
InstanceType: t3.micro
KeyName: !Ref BastionEC2KeyPair
DisableApiTermination: true
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeviceIndex: "0"
SubnetId: { "Fn::ImportValue": !Sub "test-front-subnet-1a" }
GroupSet:
- !Ref FrontBastionSecurityGroup
Tags:
- Key: "Name"
Value: test-front-bastion
# test-app-1a
AppEC2:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-02c3627b04781eada
InstanceType: t3.micro
KeyName: !Ref AppEC2KeyPair
DisableApiTermination: true
SecurityGroupIds:
- !Ref APPSecurityGroup
SubnetId: { "Fn::ImportValue": !Sub "test-application-subnet-1a" }
Tags:
- Key: "Name"
Value: test-app-1a
EC2 인스턴스를 생성합니다.
SNS Topic 생성
AWSTemplateFormatVersion: "2010-09-09"
Description:
Create sns
# ------------------------------------------------------------#
# Create sns Topic
# ------------------------------------------------------------#
Resources:
MySNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: my_sns_topic
Subscription:
- Endpoint: kim.jaewook@classmethod.jp
Protocol: email
#-------------------------------------------------------------------
#OutPut
#-------------------------------------------------------------------
Outputs:
# SNS
SNS:
Value: !Ref MySNSTopic
Export:
Name: !Sub "my-sns-topic"
이메일로 알람을 받기 위해 Amazon SNS도 생성합니다.
Amazon SNS에 대한 이메일 설정은 아래 블로그를 참고해 주세요.
CloudWatch Alarms 생성
AWSTemplateFormatVersion: "2010-09-09"
Description:
Set CloudWatch Alarms
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
Ec2InstanceId:
Description: Ec2 InstanceId
Type: AWS::EC2::Instance::Id
# ------------------------------------------------------------#
# Create CloudWatch Alarms
# ------------------------------------------------------------#
Resources:
C2CPUUtilizationAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmActions:
- { "Fn::ImportValue": !Sub "my-sns-topic" }
AlarmName: test-Alarms
MetricName: CPUUtilization
Namespace: AWS/EC2
Statistic: Average
Period: 60
EvaluationPeriods: 2
Threshold: 40
TreatMissingData: breaching
OKActions:
- { "Fn::ImportValue": !Sub "my-sns-topic" }
ComparisonOperator: GreaterThanOrEqualToThreshold
Dimensions:
- Name: InstanceId
Value: !Ref Ec2InstanceId
마지막으로 CloudWatch Alarms를 생성합니다.
간단하게 CPU 사용률이 40%를 넘기면 이메일로 통지가 가는 설정입니다.
CloudWatch Alarms에 관한 상세한 속성은 아래 링크를 참고해 주세요.
CloudWatch Alarms를 생성할 때, EC2 인스턴스를 선택해야 하는데, CPU 사용률을 감시하고 싶은 EC2 인스턴스를 선택합니다.
이메일로 알람 받아보기
sudo amazon-linux-extras install epel -y
sudo yum install stress -y
sudo stress --cpu 1 --timeout 600
stress를 사용해서 강제로 CPU 사용률을 올립니다. 600초 동안 1개의 CPU를 최대한 사용합니다.
CloudWatch Alarms에서 확인해 보면 40%를 넘겼기 때문에 경보 상태가 된 것을 확인할 수 있습니다.
로그를 살펴보면, 정상에서 경보 상태로 변경된 다음, 지정해 둔 SNS Topic가 실행된 것을 확인할 수 있습니다.
이메일로 들어가 보면, 다음과 같이 알람이 온 것을 확인할 수 있습니다.
stress를 중지시키고 기다려보면 다시 CPU가 40% 밑으로 떨어지면서 status가 알람에서 OK 상태로 변경 됐다는 메일이 날아오는 것을 확인할 수 있습니다.
그 외 EC2 인스턴스 CPU 사용률을 Slack으로 받아보는 내용에 대해서는 아래 블로그를 참고해 주세요.
본 블로그 게시글을 보시고 문의 사항이 있으신 분들은 클래스메소드코리아 (info@classmethod.kr)로 연락 주시면 빠른 시일 내 담당자가 회신 드릴 수 있도록 하겠습니다 !