[アップデート] Amazon CloudWatchが関連するテレメトリやリソース関係を可視化できるようになりました
こんにちは。たかやまです。
Amazon CloudWatchが関連するテレメトリやリソースの関係を可視化することで、問題の根本原因をより迅速に特定し、運用効率を向上させることができるようになりました!
三行まとめ
- CloudWatchで関連するテレメトリやリソースの関係を可視化できるようになった
- AWSマネジメントコンソールの「Operational troubleshooting」タブからも利用可能
- ネイティブに対応していないテレメトリについてはカスタムテレメトリとして追加も可能
やってみた
サンプルリソースとしてAuto ScalingするEC2インスタンスを作成します。
以下CDKサンプルコードです。
サンプルコード
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import * as autoscaling from 'aws-cdk-lib/aws-autoscaling';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
class AutoScalingStack extends cdk.Stack {
constructor(app: cdk.App, id: string, props?: cdk.StackProps) {
super(app, id, props);
const vpc = new ec2.Vpc(this, 'MyVPC', {
maxAzs: 2,
natGateways: 1,
});
(vpc.node.defaultChild as ec2.CfnVPC).overrideLogicalId('MyVPC');
const albSecurityGroup = new ec2.SecurityGroup(this, 'ALBSecurityGroup', {
vpc,
description: 'Security group for ALB',
allowAllOutbound: true,
securityGroupName: 'my-alb-sg',
});
(albSecurityGroup.node.defaultChild as ec2.CfnSecurityGroup).overrideLogicalId('ALBSecurityGroup');
albSecurityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(80),
'Allow HTTP traffic'
);
const ec2SecurityGroup = new ec2.SecurityGroup(this, 'EC2SecurityGroup', {
vpc,
description: 'Security group for EC2 instances',
allowAllOutbound: true,
securityGroupName: 'my-ec2-sg',
});
(ec2SecurityGroup.node.defaultChild as ec2.CfnSecurityGroup).overrideLogicalId('EC2SecurityGroup');
ec2SecurityGroup.addIngressRule(
albSecurityGroup,
ec2.Port.tcp(80),
'Allow traffic from ALB'
);
const userData = ec2.UserData.forLinux();
userData.addCommands(
'yum update -y',
'yum install -y httpd',
'systemctl start httpd',
'systemctl enable httpd',
'echo "<html><body><h1>Hello from EC2</h1></body></html>" > /var/www/html/index.html',
'chmod 644 /var/www/html/index.html'
);
const asg = new autoscaling.AutoScalingGroup(this, 'ASG', {
vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
securityGroup: ec2SecurityGroup,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE4_GRAVITON, ec2.InstanceSize.MICRO),
machineImage: ec2.MachineImage.latestAmazonLinux2023({
cpuType: ec2.AmazonLinuxCpuType.ARM_64
}),
userData: userData,
minCapacity: 2,
maxCapacity: 4,
desiredCapacity: 2,
healthCheck: autoscaling.HealthCheck.elb({ grace: cdk.Duration.seconds(180) }),
autoScalingGroupName: 'my-asg',
});
(asg.node.defaultChild as autoscaling.CfnAutoScalingGroup).overrideLogicalId('MyASG');
const lb = new elbv2.ApplicationLoadBalancer(this, 'LB', {
vpc,
internetFacing: true,
securityGroup: albSecurityGroup,
loadBalancerName: 'my-alb',
});
(lb.node.defaultChild as elbv2.CfnLoadBalancer).overrideLogicalId('MyALB');
const listener = lb.addListener('Listener', {
port: 80,
defaultAction: elbv2.ListenerAction.fixedResponse(200, {
contentType: 'text/plain',
messageBody: 'OK',
}),
});
(listener.node.defaultChild as elbv2.CfnListener).overrideLogicalId('MyALBListener');
const targetGroup = listener.addTargets('Target', {
port: 80,
targets: [asg],
targetGroupName: 'my-target-group',
healthCheck: {
path: '/',
unhealthyThresholdCount: 2,
healthyThresholdCount: 2,
interval: cdk.Duration.seconds(15),
timeout: cdk.Duration.seconds(10),
},
deregistrationDelay: cdk.Duration.seconds(30),
});
(targetGroup.node.defaultChild as elbv2.CfnTargetGroup).overrideLogicalId('MyTargetGroup');
const requestCountPolicy = asg.scaleOnRequestCount('AModestLoad', {
targetRequestsPerMinute: 60,
});
(requestCountPolicy.node.defaultChild as autoscaling.CfnScalingPolicy).overrideLogicalId('RequestCountScalingPolicy');
const cpuPolicy = asg.scaleOnCpuUtilization('CpuScaling', {
targetUtilizationPercent: 70,
cooldown: cdk.Duration.seconds(300),
});
(cpuPolicy.node.defaultChild as autoscaling.CfnScalingPolicy).overrideLogicalId('CPUUtilizationScalingPolicy');
new cdk.CfnOutput(this, 'LoadBalancerDNS', {
value: lb.loadBalancerDnsName,
description: 'The DNS name of the load balancer',
}).overrideLogicalId('LoadBalancerDNS');
}
}
const app = new cdk.App();
new AutoScalingStack(app, 'AutoScalingStack');
app.synth();
AWSマネジメントコンソールから確認する
こちらの機能は、AWSマネジメントコンソール全体に統合されています。
最初見た時どこにあるのだろうと探しましたが...
Amazon Qにならぶ形でOperational troubleshooting
としてタブにありました!
開くと「リソースを検索」がでるので、こちらから検索していきます。
リソースタグやインスタンスタイプで絞り込めるようなので、さきほどサンプルコードで作成したEC2を検索してみます。
すると、以下のようにトポロジーマップとして対象EC2とそれに関連するリソースが合わせて表示されました。
その他情報としては、対象リソースの関連メトリクスやログも合わせて表示してくれるようです。
後述するCloudWatchからの検索方法ではメトリクスが表示されているので、AWSマネジメントコンソールからの呼び出しはまだ動作が安定していないのかもしれません。
リソースを見ているときに、このリソースがどのリソースと紐づいているだろうという際に活用できるかと思います。
CloudWatchから確認する
また、この機能はCloudWatchと連携して利用することができます。
個人的にこちらの使い方がとても便利だと感じました。
作成したAuto ScalingグループのCloudWatch Alarmを確認してみます。
こちらを確認すると 関連するものを詳しく見る
というボタンが追加されていることがわかります。
こちらを選択するとCloudWatch Alarmに紐づくリソースが自動で検索され、トポロジーマップとして表示されます。
また、紐づくリソースを選択すると芋づる式に関連リソースが表示されます。
CloudWatch Alarmが増えてくるとどのアラームがどのリソースと紐づいているのかわかりづらいことがありますが、そういった場合にこの機能を活用すると便利そうです。
また、Container Insightsなどの他のCloudWatch機能とも連携しているようなので、ぜひお使いのモニタリングツールの調査に活用いただければと思います。
テレメトリ対象リソース
100を超えるAWSサービスを対象としてます。
リソースごとにメトリクス
/ ログ
を取得できるかは異なるので詳細は以下のリンクを参照してください。
カスタムテレメトリの追加
ネイティブに対応しているリソース以外にもカスタムテレメトリの形で追加することができます。
カスタムテレメトリとして登録したい情報について、メトリクスについてはPutMetricData、ログについてはPutLogEventsで登録することができます。
その際にKeyAttributes
およびAttributes
を指定することで、リソースとの関連性を持たせることができます。
また、CloudWatch AgentまたはEKSで追加テレメトリ情報を送る場合に以下のバージョン以上が対応となります。
- CloudWatch Agent:
1.300049.1
- EKS:
v2.3.1-eksbuild.1
およびCloudWatch Observability EKS アドオン
最後に
CloudWatchでの関連するテレメトリやリソースの関係の可視化に対応しました。
リソースマップだったり、可視化されることで困ることはないのでありがたいアップデートですね!
私も積極的に使っていきたいと思います。
このブログがどなたかの参考になれば幸いです。
以上、たかやま(@nyan_kotaroo)でした。