はじめに
データアナリティクス事業本部ビッグデータチームのyosh-kです。
今回は、Windows OSのEC2インスタンスを構築し、CloudWatch Alarmを設定してAlarmが発報されるまでの負荷試験を実施したいと思います。
前提
今回の要件は以下になります。
- EC2インスタンス内に以下のソフトウェアをインストール
- chocolatey
- awscli
- GoogleChrome
- vscode
- Microsoft Visual C++ Redistributable
- EBSの容量は150GBであり、内訳は以下とする。
- Cドライブ: 100
- Dドライブ: 50
- CloudWatch Alarmでは以下を監視する。
- 30 分内の6データポイントのCPUUtilization > 80
- 15 分内の2データポイントのメモリ使用量 > 75
- 15 分内の2データポイントのディスク使用量 < 20
全体的な構成としては以下になります。
- CloudWathはEC2インスタンスからメトリクスを取得します。メモリ使用量やディスク使用量のメトリクスはデフォルトでは取得できないため、CloudWath AgentをEC2インスタンス内にインストールして取得できるように設定します。
- CloudWath Alarmを条件に合わせて設定します。
- Alarm条件となった場合は、EventBridgeでステータスが
ALARM
となったことを検知し、EventBridgeのTargetとして、Step Functionsを設定します。 - Step FunctionsでSNS TOPICとmessageを指定し、Publishすることで、該当のメールアドレスに送信します。
今回Step Functionsを使用している理由は、SNS TOPICでのPublish時に日本語でのメール文言で送信するためになります。 今回の構成については、以下記事を参考に実装しています。
- インスタンスの利用可能な CloudWatch メトリクスのリスト表示 - Amazon Elastic Compute Cloud
- IICS Secure AgentをWindows環境にインストールしてみる(2023年版) | DevelopersIO
- CloudWatchアラームとSNSで日本語の件名・本文のメールを送るためのCloudFormationテンプレートを作ってみた | DevelopersIO
実装
それでは実装になります。実装コードはリンクに格納しています。
windows_ec2.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Windows Server for IICS Secure Agent
Parameters:
Prefix:
Description: Prefix
Type: String
AZ1:
Description: AZ1
Type: String
Default: a
LatestWindowsAmiId :
Type : 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
AllowedValues:
- '/aws/service/ami-windows-latest/Windows_Server-2016-Japanese-Full-Base'
- '/aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base'
- '/aws/service/ami-windows-latest/Windows_Server-2019-Japanese-Full-Base'
Default: '/aws/service/ami-windows-latest/Windows_Server-2019-Japanese-Full-Base'
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instances
Type: String
MinLength: '1'
MaxLength: '64'
AllowedPattern: '[-_ a-zA-Z0-9]*'
ConstraintDescription: can contain only alphanumeric characters, spaces, dashes
and underscores.
Resources:
#-----------------------------------------------------------------------------
# VPC
#-----------------------------------------------------------------------------
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 192.168.0.0/24
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub "${Prefix}-vpc"
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${Prefix}-Public-rtb"
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Sub "${AWS::Region}${AZ1}"
VpcId: !Ref VPC
CidrBlock: 192.168.0.0/28
Tags:
- Key: Name
Value: !Sub "${Prefix}-Public-subnet"
PublicSubnetAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicRouteTable
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId:
Ref: PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: InternetGateway
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Application
Value:
Ref: AWS::StackId
- Key: Network
Value: Public
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId:
Ref: VPC
InternetGatewayId:
Ref: InternetGateway
#-----------------------------------------------------------------------------
# EC2 Instance
#-----------------------------------------------------------------------------
InstanceWindows:
Type: "AWS::EC2::Instance"
Properties:
IamInstanceProfile: !Ref ServerProfile
ImageId: !Ref LatestWindowsAmiId
InstanceType: m5a.xlarge
KeyName:
Ref: KeyName
BlockDeviceMappings:
- DeviceName: "/dev/sda1" # C ドライブ
Ebs:
VolumeType: 'gp2'
VolumeSize: 150
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeviceIndex: "0"
SubnetId: !Ref PublicSubnet
UserData:
Fn::Base64: |
<script>
@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command " [System.Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
tzutil.exe /s "Tokyo Standard Time"
Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -name "HideFileExt" -Value 0
Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -name "Hidden" -Value 1
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
choco install awscli -y
choco install GoogleChrome -y
choco install vscode -y
@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "
$installerUrl = 'https://aka.ms/vs/17/release/vc_redist.x64.exe'
$installerPath = '$env:TEMP\vc_redist.x64.exe'
Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath
Start-Process -FilePath $installerPath -ArgumentList '/install', '/quiet', '/norestart' -Wait
Remove-Item $installerPath
" && echo VC++ 2015 Redistributable installed
</script>
Tags:
- Key: Name
Value: !Sub "${Prefix}-windows-instance"
#-----------------------------------------------------------------------------
# IAM
#-----------------------------------------------------------------------------
ServerRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service:
- "ec2.amazonaws.com"
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
- "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
S3BucketPolicyForSSM:
Type: AWS::IAM::Policy
Properties:
PolicyName: S3BucketPolicyForSSM
Roles:
- !Ref ServerRole
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action: "s3:GetObject"
Resource:
- !Sub "arn:aws:s3:::aws-ssm-${AWS::Region}/*"
- !Sub "arn:aws:s3:::aws-windows-downloads-${AWS::Region}/*"
- !Sub "arn:aws:s3:::amazon-ssm-${AWS::Region}/*"
- !Sub "arn:aws:s3:::amazon-ssm-packages-${AWS::Region}/*"
- !Sub "arn:aws:s3:::${AWS::Region}-birdwatcher-prod/*"
- !Sub "arn:aws:s3:::patch-baseline-snapshot-${AWS::Region}/*"
ServerProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Path: "/"
Roles:
- Ref: ServerRole
InstanceProfileName: !Sub "${Prefix}-Server"
VPCなどのネットワークとEC2インスタンス、EC2インスタンス用IAM Roleを定義しています。
以下記事の内容をCOPYしたものとなりますが、追加でUserDataにMicrosoft Visual C++ Redistributable
をインストールするコマンドを実装しています。
health_resource_check_role.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Template for Creating Statemachine SNS Publish Role
Resources:
StateMachineSNSPublishRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: !Sub "SNSPublishFromStateMachineRole"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- states.amazonaws.com
Action: "sts:AssumeRole"
Path: "/"
Policies:
- PolicyName: StateMachineSNSPublishPolicy
PolicyDocument:
Statement:
- Effect: Allow
Resource: "*"
Action:
- sns:Publish
EventBridgeStateMachineExecuteRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: !Sub "EventBridgeToStateMachineExecutionRole"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- events.amazonaws.com
Action: "sts:AssumeRole"
Path: "/"
Policies:
- PolicyName: EventBridgeStateMachineExecutePolicy
PolicyDocument:
Statement:
- Effect: Allow
Resource: "*"
Action:
- states:StartExecution
Alarmが発報した際に使用するEventBridgeとStep FunctionsのIAM Roleを定義しています。
health_resource_check_sns.yml
AWSTemplateFormatVersion: 2010-09-09
Description: SNS for CloudWatch Alarm notification for dev
Parameters:
NotificateDestinationEmail:
Description: Destination Email of for SNS
Type: String
Resources:
######################## 共通りソース ########################
######################
# SNSトピック #
######################
# 通知先設定
ResourceSnsTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: CloudWatchAlarmResourceNotificationTopic
Subscription:
- Endpoint: !Sub ${NotificateDestinationEmail}
Protocol: email
Alarmが発報してSNS PublishするSNS TOPICを定義しています。
health_resource_check_alarm.yml
AWSTemplateFormatVersion: 2010-09-09
Description: CWAlarm & SNS notification
Parameters:
StatemachineExecRoleARN:
Description: State Machine Execute Role ARN
Type: String
SNSPublishRoleARN:
Description: SNS Publish Role ARN
Type: String
InstanceId:
Description: InstanceId which is watched for CPUUtilization
Type: String
InstanceType:
Description: InstanceType which is watched for Memory
Type: String
CloudWatchAlarmResourceNotificationTopicARN:
Description: ARN of CloudWatchAlarmResourceNotificationTopic
Type: String
Resources:
######################## 監視対象ごとに作成するりソース ########################
######################
# CloudWatch アラーム #
######################
CPUAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: cpu-check-alarm
ComparisonOperator: GreaterThanThreshold
DatapointsToAlarm: 6
EvaluationPeriods: 6
Threshold: 80
Namespace: AWS/EC2
Dimensions:
- Name: InstanceId
Value: !Ref InstanceId
MetricName: CPUUtilization
Period: 300
Statistic: Maximum
TreatMissingData: notBreaching
MemoryAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: memory-check-alarm
ComparisonOperator: GreaterThanThreshold
DatapointsToAlarm: 2
EvaluationPeriods: 3
Threshold: 75
MetricName: "Memory % Committed Bytes In Use"
Namespace: CWAgent
Dimensions:
- Name: InstanceId
Value: !Ref InstanceId
- Name: objectname
Value: Memory
- Name: InstanceType
Value: !Ref InstanceType
Period: 300
Statistic: Maximum
TreatMissingData: notBreaching
CDiskAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: c-disk-free-space-alarm
ComparisonOperator: LessThanThreshold
DatapointsToAlarm: 2
EvaluationPeriods: 3
Threshold: 20
MetricName: "LogicalDisk % Free Space"
Namespace: CWAgent
Dimensions:
- Name: instance
Value: "C:"
- Name: InstanceId
Value: !Ref InstanceId
- Name: objectname
Value: "LogicalDisk"
- Name: InstanceType
Value: !Ref InstanceType
Period: 300
Statistic: Minimum
TreatMissingData: notBreaching
DDiskAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: d-disk-free-space-alarm
ComparisonOperator: LessThanThreshold
DatapointsToAlarm: 2
EvaluationPeriods: 3
Threshold: 20
MetricName: "LogicalDisk % Free Space"
Namespace: CWAgent
Dimensions:
- Name: instance
Value: "D:"
- Name: InstanceId
Value: !Ref InstanceId
- Name: objectname
Value: "LogicalDisk"
- Name: InstanceType
Value: !Ref InstanceType
Period: 300
Statistic: Minimum
TreatMissingData: notBreaching
######################
# EventBridge #
######################
CPUAlarmEvent:
Type: AWS::Events::Rule
Properties:
Description: String
Name: cpu-check-event
EventPattern: !Sub |
{
"source": ["aws.cloudwatch"],
"detail-type": ["CloudWatch Alarm State Change"],
"resources": [{"prefix": "arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:cpu-check-alarm"}],
"detail": {"state": {"value": ["ALARM"]}}
}
Targets:
- Arn: !Ref SNSResourceStateMachine
Id: step-function
RoleArn: !Ref StatemachineExecRoleARN
InputTransformer:
InputPathsMap:
"Account": "$.account"
"AlarmName": "$.detail.alarmName"
"MetricsName": "$.detail.configuration.metrics[0].metricStat.metric.name"
"Reason": "$.detail.state.reason"
"Time": "$.time"
InputTemplate: |
{
"subject": "CPU使用率超過通知",
"message": "CPU使用率超過通知 \n AWSアカウントID: \"<Account>\" \n 時間: \"<Time>\" \n アラーム名: \"<AlarmName>\" \n メトリック: \"<MetricsName>\" \n 理由: \"<Reason>\""
}
MemoryAlarmEvent:
Type: AWS::Events::Rule
Properties:
Description: String
Name: memory-check-event
EventPattern: !Sub |
{
"source": ["aws.cloudwatch"],
"detail-type": ["CloudWatch Alarm State Change"],
"resources": [{"prefix": "arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:memory-check-alarm"}],
"detail": {"state": {"value": ["ALARM"]}}
}
Targets:
- Arn: !Ref SNSResourceStateMachine
Id: step-function
RoleArn: !Ref StatemachineExecRoleARN
InputTransformer:
InputPathsMap:
"Account": "$.account"
"AlarmName": "$.detail.alarmName"
"MetricsName": "$.detail.configuration.metrics[0].metricStat.metric.name"
"Reason": "$.detail.state.reason"
"Time": "$.time"
InputTemplate: |
{
"subject": "メモリ使用率超過通知",
"message": "メモリ使用率超過通知 \n AWSアカウントID: \"<Account>\" \n 時間: \"<Time>\" \n アラーム名: \"<AlarmName>\" \n メトリック: \"<MetricsName>\" \n 理由: \"<Reason>\""
}
CDiskAlarmEvent:
Type: AWS::Events::Rule
Properties:
Description: String
Name: c-disk-check-event
EventPattern: !Sub |
{
"source": ["aws.cloudwatch"],
"detail-type": ["CloudWatch Alarm State Change"],
"resources": [{"prefix": "arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:c-disk-free-space-alarm"}],
"detail": {"state": {"value": ["ALARM"]}}
}
Targets:
- Arn: !Ref SNSResourceStateMachine
Id: step-function
RoleArn: !Ref StatemachineExecRoleARN
InputTransformer:
InputPathsMap:
"Account": "$.account"
"AlarmName": "$.detail.alarmName"
"MetricsName": "$.detail.configuration.metrics[0].metricStat.metric.name"
"Reason": "$.detail.state.reason"
"Time": "$.time"
InputTemplate: |
{
"subject": "Cドライブディスク使用率超過通知",
"message": "Cドライブディスク使用率超過通知 \n AWSアカウントID: \"<Account>\" \n 時間: \"<Time>\" \n アラーム名: \"<AlarmName>\" \n メトリック: \"<MetricsName>\" \n 理由: \"<Reason>\""
}
DDiskAlarmEvent:
Type: AWS::Events::Rule
Properties:
Description: String
Name: !Sub "d-disk-check-event"
EventPattern: !Sub |
{
"source": ["aws.cloudwatch"],
"detail-type": ["CloudWatch Alarm State Change"],
"resources": [{"prefix": "arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:d-disk-free-space-alarm"}],
"detail": {"state": {"value": ["ALARM"]}}
}
Targets:
- Arn: !Ref SNSResourceStateMachine
Id: step-function
RoleArn: !Ref StatemachineExecRoleARN
InputTransformer:
InputPathsMap:
"Account": "$.account"
"AlarmName": "$.detail.alarmName"
"MetricsName": "$.detail.configuration.metrics[0].metricStat.metric.name"
"Reason": "$.detail.state.reason"
"Time": "$.time"
InputTemplate: |
{
"subject": "Dドライブディスク使用率超過通知",
"message": "Dドライブディスク使用率超過通知 \n AWSアカウントID: \"<Account>\" \n 時間: \"<Time>\" \n アラーム名: \"<AlarmName>\" \n メトリック: \"<MetricsName>\" \n 理由: \"<Reason>\""
}
######################## 共通りソース ########################
######################
# ステートマシン #
######################
## 件名カスタマイズ用
SNSResourceStateMachine:
Type: "AWS::StepFunctions::StateMachine"
Properties:
StateMachineName: windows-ec2-resource-check-state-machine
DefinitionString: !Sub |-
{
"StartAt": "PublishSns",
"States": {
"PublishSns": {
"Type": "Task",
"Resource": "arn:aws:states:::sns:publish",
"Parameters": {
"TopicArn": "${CloudWatchAlarmResourceNotificationTopicARN}",
"Message.$": "$.message",
"Subject.$": "$.subject"
},
"End": true
}
}
}
RoleArn: !Ref SNSPublishRoleARN
CloudWatch Alarm、EventBridge、 Step Functionsを定義しています。CloudWatch Alarmの設定内容やメトリクスの意味について先にまとめておきます。
- CloudWath Alarm:
- ComparisonOperator: 閾値の条件を表します。GreaterThanThresholdはより大きい。LessThanThresholdはより小さい。
- DatapointsToAlarm: アラームが ALARM 状態に移るために閾値を超過する必要がある評価期間内のデータポイントの数です。
- EvaluationPeriods: アラームの状態を決定するまでに必要とする最新の期間またはデータポイントの数です。
- Threshold: 閾値。
- Period: アラームの各データポイントを作成する期間です。
- Statistic: メトリクスデータをどのような方法で統計するかを設定します。Maximumは最大値です。
- TreatMissingData: 評価したいデータが取得できず欠落データになる場合の設定。notBreachingは欠落データは閾値内と判断します。
- メトリクス:
- CPUUtilization : CPU使用率を監視するメトリクス。
- Memory % Committed Bytes In Use: 仮想メモリの最大値に対してどのくらいの割合でメモリを確保(コミット)しているかを表すメトリクス。
- LogicalDisk % Free Space: 論理ディスクドライブの利用可能な空き領域を表すメトリクス。
意味を整理した上でAlarmの設定です。
- CPUAlarm: 300秒(5分)ごとのデータポイント取得を6回行い、その全てで80%を超過したらアラートとなります。
- MemoryAlarm: 300秒(5分)ごとのデータポイント取得を3回行い、そのうち2回以上で75%を超過したらアラートとなります。
- CDiskAlarm: 300秒(5分)ごとのデータポイント取得を3回行い、そのうち2回以上で20%を下回るとアラートとなります。
- DDiskAlarm: DドライブのAlarmでAlarm内容はCDiskAlarmと同様になります。
- EventBridge: それぞれのAlarmのstateがALARM状態の際に、Step Functionsを起動するように設定しています。
- Step Functions: 渡されたパラメータを元にSNS Publishを実行します。
参考情報
- Amazon CloudWatch でのアラームの使用 - Amazon CloudWatch
- メモリ使用量を確認する際に見るべきパフォーマンス カウンター | Microsoft Japan Windows Technology Support Blog
- CloudWatch Agentを使ってWindows Serverのメトリクスを監視してみた | DevelopersIO
cloudwatch_agent_config.json
{
"metrics": {
"namespace": "CWAgent",
"append_dimensions": {
"InstanceId": "${aws:InstanceId}",
"InstanceType": "${aws:InstanceType}"
},
"metrics_collected": {
"Processor": {
"measurement": [
"% Idle Time",
"% Interrupt Time",
"% Privileged Time",
"% User Time"
],
"metrics_collection_interval": 60,
"resources": [
"*"
],
"totalcpu": true
},
"LogicalDisk": {
"measurement": [
"% Free Space"
],
"drop_device": true,
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"Memory": {
"measurement": [
"% Committed Bytes In Use"
],
"metrics_collection_interval": 60
}
}
},
"logs": {
"logs_collected": {
"windows_events": {
"collect_list": [
{
"event_format": "xml",
"event_levels": [
"VERBOSE",
"INFORMATION",
"WARNING",
"ERROR",
"CRITICAL"
],
"event_name": "System",
"log_group_name": "CWAgentSystem",
"log_stream_name": "{instance_id}"
},
{
"event_format": "xml",
"event_levels": [
"VERBOSE",
"INFORMATION",
"WARNING",
"ERROR",
"CRITICAL"
],
"event_name": "Application",
"log_group_name": "CWAgentApplication",
"log_stream_name": "{instance_id}"
},
{
"event_format": "xml",
"event_levels": [
"VERBOSE",
"INFORMATION",
"WARNING",
"ERROR",
"CRITICAL"
],
"event_name": "Security",
"log_group_name": "CWAgentSecurity",
"log_stream_name": "{instance_id}"
}
]
}
}
}
}
configファイルを元にCloudWatchメトリクスの取得を行います。 ProcessorメトリクスやWindows logについては、今回の監視対象ではありませんが、CloudWatchメトリクスとして取得する設定としています。
構築
EC2 キーペア作成
まずはEC2画面からキーペアを任意の名前で作成します。名前以外はデフォルトで作成します。
Windows EC2構築
cliコマンドでもデプロイできますが、今回はAWS Management Consoleからデプロイします。
CloudFormationの画面からスタックの作成、templateはwindows_ec2.yml
を選択し新しいソースを作成します。
パラメータは、先ほど入力したキーペアとEC2インスタンスのPrefixなどに使用する任意のPrefixを入力します。
問題なく構築が完了しました。次に構築されたEC2に2パターンで接続をしてみたいと思います。
Windows EC2 Fleet Managerでの接続
EC2インスタンスを選択し、接続ボタンを押下します。 RDPクライアントからFleet Managerを選択し、ユーザー名はデフォルトのAdministratorとします。 認証タイプでは、作成したキーペアを選択しConnectします。
接続に成功しました。
Windows EC2 SSM port forward経由でRDP接続
以下の記事を参考にMacOSでport forward接続をしてみます。
Windows端末からPrivate環境下のWindowsサーバにSSMポートフォワード経由でRDPする方法をまとめてみた | DevelopersIO
事前にMicrosoft Remote Desktopをインストールします。
次にターミナル上でセッションを開始するコマンドを実行します。INSTANCE_IDとIAM_PROFILEは自身の環境のものに置き換えます。
aws ssm start-session --target <INSTANCE_ID> --document-name AWS-StartPortForwardingSession --parameters portNumber=3389,localPortNumber=3389 --profile <IAM_PROFILE>
Starting session with SessionId: botocore-session-1708740374-047d3aac745bd4f82
Port 3389 opened for sessionId botocore-session-1708740374-047d3aac745bd4f82.
Waiting for connections...
次に先ほどインストールしたMicrosoft Remote Desktopを開き、接続を行います。 PC nameはlocalhostとします。 接続する際にAdministratorで接続しますが、その際にはパスワードが必要となります。 パスワードはEC2インスタンスのセキュリティのWindowsパスワードを取得から取得ができます。 プライベートキーファイルには作成したキーペアを読み込ませてパスワードを取得します。 取得したパスワードから問題なくログインができました。
インストールされたソフトウェアの確認
コントロールパネルのプログラムと機能からインストールされたソフトウェアを確認します。想定通り全てインストールされています。
chocolateyは画面上からは確認できませんでしたので、Powershell上で確認しました。
Windows上でのメトリクス確認
今回監視するメトリクスをWindows上で確認します。管理ツールからパフォーマンスモニターを選択します。 パフォーマンスモニタからプラスボタンを選択します。 遷移した画面から今回監視するメトリクスを確認できます。
Cドライブ、Dドライブディスク分割
今回の要件として、Cドライブ:100、Dドライブ:50とあるので、Windows上から設定を行います。
Windows環境のAWS EBS Root Volumeを縮小または分割してみる | DevelopersIO
Windowsボタンを右クリックし、ディスクの管理を選択します。 構築時は150GBが全てCドライブに割り当てられているので、ボリュームの縮小からCドライブを100GBに縮小します。1GBは1024MBなので、50GBを縮小するには50GB * 1024MB/GB = 51200MBとなります。
Cドライブが100GBになりました。次は未割り当て領域を右クリックし、新しいシンプルボリュームを作成します。こちらはデフォルトでDドライブが選択されるので、そのままデフォルト設定で空き領域全てに割り当てる形で作成します。 Cドライブ100GB、Dドライブ50GBとなりました。
EventBridge, Step Functions用IAM Role作成
CloudFormationの画面からスタックの作成、templateはhealth_resource_check_role.yml
を選択し新しいソースを作成します。
SNS TOPIC作成
CloudFormation画面からスタックの作成、templateはhealth_resource_check_sns.yml
を選択し新しいソースを作成します。
メールアドレスは検証用の任意のアドレスを入力します。
スタック作成後はメールアドレスにサブスクリプションを承認するためのメールが届いているはずですので、メール本文からサブスクリプションを承認し、ステータスを確認済みとします。
CloudWatch Agent Install
続いてCloudWatch AgentをInstallします。
以下のSSM Run CommandをAWS CloudShellから実行します。
aws ssm send-command \
--document-name "AWS-ConfigureAWSPackage" \
--document-version "1" \
--targets Key=InstanceIds,Values="<INSTANCE_ID>" \
--parameters action=Install,installationType="Uninstall and reinstall",name=AmazonCloudWatchAgent,version=latest \
--timeout-seconds 600 --max-concurrency "50" --max-errors "0" --region ap-northeast-1
Run Commandの実行結果はSystem Mangerから確認できます。
CloudWatchメトリクス取得設定
続いてCloud Watch メトリクスを取得する設定を行います。実装したcloudwatch_agent_config.jsonについては、SSM Parameter Storeに格納します。パラメータファイル名はAmazonCloudWatch-
のprefixとします。
SSM_PARAMETER_NAMEは先ほど作成したパラメータファイル名に修正してコマンドをCloudShell上で実行します。
aws ssm send-command --document-name "AmazonCloudWatch-ManageAgent" \
--document-version "6" \
--targets '[{"Key":"InstanceIds","Values":["<INSTANCE_ID>"]}]' \
--parameters '{"action":["configure"],"mode":["ec2"],"optionalConfigurationSource":["ssm"],"optionalConfigurationLocation":["<SSM_PARAMETER_NAME>"],"optionalOpenTelemetryCollectorConfigurationSource":["ssm"],"optionalOpenTelemetryCollectorConfigurationLocation":[""],"optionalRestart":["yes"]}' \
--timeout-seconds 600 --max-concurrency "50" --max-errors "0" --region ap-northeast-1
実行結果はSSM Run Commandから確認できます。また、数分後にはCloudWatchメトリクスが取得できていることが画面上からも確認できます。
CloudWatch Alarm, EventBridge, Step Functions構築
最後にCloudWatch Alarm, EventBridge, Step Functionsを構築します。
CloudFormationの画面からスタックの作成、templateはhealth_resource_check_alarm.yml
を選択し新しいソースを作成します。
パラメータにはこれまで作成したリソース名等を入力します。
CloudWatch Alarm, EventBridge, Step Functionsが正常に構築できました。
私の場合は、CloudWatch Alarmにメトリクスが表示されないケースで多くの時間を費やしましたが、設定項目が足りなかったことが原因でした。同じようにCloudWatchメトリクスが取得できているのにCloudWatch Alarmにメトリクスが表示されない事象となった場合は、手動でCloudWatch Alarmを作成してみて、設定項目に不足がないか確認してみると良いと思いました。
負荷試験
それではそれぞれのAlarmに対し、以下記事を参考に負荷試験をしていきたいと思います。
Windowsで使用できるMicrosoftの負荷ツールを使ってみた | ITStudy
CPU負荷試験
CPU負荷試験では、Microsoftが提供しているCPU Stressという負荷ツールを使用します。
CpuStres - Sysinternals | Microsoft Learn
条件として30分間80%超過していれば発報されるので、CPU Stressをローカルにインストールし、4つのProcessのActivityをBusy、1つをMediumとすることで80%を超過するCPU使用率となりました。
30分後に確認しました。6データポイント後にアラート状態となり、メール通知が来ていることも確認できました。
メモリ負荷試験
メモリ負荷試験では、Microsoftが提供しているTestlimitという負荷ツールを使用します。
Testlimit - Sysinternals | Microsoft Learn
条件として15分間75%超過していれば発報されるので、Testlimitをローカルにインストールし、Testlimitで13GBのメモリを確保してみます。
.\Testlimit64.exe -d -c 13000
15分後に確認したところ、アラーム状態となり、そのタイミングで通知が来ていることを確認できました。
ディスク負荷試験
ディスク負荷試験では、指定のファイルサイズのファイルを作成する.NetコマンドをCドライブ、Dドライブ用に実行します。
条件として15分間20%下回れば発報されるので、以下のコマンドをPowershell上で実行します。
$path = "C:\largefile.txt"
$file = [io.file]::Create($path)
$file.SetLength(60GB)
$file.Close()
$path = "D:\largefile.txt"
$file = [io.file]::Create($path)
$file.SetLength(45GB)
$file.Close()
Cドライブ、Dドライブともに15分後にアラーム状態となり、そのタイミングで通知が来ていることを確認できました。
最後に
Windowsのメトリクスを取得してCloudWatchアラームを発報するまでに多くの時間を調査したので、詰まった際は画面上で試しに作成してみて設定を確認した方が早いと学びました。少しでも役立つと幸いです。