Monitor a Fleet of EC2 Instances

Build a unified CloudWatch dashboard monitoring three EC2 instances with custom metrics.

Introduction

30 Second Summary

When you manage multiple servers, problems hide in the ones you are not watching. One server quietly runs out of memory while you are busy checking another, and by the time you notice, your users already have.

In this project, you will build a fleet monitoring system that watches three EC2 instances from a single CloudWatch dashboard. You will install a monitoring agent to unlock hidden metrics, set up email alerts, and stress-test a server to prove the whole pipeline works.

What You'll Build

You stress-test one of your servers and watch its CPU line spike on the dashboard while the other two stay flat, then check your inbox to find the alert already waiting.

By the end of this project, you'll have:

  • You can see CPU, memory, and disk metrics for all three instances updating live on a single dashboard, so you can spot which server is struggling at a glance.
  • You get an email notification the moment one instance crosses your CPU threshold, proving you do not need to stare at a screen to catch problems.
  • You can stress-test one instance and watch the alarm transition from OK to In alarm while the other two remain healthy on the same graph.
  • Secret Mission: Configure cross-account observability so your monitoring account is ready to receive metrics from other AWS accounts the moment you create them.

Are there any prerequisites?

You need an AWS account with free tier eligibility. This project stays entirely within the free tier (3 t2.micro instances, 3 free dashboards, 10 free alarms, 10 free custom metrics).

You will also need the AWS CLI installed on your machine. Step 1 covers all other setup, including IAM roles and instance launching.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters.

Launch Your Fleet and Set Up IAM

Before you can monitor anything, you need something to monitor. Your fleet of three EC2 instances needs the right permissions to communicate with Systems Manager and CloudWatch.

Without the correct IAM role, Systems Manager cannot reach your instances and the CloudWatch agent cannot publish data. In this step, you will create an IAM role with the right policies, launch your three-instance fleet, and confirm that all three are reachable.

In this step, get ready to:
  • Create an IAM role with permissions for Systems Manager and CloudWatch.
  • Launch three t2.micro Amazon Linux 2023 instances as your fleet.
  • Verify all three instances appear as managed nodes in Systems Manager Fleet Manager.
Create an IAM role for your fleet

Every instance in your fleet needs permission to talk to two AWS services: Systems Manager (so you can manage them remotely) and CloudWatch (so they can publish metrics). An IAM role bundles these permissions together and attaches them to each instance at launch.

  • In the AWS Management Console search bar at the top, type IAM and select IAM from the results.
  • In the left navigation pane, click Roles.
  • Click Create role.
  • Under Trusted entity type, select AWS service.
  • Under Use case, select EC2.
  • Click Next.

Now you will attach the two managed policies your fleet needs.

  • In the search box on the Add permissions page, type AmazonSSMManagedInstanceCore.
  • Check the box next to AmazonSSMManagedInstanceCore.
  • Clear the search box, then type CloudWatchAgentServerPolicy.
  • Check the box next to CloudWatchAgentServerPolicy.
  • Click Next.
  • For Role name, enter CloudWatchFleetRole.
  • Scroll down and click Create role.

You should see a green success banner confirming the role was created.

What do these policies do?

AmazonSSMManagedInstanceCore lets Systems Manager communicate with and manage the instance remotely. This is what allows you to run commands on your fleet without SSH.

CloudWatchAgentServerPolicy gives the CloudWatch agent permission to publish metrics and logs from inside the instance to the CloudWatch service.

What is an IAM role?

An IAM role is like a name badge that grants specific permissions. When you attach a role to an EC2 instance, any software running on that instance can use the role's permissions to talk to other AWS services without needing a password or API key stored on the machine.

Launch three EC2 instances as your fleet

You will launch three instances representing a typical small fleet: a web server, an app server, and a database server. Each gets the IAM role you just created so they can report to CloudWatch and be managed by Systems Manager.

  • In the console search bar, type EC2 and select EC2 from the results.
  • Click Launch instance.
  • Under Name and tags, enter WebServer as the name.
  • Under Application and OS Images, confirm that Amazon Linux 2023 AMI is already selected (it is the default).
  • Under Instance type, select t2.micro (Free tier eligible).
  • Under Key pair (login), select Proceed without a key pair (Not recommended).

Why no key pair?

