1. ホーム
  2. 記事一覧
  3. 【Terraformハンズオン】EC2にCloudWatchアラームを設定してみよう!

2024.07.15

【Terraformハンズオン】EC2にCloudWatchアラームを設定してみよう!

こちらの記事では、IaCツールであるTerraformを使用して、EC2にCloudWatchアラームを設定する方法を解説します。初学者にも理解しやすいよう、身近な例えを交えながら解説していきます。CloudWatchアラームの設定や設定値の理解は、AWSを扱うインフラエンジニアには必須の知識となりますので、手を動かしながら理解を深めていきましょう。

CloudWatchとは

Amazon CloudWatchは、EC2やECS、RDSなど様々なAWSリソースやアプリケーションの監視を行うサービスです。

CPU使用率などの測定値のことを「メトリクス」と呼び、このメトリクスの収集や、ログの管理、イベント管理機能、複数のメトリクス情報を一箇所に集約したダッシュボード作成機能など非常に多岐にわたる機能を提供します。

CloudWatchにおける監視項目に関しては以下の記事にて解説しています。

https://envader.plus/article/358

CloudWatchアラームとは

CloudWatchアラームは、CloudWatchが提供する機能の一つです。CloudWatchアラームを設定することで、「特定の条件が満たされたときにシステム管理者へ通知を送る」などのアクションを実行することができます。

特定の条件とは、「CPU使用率が80%を超えたら」や「サーバーからの5xxエラーが10回を超えたら」といった様々な条件を設定することが可能です。

日常で例えると、「部屋の室温が28度を超えたらスマホに通知を送る」という設定をするイメージです。

このような設定を、AWSのさまざまなリソースに対して行えます。

CloudWatchアラームを設定するメリット

ここからは、CloudWatchアラームを設定する主なメリットについて解説します。

障害対応の迅速化

CPU使用率のしきい値を70%としていたとします。通常運用時には30%前後で推移していたサーバーのCPU使用率が、アクセス集中などにより70%を超えた場合、自動でシステム管理者に通知することができます。

こうすることで、問題発生時にすぐに気づくことができ、障害に対する迅速な対応が可能になります。

コスト管理

AWSの実際の請求額に対してアラートを設定することも可能です。

月のAWS利用料の予算を500ドルとしていた場合、400ドルでアラームのしきい値を設定しておけば予算上限に近づいていることを気づくことができます。早く気づくことで、AWSのリソース調整を行ったり、必要に応じて予算の見直しを行うことが可能です。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html

ユーザー体験の向上

ウェブサイトやアプリケーションのエラーに関するアラームを設定することで、サービスの不具合を素早く発見し、修正に向けて動き出すことができます。

ユーザーがサービスへアクセスしようとしたところ、4xxエラーが表示されてアクセスできない、5xxエラーが表示されてしまうなどの状態になったとします。

4xx、5xxエラーに対してアラームを設定しておけば、管理者が通知を受け取り、リンクの修正やダウンしているサーバーはないかなど復旧に向けて素早く対応することができます。

実際の現場ではCloudWatchアラームはどう使われている?

実際の現場では、CloudWatchアラームは様々な方法で活用されています。以下に、具体的な例をいくつか挙げて解説します。

サーバーリソースの監視

サーバーリソースの監視では、EC2やECSのCPU使用率などに着目します。先述したように、CPU使用率がX%を超えたらアラートを発信するよう設定しておくことで、サーバーの高負荷状態をより早く発見することができます。

リリース直後のサービスであれば、しきい値に達した時点で他のリソースと合わせてメトリクスを確認し、CPU使用率が上がることでどう関連してパフォーマンスが変化するのかといったことも把握できます。

こうすることで、レスポンス遅延などのパフォーマンス低下や、サービス停止を未然に防ぐことができ、しきい値変更や改善に向けて動くことが可能になります。

ネットワークトラフィックの監視

ネットワークトラフィックの監視では、EC2インスタンスのNetworkInメトリクス、ELBのRequestCountなどを監視します。

通常はリクエストがどのくらい来ていたのかを把握する場合に有効ですが、メトリクスが明らかに異常に増加していた場合、DDoS攻撃などのサイバー攻撃が来ていたのではという予測も立てることが可能です。

データベースの監視

RDSインスタンスなどデータベースのメトリクスを監視します。

RDSでは、EC2などと同じCPU使用率や、使用可能なメモリ量、読み取りや書き込みに関する処理時間、コネクション数(どのくらいデータベースに接続しているか)などを計測します。

データベースはサービス、アプリケーションを運用していく上で非常に重要な役割を担います。このようなメトリクスを把握することで、ディスク容量不足によるデータ書き込みエラー防止、RDSインスタンスクラスの見直しに役立ちます。

CloudWatchアラームの評価方法