You will connect to these instances through Systems Manager Session Manager, not SSH. Session Manager uses the IAM role you created instead of SSH keys, so a key pair is not needed.

  • Under Network settings, keep the default VPC and default security group.
  • Expand the Advanced details section at the bottom.
  • For IAM instance profile, select CloudWatchFleetRole from the dropdown.
  • Click Launch instance.

You should see a success message with a link to the instance ID. Your first fleet member is now launching.

Don't see CloudWatchFleetRole in the dropdown?

The role can take a minute to propagate after creation. Refresh the page and try expanding Advanced details again. If it still does not appear, return to IAM and confirm the role was created with the EC2 trusted entity.

Help me troubleshoot why my IAM role does not appear in the EC2 launch wizard IAM instance profile dropdown.

Now launch the second and third instances with the same settings but different names.

  • Click Launch instance again from the EC2 dashboard (or click Launch more instances from the success page).
  • Under Name and tags, enter AppServer.
  • Confirm the same settings: Amazon Linux 2023 AMI, t2.micro, no key pair, default network, and CloudWatchFleetRole under Advanced details > IAM instance profile.
  • Click Launch instance.
  • Repeat one more time with the name DatabaseServer and the same settings.
  • Click Launch instance.
  • Navigate to the Instances page using the left sidebar.
  • Wait until all three instances (WebServer, AppServer, DatabaseServer) show Running in the Instance state column.

This takes about 30 seconds. You can click the refresh icon to update the table.

Why Amazon Linux 2023?

Amazon Linux 2023 comes with the Systems Manager agent pre-installed. This means your instances can register with Systems Manager immediately after launch without any extra setup.

Verify your fleet in Systems Manager Fleet Manager

All three instances are running, but can Systems Manager actually reach them? Fleet Manager shows you which instances have successfully registered as managed nodes.

Before you check, predict: do you think all three instances will appear immediately, or will there be a delay?

  • In the console search bar, type Systems Manager and select Systems Manager.
  • In the left navigation pane, click Fleet Manager (under Node Management).
  • Look for your three instances in the managed nodes list.

All three instances should appear within 2-3 minutes of launching. If you do not see all three yet, wait a moment and click the refresh button.

Instances not appearing in Fleet Manager?

Give it up to 5 minutes. The SSM agent needs time to register after the instance boots.

If an instance still does not appear after 5 minutes, return to the EC2 console and verify that the instance has CloudWatchFleetRole listed under its IAM Role column. An instance without the correct role cannot register with Systems Manager.

Help me troubleshoot why my EC2 instance is not appearing in Systems Manager Fleet Manager as a managed node.

Your fleet is alive and reachable. Next up, you will explore what CloudWatch already knows about these instances and discover the gap that basic monitoring leaves.

Explore Default CloudWatch Metrics and Hit the Gap

Your fleet is running and reporting to Systems Manager. Now you need to answer a fundamental question: what does AWS actually tell you about the health of these instances?

Before installing anything extra, you are going to explore what CloudWatch gives you for free out of the box. You might assume AWS tracks everything important. Let's test that assumption.

In this step, get ready to:
  • Explore the default EC2 metrics available in CloudWatch.
  • Search for memory and disk usage metrics.
  • Identify the monitoring gap that the CloudWatch agent solves.
Browse default EC2 metrics in CloudWatch

CloudWatch automatically collects metrics from every running EC2 instance. These come from the hypervisor, the layer that sits between AWS hardware and your virtual machine.

  • Open the CloudWatch console at https://console.aws.amazon.com/cloudwatch/.
  • In the navigation pane on the left, click Metrics, then All metrics.
  • Under the Browse tab, select the EC2 namespace.
  • Click Per-Instance Metrics.

You should see a table listing metrics for all three of your instances. Look for metric names like CPUUtilization, NetworkIn, NetworkOut, DiskReadOps, and DiskWriteOps.

  • In the search field above the table, type CPUUtilization and press Enter.
  • Confirm you see a CPUUtilization row for each of your three instances (WebServer, AppServer, DatabaseServer).
  • Select the checkbox next to all three CPUUtilization rows to graph them.

You should see a graph appear at the top with three lines, one per instance. All three are likely near zero because the instances are idle.

What are these default metrics?

These metrics come from the EC2 hypervisor, the virtualization layer that manages your instance from the outside. The hypervisor can see how much CPU time your instance uses, how much network traffic flows in and out, and how many disk read/write operations occur.

With basic monitoring (the free default), these data points arrive every 5 minutes.