CloudWatchアラームは、設定した特定の条件が満たされたときに通知を送る機能です。

アラームの評価方法を理解することは重要ですが、若干理解しにくい部分があります。今回はエアコンを例にして解説していくので一緒に学んでいきましょう。

Evaluation Periods(評価期間)

これは、「過去どのくらいの期間を評価するか」の部分に当たります。

例えばエアコンで室温を管理したい場合、「過去何個分までのデータを振り返るか、評価対象にするか」というルールを設定するものです。

Evaluation Periodsを10にした場合、過去10個分のデータを振り返って評価します。30にした場合、過去30個分を振り返って評価します。

Datapoints to Alarm(アラームを発生させるため、異常と判定された数)

「アラームを発生させる条件」にあたり、過去の評価期間のうち何回しきい値を超えたらアラームを発生させるかを指定します。

Evaluation Periodsを10に設定し、Datapoints to Alarmを5に設定した場合、過去10個分のデータを振り返ってみて、5回しきい値を超えていたらアラームを発生させます。

再度エアコンで例えると、過去10個分のデータを振り返ってみて、しきい値(室温)を5回超えたらアラームを発生させることになります。

Period(期間)

CloudWatchがどのくらいの頻度でデータを収集するか(測定間隔)のことです。Periodが1であれば1分、5であれば5分間隔でデータを収集します。

Threshold(しきい値)

どの値を異常とするか、基準となる値のことです。

こちらもエアコンで例えると、28とすると室温が28度以上であれば異常とする、となります。

最後にまとめると、以下のように読み取ることができます。

# 室温が28度以上を異常とする
Threshold = 28

# 過去10回分のデータを評価対象とする
Evaluation Periods = 10

# 10回中5回以上、異常と判定したらアラームを発生させる
Datapoints to Alarm **= 5

# 5分ごとに室温を測定する**
Period **= 5**

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarm-evaluation

CloudWatchアラームの欠落データ処理方法

CloudWatchのメトリクスは、サーバーがダウンした時やリソースの設定によリ、全てのデータポイントがCloudWatchに送信されないことがあります。この時の「欠落したデータをどう処理するか」、という設定があるため、こちらも確認していきます。

notBreaching(正常とみなす)

Evaluation Periods(評価期間)中のデータが取得できていない場合でも、正常と判断します。この場合、問題なく運用できていると判断するためアラームは発生しません。

エアコン(サーバー)からのデータが受信できていなくても、エアコンが壊れているとは判断されなくなります。

notBreachingにすることで、開発環境やテスト環境で一時的にリソースを停止することがわかっている場合や、メンテナンスを実施する際に欠落データが「ALARM」状態として扱われてしまうことを防ぎます。

breaching(異常とみなす)

評価期間中のデータが取得できていない場合、しきい値を超えた状態と判断します。

エアコンでしきい値を28度としていた場合、データが取得できていないときは28度を超えたものとして扱われるため「ALARM」状態となります。

breachingの設定では欠落データを「アラームを発するべき状態」として判断するため、サーバーが高負荷でダウンしてしまった場合や、ネットワークの問題でメトリクスが収集されなくなってしまった場合などにすぐ気付けるというメリットがあります。

ignore(無視する)

ignoreでは、評価期間中にデータが取得できない状態が発生しても無視されます。

この場合、データが欠落していても特に何も変更はされず、アラームの状態は変更されずに維持されます。

missing(データ不足として処理)

missingでは、取得できていないデータをINSUFFICIENT_DATA(データ不足)と判断します。

この状態は、「OK」でも「ALARM」でもない状態として扱われてしまうため、仮にサーバーがダウンしていてメトリクスを取得できない状態が続いていても、気付けない可能性があります。

missingとして設定する場合には、この状態を気付けるようにINSUFFICIENT_DATA状態でのアラーム設定をする必要があるかを検討する必要があります。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-and-missing-data

TerraformでCloudWatchアラームを設定してみよう

ここからはTerraformを使って、実際にEC2を起動してCloudWatchアラームを設定していきます。

基本的なTerraformの記述を記載するため、ご自身で色々設定を変更してみると勉強になると思います。

versions.tf

versions.tfでは、AWS providerの設定をしていきます。

Terraformの基本的な設定方法は以下の記事にて解説しています。

https://envader.plus/article/162

# versions.tf
 terraform {
   required_version = ">= 1.0.0"
   required_providers {
     aws = {
       source  = "hashicorp/aws"
       version = "5.3.0"
     }
   }
 }
 
 provider "aws" {
   region = "ap-northeast-1"
   alias  = "ap-northeast-1" # SNSを作成する際に指定している
 }

ec2.tf

EC2を起動するためのtfファイルです。

SSMで接続できるようにIAM Roleを作成しています。