Search for memory and disk metrics

You confirmed CPU and network metrics exist. Now think about what else you would want to know if you were running a production fleet.

Before you search, consider this: do you think CloudWatch already tracks how much memory your instances are using?

  • Clear the search field in the Per-Instance Metrics view.
  • Type mem in the search field and press Enter.

The table shows no results. There is no memory metric in the AWS/EC2 namespace.

  • Clear the search field again.
  • Type disk_used_percent and press Enter.

Again, nothing. There is no disk space percentage metric either.

Why are these metrics missing?

The hypervisor sits outside your instance. It can measure CPU cycles consumed and network packets transferred because those flow through the virtualization layer. Memory usage and disk space percentage, however, live inside the operating system. The hypervisor has no visibility into them.

This is a fundamental architectural boundary. AWS cannot report what it cannot see.

Understand the monitoring gap

You have now hit the gap that every AWS team encounters when they first set up monitoring.

  • Think about your DatabaseServer. If it runs out of memory, will CloudWatch alert you with the default metrics? No.
  • Think about your AppServer. If its disk fills up completely, will you get a warning from CloudWatch? No.
  • The only way to get memory and disk metrics into CloudWatch is to run something inside the instance that collects and publishes them.

That something is the CloudWatch agent. It runs inside each instance, reads OS-level statistics, and sends them to CloudWatch as custom metrics.

What is the CloudWatch agent?

The CloudWatch agent is a lightweight process that runs inside your EC2 instance. It collects operating system metrics like memory usage, disk space, and process counts, then publishes them to CloudWatch under a custom namespace called CWAgent.

You will install it on all three instances simultaneously in the next step using Systems Manager Run Command.

Not seeing any metrics for your instances?

Metrics can take 5-10 minutes to appear after an instance launches. If the table is empty, wait a few minutes and refresh the page.

If you still see nothing, confirm your instances are in the Running state in the EC2 console. Stopped or terminated instances do not publish metrics.

Help me troubleshoot missing CloudWatch metrics for my EC2 instances.

You now know exactly what CloudWatch can and cannot see. Default metrics cover what the hypervisor observes from the outside. Memory and disk space live inside the OS, invisible to CloudWatch until you install the agent. In the next step, you will close that gap by installing the CloudWatch agent on all three instances at once.

Install the CloudWatch Agent and Unlock Custom Metrics

In the previous step, you discovered that default CloudWatch metrics have a major blind spot. Memory usage and disk space percentage are completely invisible because those metrics live inside the operating system, beyond what the hypervisor can see.

The CloudWatch agent closes that gap. It runs inside each instance and reports OS-level data back to CloudWatch. In this step, you will install and configure the agent across all three instances simultaneously using Systems Manager Run Command. No SSH required.

In this step, get ready to:
  • Store a CloudWatch agent configuration in Parameter Store.
  • Install the CloudWatch agent on all three instances via Run Command.
  • Start the agent and verify custom metrics appear in the CWAgent namespace.
Store the agent configuration in Parameter Store

Before installing the agent, you need to tell it what to collect. The CloudWatch agent reads its instructions from a JSON configuration file. By storing this config in Systems Manager Parameter Store, you can apply the same configuration to your entire fleet in one command.

  • Return to the Systems Manager console from earlier.
  • In the left navigation pane, expand Application Management, then select Parameter Store.
  • Click Create parameter.
  • In the Name box, enter AmazonCloudWatch-FleetConfig.
  • Leave Description empty or type a short note like Fleet monitoring config.
  • For Parameter tier, select Standard.
  • For Type, select String.
  • For Data type, keep the default text.
  • In the Value box, paste the following JSON configuration:
{
  "agent": {
    "metrics_collection_interval": 60
  },
  "metrics": {
    "namespace": "CWAgent",
    "metrics_collected": {
      "cpu": {
        "resources": ["*"],
        "measurement": ["cpu_usage_idle"],
        "totalcpu": true
      },
      "disk": {
        "resources": ["*"],
        "measurement": ["used_percent"]
      },
      "mem": {
        "measurement": ["used_percent"]
      }
    },
    "append_dimensions": {
      "InstanceId": "${aws:InstanceId}"
    }
  }
}

What does this configuration do?

  • metrics_collection_interval sets the agent to collect data every 60 seconds.
  • cpu with cpu_usage_idle reports how much CPU is free. When this drops, the instance is under load.
  • disk with used_percent reports the percentage of disk space used (becomes disk_used_percent in CloudWatch).
  • mem with used_percent reports the percentage of memory in use (becomes mem_used_percent in CloudWatch).
  • append_dimensions attaches the instance ID to every metric so you can tell which server each data point belongs to.
  • Click Create parameter.

You should see a green success banner confirming the parameter was created.

Don't see a success message?

  • Make sure the JSON is valid. A missing comma or extra bracket will cause a silent failure. Copy the JSON exactly as shown above.
  • Confirm you are in the same Region where your EC2 instances are running.

Help me troubleshoot my Parameter Store creation

Install the CloudWatch agent on all three instances

With the configuration stored, you can now push the agent to your entire fleet in a single action. Systems Manager Run Command sends the install instruction to all three instances simultaneously.

  • In the Systems Manager navigation pane, select Run Command.
  • Click Run command.
  • In the Command document search box, type AWS-ConfigureAWSPackage and select it from the list.
  • In the Action dropdown, choose Install.
  • In the Name field, enter AmazonCloudWatchAgent.
  • Keep Version set to latest.
  • Scroll down to the Targets section.
  • Select Choose instances manually, then check the boxes next to all three instances (WebServer, AppServer, DatabaseServer).
  • Scroll to the bottom and click Run.

The command status page appears. Wait until the Overall status shows Success for all three targets. This typically takes 30-60 seconds.

Why Run Command instead of SSH?

Run Command is the fleet management pattern. Instead of opening SSH sessions to each server one at a time, you send a single instruction that Systems Manager delivers to every target. This approach scales to hundreds of instances with no additional effort.

Seeing a failed status?

  • Click the instance name in the Targets and outputs section, then choose View output to see the error details.
  • If you see "no latest version found for package AmazonCloudWatchAgent on platform linux", your SSM Agent may need updating. Amazon Linux 2023 ships with a recent version, so this is uncommon.
  • Confirm your instances have the CloudWatchFleetRole IAM role attached (set up in Step 1).

Help me fix my Run Command failure

Start the agent and verify custom metrics appear

The agent is installed but not running yet. You need to start it and point it at the configuration you stored in Parameter Store.

  • In the Systems Manager navigation pane, select Run Command again.
  • Click Run command.
  • In the Command document search box, type AmazonCloudWatch-ManageAgent and select it.
  • In the Action dropdown, choose configure.
  • In the Optional Configuration Source dropdown, choose ssm.
  • In the Optional Configuration Location field, enter AmazonCloudWatch-FleetConfig.
  • In the Optional Restart dropdown, choose yes.
  • Scroll down to the Targets section.
  • Select Choose instances manually and check all three instances again.
  • Scroll to the bottom and click Run.

Wait for Overall status to show Success for all three targets.

What just happened?

The AmazonCloudWatch-ManageAgent document told the agent on each instance to fetch the JSON config from Parameter Store and start collecting. Within 2-3 minutes, each instance begins pushing mem_used_percent, disk_used_percent, and cpu_usage_idle to the CWAgent namespace in CloudWatch.

Before you check CloudWatch, what do you expect to find in the CWAgent namespace? Think about which metrics should appear and how many instances should be reporting.

  • Open the CloudWatch console.
  • In the left navigation, select All metrics.
  • Under Custom namespaces, look for CWAgent. Click on it.
  • Browse the metric dimensions. You should see mem_used_percent and disk_used_percent listed for all three instances.

Metrics take 2-3 minutes to appear

If you do not see CWAgent in the namespace list yet, wait a couple of minutes and refresh the page. The agent collects at 60-second intervals, and there is a short delay before the first data points reach CloudWatch.

Still no CWAgent namespace after 5 minutes?

  • Go back to Systems Manager Run Command history and confirm both commands (install and configure) show Success for all three instances.
  • Verify you entered AmazonCloudWatch-FleetConfig (not a typo) in the Optional Configuration Location field.
  • Confirm your instances have the CloudWatchAgentServerPolicy attached via the CloudWatchFleetRole IAM role. Without this policy, the agent cannot publish metrics.

Help me troubleshoot missing CWAgent metrics

Your fleet now has full OS-level visibility. You can see exactly how much memory and disk each instance is consuming. Next up, you will build a unified dashboard that puts all three instances side by side so you can spot the outlier at a glance.

Build a Unified Fleet Dashboard