# main.tf
locals {
  vpc = {
    cidr_block  = "10.0.0.0/16"
    subnet_cidr = "10.0.1.0/24"
  }
}

# AMI
data "aws_ami" "amazonlinux2_latest" {
  owners      = ["amazon"]
  most_recent = true
  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-2.0.*.0-x86_64-gp2"]
  }
}

# EC2へAmazonSSMManagedInstanceCoreをアタッチするためのassumerole
data "aws_iam_policy_document" "assumerole_ec2" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

# vpc
resource "aws_vpc" "dev_vpc" {
  cidr_block           = local.vpc.cidr_block
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = {
    Name  = "dev-vpc"
  }
}

# subnet
resource "aws_subnet" "dev_subnet_public1" {
  vpc_id                  = aws_vpc.dev_vpc.id
  cidr_block              = local.vpc.subnet_cidr
  availability_zone       = "ap-northeast-1a"
  map_public_ip_on_launch = true
  tags = {
    Name  = "dev-subnet-public1"
  }
}

# RouteTable
resource "aws_route_table" "dev_route_table" {
  vpc_id = aws_vpc.dev_vpc.id
  tags = {
    Name  = "dev-route-table"
  }
}

# RouteTableの関連付け
resource "aws_route_table_association" "dev_public_route" {
  subnet_id      = aws_subnet.dev_subnet_public1.id
  route_table_id = aws_route_table.dev_route_table.id
}

# InternetGateway
resource "aws_internet_gateway" "dev_igw" {
  vpc_id = aws_vpc.dev_vpc.id
  tags = {
    Name  = "dev-igw"
  }
}

# Route
resource "aws_route" "dev_route" {
  route_table_id         = aws_route_table.dev_route_table.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.dev_igw.id
}

resource "aws_instance" "dev_ec2" {
  ami                  = data.aws_ami.amazonlinux2_latest.id
  instance_type        = "t3.micro"
  iam_instance_profile = aws_iam_instance_profile.dev_ec2.name
  subnet_id            = aws_subnet.dev_subnet_public1.id
  vpc_security_group_ids = [
    aws_security_group.dev_ec2.id
  ]
  tags = {
    Name = "dev-ec2"
  }
}

# SecurityGroup
resource "aws_security_group" "dev_ec2" {
  name        = "dev-sg"
  description = "dev-sg"
  vpc_id      = aws_vpc.dev_vpc.id

  tags = {
    Name  = "dev-ec2-sg"
  }
}

# アウトバウンドのみ定義
resource "aws_security_group_rule" "dev_ec2_rule_egress" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = -1
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.dev_ec2.id
}

# InstanceProfile
resource "aws_iam_instance_profile" "dev_ec2" {
  name = "dev-ec2"
  role = aws_iam_role.dev_ec2.name
}

# IAM Role
resource "aws_iam_role" "dev_ec2" {
  name               = "dev-ec2"
  path               = "/"
  assume_role_policy = data.aws_iam_policy_document.assumerole_ec2.json
}