Your three instances are now reporting memory, disk, and CPU data to CloudWatch. The next step is to bring all of that data together into a single view.

Right now, checking on your fleet means opening each instance's metrics page one at a time. A unified dashboard puts all three instances on one screen so you can instantly spot which server is the outlier. If two instances are flat and one spikes, you know exactly where to look.

In this step, get ready to:
  • Create a CloudWatch dashboard named FleetHealth with a CPU utilization widget.
  • Add memory and disk usage widgets from the CWAgent namespace.
  • Arrange and save the dashboard for fleet-wide visibility.
Create the FleetHealth dashboard and add a CPU widget

The first widget on your dashboard will show CPU utilization across all three instances on a single graph. You will create the dashboard and configure this widget in one flow.

  • In the AWS Management Console search bar, type CloudWatch and select CloudWatch from the results.
  • In the left navigation pane, click Dashboards.
  • Click Create dashboard.
  • Enter FleetHealth in the Dashboard name field.
  • Click Create dashboard.

An Add to this dashboard dialog box appears, prompting you to choose your first widget type.

  • Select Line as the widget type.
  • Click Configure.
  • In the Browse tab, click EC2 under the AWS namespaces.
  • Click Per-Instance Metrics.
  • Type CPUUtilization in the search field to filter the list.
  • Select the checkbox next to CPUUtilization for each of your three instances (WebServer, AppServer, DatabaseServer).

Identifying your instances

The metrics list shows instance IDs rather than names. If you only have three instances in this account, you can select all three CPUUtilization rows. If you have other instances, cross-reference the instance IDs with the EC2 console.

  • Click the Graphed metrics tab above the metric list.
  • Change the Period dropdown to 1 Minute for all three metrics.
  • Click Create widget.

A line graph appears on your dashboard showing three colour-coded lines. Each line represents one instance's CPU usage over time.

Why set the period to 1 minute?

The period controls how CloudWatch aggregates data points on the graph. A 1-minute period gives you the most granular view possible. Your CWAgent metrics arrive every 60 seconds, so this matches the collection interval perfectly.

For the EC2 namespace, basic monitoring publishes CPUUtilization every 5 minutes. The graph still works at 1-minute period. You will simply see data points spaced 5 minutes apart on that widget.

Don't see three lines on the graph?

Make sure you selected CPUUtilization for all three instances, not just one. Click the widget title to edit it and check the Graphed metrics tab. You should see three rows listed.

If you see no data at all, confirm your instances are running in the same region as the one selected in the console header.

help me troubleshoot why my CloudWatch dashboard widget is not showing data for my EC2 instances

Add memory and disk widgets

Now you will add two more widgets that pull from the CWAgent namespace. These show the OS-level metrics your CloudWatch agent is collecting.

  • Click the + symbol at the top of your dashboard to add a new widget.
  • Select Line as the widget type.
  • Click Next.
  • Choose Metrics.
  • In the Browse tab, click CWAgent under the custom namespaces.
  • Search for mem_used_percent and select the checkbox for all three instances.
  • Click Create widget.

A second line graph appears showing memory usage across your fleet. You should see three lines at varying percentages.

  • Click the + symbol again to add a third widget.
  • Select Line and click Next.
  • Choose Metrics.
  • In the Browse tab, click CWAgent again.
  • Search for disk_used_percent and select the checkbox for all three instances.
  • Click Create widget.

Your dashboard now has three widgets. Each shows a different health metric with all three instances represented as separate lines.

What do these metrics tell you?

mem_used_percent shows how much of each instance's RAM is in use. A line creeping toward 100% means that instance is running out of memory.

disk_used_percent shows how full each instance's root volume is. If a server fills its disk, it can crash or stop writing logs. Seeing this metric for all three instances side-by-side lets you catch storage problems early.

Arrange the widgets and save the dashboard

Arranging widgets in a consistent order makes the dashboard scannable at a glance. You will stack them vertically so CPU is always on top, memory in the middle, and disk on the bottom.

  • Drag the CPU widget to the top row of the dashboard.
  • Drag the memory widget (mem_used_percent) to the middle row, below CPU.
  • Drag the disk widget (disk_used_percent) to the bottom row.
  • Click Save dashboard in the upper right corner.

Resize for clarity

You can drag the lower-right corner of any widget to resize it. Making widgets wider gives you a better view of trends over time. Consistent sizing across all three widgets keeps the dashboard easy to scan.