# IAM Role Policy Attachment
resource "aws_iam_role_policy_attachment" "dev_ec2" {
  role       = aws_iam_role.dev_ec2.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

alarm.tf

CloudWatchアラームを作成するtfファイルを作成します。

ソースコードの中で記述しているSNSトピック、サブスクリプションの作成方法は、以下の記事で詳しく解説しています。

https://envader.plus/article/412

# alarm.tf
 locals {
   treat_missing_data = "notBreaching"
 }
 
 # snsトピックの作成
 
 # ap-northeast-1のSNSトピック
 resource "aws_sns_topic" "alert_to_mail_ap-northeast-1" {
   name     = "dev-cloudwatch-alarm-alert-to-mail"
   provider = aws.ap-northeast-1
 }
 
 # ap-northeast-1のSNSトピック サブスクリプション
 resource "aws_sns_topic_subscription" "alert_to_email_ap-northeast-1_1" {
   topic_arn = aws_sns_topic.alert_to_mail_ap-northeast-1.arn
   protocol  = "email"
   endpoint  = "xxxxxxxxx@gmail.com"
   provider  = aws.ap-northeast-1
 }
 
 # CloudWatchAlarmの作成
 resource "aws_cloudwatch_metric_alarm" "cpu_alarm" {
   alarm_name = "dev-ec2-cpu-alarm"
   comparison_operator = "GreaterThanOrEqualToThreshold" # アラームがトリガーされる条件(閾値以上)
   evaluation_periods = "5" # データの評価期間
   datapoints_to_alarm = "2" # 何回しきい値を超えたらアラームを発生させるか
   metric_name = "CPUUtilization" # 監視するメトリクス名
   namespace = "AWS/EC2"
   period = "300" # 測定期間。ここは秒で指定する
   statistic = "Average" # メトリクスに適用される統計情報。ここでは平均を指定。
   threshold = "60" # しきい値
   alarm_description = "This metric monitors ec2 instance cpu utilization"
   dimensions = {
     InstanceId = aws_instance.dev_ec2.id # 監視対象とするインスタンスを指定
   }
   alarm_actions = [aws_sns_topic.alert_to_mail_ap-northeast-1.arn] # アラームがトリガーされたときに実行されるアクション(SNSトピックにアラートを送信)
   ok_actions = [aws_sns_topic.alert_to_mail_ap-northeast-1.arn] # アラームがOK状態のときに実行されるアクション(# アラームがOK状態のときに実行されるアクション(SNSトピックにアラートを送信)
   actions_enabled = true # アラームのアクションを有効化する
 
   treat_missing_data = local.treat_missing_data # 欠落データの処理方法 (今回はlocal変数ないで定義)
   insufficient_data_actions = [aws_sns_topic.alert_to_mail_ap-northeast-1.arn] # データ不足の時に実行するアクション(SNSトピックに送信)
 }

CloudWatchアラームのソースコードを解説していきます。

comparison_operator = "GreaterThanOrEqualToThreshold"

comparison_operatorでは、メトリクスの値が指定した閾値以上になったときにアラームがトリガーされるよう指定しています。

evaluation_periods = "5"
period = "60"
datapoints_to_alarm = "2"

アラームが発生する条件として、5つの評価期間を設定しています。それぞれの期間は60秒で設定し、2つのデータポイントがしきい値を超えるとアラームが発生します。

alarm_actions = [aws_sns_topic.alert_to_mail_ap-northeast-1.arn]
ok_actions = [aws_sns_topic.alert_to_mail_ap-northeast-1.arn]

alarm_actionsでは、アラームが発生した時のアクションを定義し、ok_actionsでは、OK状態に戻ったときに実行されるアクションを定義しています。今回のケースでは、両方とも作成したSNSトピックへ通知するようにしています。

まとめ

こちらの記事では、Terraformを使用してEC2インスタンスにCloudWatchアラームを設定する方法について解説しました。

アラームの評価方法、欠落データの処理方法は理解しにくい部分だと筆者自身も感じており、業務にあたる際も毎回確認しながら進めています。

AWSを扱うインフラエンジニアとしては必須のスキルとなってきますので、本記事を参考に色々試していただき、CloudWatchアラームについての理解を深めていただければ幸いです。

【番外編】USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

IT未経験者必見 USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

プログラミング塾に半年通えば、一人前になれると思っているあなた。それ、勘違いですよ。「なぜ間違いなの?」「正しい勉強法とは何なの?」ITを学び始める全ての人に知って欲しい。そう思って書きました。是非読んでみてください。

「フリーランスエンジニア」

近年やっと世間に浸透した言葉だ。ひと昔まえ、終身雇用は当たり前で、大企業に就職することは一種のステータスだった。しかし、そんな時代も終わり「優秀な人材は転職する」ことが当たり前の時代となる。フリーランスエンジニアに高価値が付く現在、ネットを見ると「未経験でも年収400万以上」などと書いてある。これに釣られて、多くの人がフリーランスになろうとITの世界に入ってきている。私もその中の1人だ。数年前、USBも知らない状態からITの世界に没入し、そこから約2年間、毎日勉学を行なった。他人の何十倍も努力した。そして、企業研修やIT塾で数多くの受講生の指導経験も得た。そこで私は、伸びるエンジニアとそうでないエンジニアをたくさん見てきた。そして、稼げるエンジニア、稼げないエンジニアを見てきた。

「成功する人とそうでない人の違いは何か?」

私が出した答えは、「量産型エンジニアか否か」である。今のエンジニア市場には、量産型エンジニアが溢れている!!ここでの量産型エンジニアの定義は以下の通りである。

比較的簡単に学習可能なWebフレームワーク(WordPress, Rails)やPython等の知識はあるが、ITの基本概念を理解していないため、単調な作業しかこなすことができないエンジニアのこと。

多くの人がフリーランスエンジニアを目指す時代に中途半端な知識や技術力でこの世界に飛び込むと返って過酷な労働条件で働くことになる。そこで、エンジニアを目指すあなたがどう学習していくべきかを私の経験を交えて書こうと思った。続きはこちらから、、、、

note記事3000いいね超えの殿堂記事 今すぐ読む

エンベーダー編集部

エンベーダーは、ITスクールRareTECHのインフラ学習教材として誕生しました。 「遊びながらインフラエンジニアへ」をコンセプトに、インフラへの学習ハードルを下げるツールとして運営されています。

RareTECH 無料体験授業開催中! オンラインにて実施中! Top10%のエンジニアになる秘訣を伝授します! RareTECH講師への質疑応答可

関連記事