Before you look at the finished dashboard, what do you expect to see across the three widgets? Think about whether the lines for all three instances should look similar or different right now.

Look at your saved FleetHealth dashboard. You see three stacked line widgets, each showing three colour-coded lines. CPU is on top, memory is in the middle, and disk is on the bottom. Data points update every 60 seconds as your CloudWatch agent reports new values.

What should I see?

All three instances are idle right now, so you should see relatively flat, low lines across the CPU widget. The memory and disk widgets may show slightly different values for each instance because each has its own set of running processes, but the lines should be stable.

The key point is that all three instances are visible on the same graph. If one instance were struggling, its line would stand out immediately against the other two.

Widgets showing "No data" or missing lines?

If a CWAgent widget shows no data, confirm the CloudWatch agent is still running on all three instances. Return to Systems Manager and check the Run Command history from the previous step.

If only one or two lines appear, you may have missed selecting an instance during metric selection. Click the widget title to edit it and add the missing instance.

help me debug why my CloudWatch dashboard is not showing CWAgent metrics for all three instances

Your fleet now has a single pane of glass. You can see CPU, memory, and disk for all three instances at a glance. Next up, you will create an alarm that notifies you by email the moment one of these instances crosses a threshold. No more watching the dashboard and hoping you catch a spike.

Create an Alarm with SNS Notifications and Trigger It

Your FleetHealth dashboard gives you a live view of all three instances. But a dashboard only helps if someone is actively watching it.

In this step, you will close that gap by creating an alarm that proactively notifies you when something goes wrong. You will wire up an email notification, then deliberately stress one instance to prove the full pipeline works end-to-end.

In this step, get ready to:
  • Create an SNS topic and subscribe your email for notifications.
  • Create a CloudWatch alarm that fires when CPU exceeds 70%.
  • Stress-test WebServer and watch the alarm fire in real time.
Create an SNS topic and subscribe your email

Before CloudWatch can send you a notification, it needs somewhere to send it. Amazon SNS acts as the messaging layer between CloudWatch and your inbox.

  • In the AWS Management Console, search for SNS and open the Simple Notification Service console.
  • In the left navigation pane, click Topics.
  • Click Create topic.
  • For Type, select Standard.
  • For Name, enter FleetAlerts.
  • Scroll to the bottom and click Create topic.

You should see the FleetAlerts topic page with its ARN displayed in the Details section.

What is an SNS topic?

An SNS topic is a channel that accepts messages and fans them out to all subscribers. Think of it as a group chat where CloudWatch posts alerts and everyone subscribed receives a copy.

Now subscribe your email so you actually receive the alerts.

  • On the FleetAlerts topic page, click Create subscription.
  • For Protocol, select Email.
  • For Endpoint, enter your personal email address.
  • Click Create subscription.

Why do I need to confirm the subscription?

AWS requires confirmation to prevent someone from subscribing your email without your consent. Until you click the confirmation link, the subscription stays in a Pending state and will not receive any messages.

  • Open your email inbox and look for a message from AWS Notifications.
  • Click the Confirm subscription link inside the email.
  • Return to the SNS console and refresh the Subscriptions tab on your FleetAlerts topic page.

The subscription status should now show Confirmed. Your email is ready to receive alarm notifications.

Don't see the confirmation email?

  • Check your spam or junk folder. The sender is typically no-reply@sns.amazonaws.com.
  • Double-check you entered the correct email address. If not, delete the subscription and create a new one.
  • Wait 2-3 minutes. The email can take a moment to arrive.

Why isn't my SNS subscription confirmation arriving?

Create a CloudWatch alarm on WebServer CPU

With the notification channel ready, you can now create an alarm that watches one specific metric and triggers when it crosses a threshold.

  • Navigate to the CloudWatch console.
  • In the left navigation pane, click Alarms, then All alarms.
  • Click Create alarm.
  • Click Select metric.
  • In the All metrics tab, click EC2, then Per-Instance Metrics.
  • Find the row where the InstanceId column matches your WebServer instance and the Metric Name column shows CPUUtilization.
  • Select the checkbox next to that row, then click Select metric.

Find your WebServer instance ID quickly

If you are unsure which instance ID belongs to WebServer, open the EC2 console in a new tab and check the Name column next to each instance ID. Copy the WebServer ID, then paste it into the search box on the CloudWatch metric selection page.

You should now be on the Specify metric and conditions page.

  • For Statistic, select Average.
  • For Period, select 1 minute.
  • Under Conditions, for Threshold type, choose Static.
  • For Whenever CPUUtilization is, select Greater.
  • Under than..., enter 70.
  • Click Additional configuration. For Datapoints to alarm, set both values to 1 out of 1.
  • Click Next.

What does 1 out of 1 datapoints mean?

This means the alarm triggers after just one 1-minute period of CPU above 70%. In production you might set 3 out of 5 to avoid false alarms from short spikes. For this project, 1 out of 1 makes the alarm trigger quickly so you can see it in action.

You are now on the Configure actions page.

  • Under Notification, confirm that In alarm is selected.
  • In the SNS topic dropdown, select your FleetAlerts topic.
  • Click Next.
  • For the alarm name, enter WebServer-CPUUtilization-High.
  • Click Next.
  • On the Preview and create page, review your settings and click Create alarm.

The alarm is created. Its initial state will show Insufficient data for a minute or two while CloudWatch collects its first evaluation period. After 1-2 minutes it should transition to OK (since CPU is well below 70% right now).

Alarm stuck on Insufficient data?

  • Wait 2-3 minutes. The alarm needs at least one full period of data before it can evaluate.
  • Make sure you selected the correct instance ID during metric selection. If the instance does not match, no data flows to the alarm.
  • Verify the alarm period is set to 1 minute, not 5 minutes. A 5-minute period takes longer to produce its first evaluation.

My CloudWatch alarm is stuck in Insufficient data state and will not change to OK. How do I fix this?

Stress-test WebServer and watch the alarm fire

The alarm is watching and your email is subscribed. Now you will deliberately spike the WebServer's CPU to prove the entire notification pipeline works.

  • Navigate to the Systems Manager console.
  • In the left navigation pane, click Session Manager.
  • Click Start session.
  • Select the WebServer instance from the list and click Start session.

A terminal session opens in your browser, connected directly to the WebServer instance.

Before you run the stress command, think about what you expect to happen. Do you think the alarm will fire immediately, or will there be a delay?

  • Spike the CPU by running this command in the Session Manager terminal:
# Spawn a process that consumes 100% of one CPU core
yes > /dev/null &

What does this command do?

The yes command outputs an endless stream of characters. Redirecting it to /dev/null discards the output but keeps the CPU busy processing. The & sends it to the background so you keep control of the terminal.

On a t2.micro with 1 vCPU, this single process saturates the entire CPU, pushing utilization well above 70%.

Now wait 3-5 minutes for CloudWatch to evaluate the new data. While you wait, monitor the alarm.

  • Switch back to the CloudWatch console.
  • Navigate to Alarms, then All alarms.
  • Watch the WebServer-CPUUtilization-High alarm. Within 3-5 minutes, the state should change from OK to In alarm.
  • Check your email inbox. You should receive a notification from FleetAlerts confirming the alarm triggered.

Now open your dashboard to see the fleet-wide picture.

  • In the CloudWatch console, click Dashboards in the left navigation pane.
  • Open FleetHealth.

On the CPU widget, you should see the WebServer line spiking sharply while the AppServer and DatabaseServer lines remain flat near zero. This is exactly the power of a unified dashboard. You can instantly identify the outlier without checking each instance one by one.

  • Return to the Session Manager terminal and stop the stress process by running:
# Kill all background yes processes
kill %1

Why stop the stress test?

Leaving the process running would keep your CPU pegged at 100%, which drains your t2.micro CPU credits. Killing it lets the instance return to normal. Within a few minutes, the alarm will transition back from In alarm to OK.

  • Click Terminate in the Session Manager window to close the session.

Alarm not transitioning to In alarm?

  • Confirm you ran the yes > /dev/null & command on the WebServer instance, not AppServer or DatabaseServer.
  • Wait at least 3-5 minutes. The alarm period is 1 minute, but CloudWatch can take 1-2 additional minutes to aggregate and evaluate.
  • Open the alarm and check the History tab to see if state transitions are occurring.
  • If the alarm shows the correct instance ID but no spike, the yes process may have been terminated. Reconnect via Session Manager and re-run it.

My CloudWatch alarm is not transitioning to In alarm even though I ran the stress test. Help me troubleshoot.

You now have a fully operational monitoring pipeline. The dashboard gives you the big picture at a glance. The alarm reaches out and taps you on the shoulder the moment something goes wrong. Next up, you will extend this monitoring to work across multiple AWS accounts.

Secret mission

Configure Cross-Account Observability

You have mastered single-account fleet monitoring. In the real world, teams operate across multiple AWS accounts for dev, staging, and production. Configure your account as a CloudWatch monitoring account with an OAM sink, so it is ready to receive metrics from other accounts the moment you create them.

Clean Up Your Resources

Clean Up Your Resources

This project runs on AWS free tier resources, but your three EC2 instances consume your 750 free hours while running. Three instances running simultaneously use 3 hours of your monthly allowance per clock hour.

Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Cost warning

If you leave all three instances running 24/7, they will consume your entire 750 free tier hours in about 10 days. Stop or terminate them when you are finished experimenting to avoid unexpected charges.

Resources you used:

  • 3 EC2 t2.micro instances (WebServer, AppServer, DatabaseServer).
  • 1 CloudWatch dashboard (FleetHealth).
  • 1 CloudWatch alarm (WebServer-CPUUtilization-High).
  • 1 SNS topic (FleetAlerts) with email subscription.
  • 1 IAM role (CloudWatchFleetRole).
  • 1 Systems Manager parameter (AmazonCloudWatch-FleetConfig).
  • 1 OAM sink (FleetMonitoringSink).

Keep everything running

No action needed. Choose this if you are still actively building or want to continue experimenting with your fleet monitoring setup.

  • Your three instances will keep consuming free tier hours while running.
  • Monitor your free tier usage in the AWS Billing console under Free Tier to avoid surprise charges.
  • Your dashboard, alarm, and SNS topic remain active and functional.

Pause - I'll come back to this later

Shut down running instances to stop consuming free tier compute hours. Your dashboard, alarm, and configuration remain intact but will show no data until you restart.

  • In the EC2 console, select all three instances (WebServer, AppServer, DatabaseServer).
  • Click Instance state, then click Stop instance.
  • Confirm the stop action.
  • Your instances will not consume compute hours while stopped.
  • Restart anytime by selecting the instances and choosing Instance state then Start instance.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow each step below to fully clean up your account.

Terminate EC2 instances:

  • In the EC2 console, select all three instances (WebServer, AppServer, DatabaseServer).
  • Click Instance state, then click Terminate instance.
  • Confirm the termination.

Delete the CloudWatch dashboard:

  • In the CloudWatch console, navigate to Dashboards.
  • Select FleetHealth, then click Delete.
  • Confirm the deletion.

Delete the CloudWatch alarm:

  • In the CloudWatch console, navigate to Alarms, then All Alarms.
  • Select the checkbox next to WebServer-CPUUtilization-High.
  • Click Actions, then Delete.
  • Confirm by clicking Delete.

Delete the SNS topic:

  • In the SNS console, navigate to Topics.
  • Select FleetAlerts, then click Delete.
  • Type delete me in the confirmation field, then click Delete.

Delete the IAM role:

  • In the IAM console, navigate to Roles.
  • Search for CloudWatchFleetRole.
  • Select it, then click Delete.
  • Type the role name to confirm, then click Delete.

Delete the Parameter Store entry:

  • In the Systems Manager console, navigate to Parameter Store.
  • Select AmazonCloudWatch-FleetConfig.
  • Click Delete and confirm.

Delete the OAM sink:

  • In your terminal, run the following command using the sink ARN you documented earlier:
aws oam delete-sink --identifier [[SINK_ARN="your FleetMonitoringSink ARN"]]

This command produces no output on success. You have now removed all project resources from your account.

Nice Work!

Nice Work!

You just built a production-grade fleet monitoring system using Amazon CloudWatch. Three EC2 instances, one unified dashboard, and an alarm that proves itself the moment something goes wrong.

You've learned how to:

  • Discovered the blind spot in default EC2 monitoring (no memory or disk metrics) and closed it by installing the CloudWatch agent across all three instances simultaneously using Systems Manager Run Command.
  • Built a unified CloudWatch dashboard that shows all three instances side-by-side for instant fleet-wide visibility and outlier detection.
  • Created a CloudWatch alarm with SNS email notification and proved it works end-to-end with a live stress test, clearly seeing one instance spike while the others stayed healthy.
  • Secret Mission: Configured your account as a CloudWatch monitoring account with an OAM sink, ready to receive cross-account metrics from future AWS accounts.

Ready to quiz yourself?