AWS

EC2에 CloudWatch 연동

Seongmin 2025. 5. 6. 22:09
반응형

EC2 + CloudWatch

 

모니터링은 안정적인 인프라 운영에 매우 중요한 부분입니다. 서비스에 문제가 발생하면 사용자는 서비스를 이용할 수 없게 되고, 그 영향이 연관된 다른 서비스로 번지며 더 큰 장애로 이어질 수 있습니다. 더 나아가, 발생한 문제를 수습하는 데는 많은 시간과 비용이 들기 때문에 사후 대응보다는 사전 탐지와 예방이 훨씬 중요합니다. 이를 위해 우리는 모니터링을 통해 시스템의 상태를 지속적으로 관찰하고, 문제가 발생하기 전의 이상 징후를 빠르게 파악하여 미리 대응할 수 있어야 합니다.

이번 글에서는 AWS에서 EC2 인스턴스를 모니터링하기 위해 CloudWatch Agent를 설정하는 방법과, 수집된 데이터를 바탕으로 CloudWatch 대시보드를 구성하는 방법에 대해 단계별로 설명합니다.

 

1. CloudWatch

CloudWatch는 EC2, RDS, Lambda 등 각종 리소스의 상태를 확인하고 지표를 수집하며, 수집된 데이터를 시각화하거나 일정 조건에 따라 알림을 전송하는 등 다양한 기능을 수행합니다. EC2 인스턴스를 생성하면, CloudWatch는 별도의 설정 없이 자동으로 기본적인 지표를 수집합니다. 아래는 수집되는 대표적인 지표 목록입니다.

  1. CPUUtilization
    • 인스턴스의 CPU 사용량을 의미합니다.
    • 인스턴스의 과부하 상태를 판단할 때 주로 사용합니다.
  2. NetworkIn / NetworkOut
    • 네트워크를 통해 수신하거나 전송한 바이트 수를 의미합니다.
    • 트래픽 급증이나 급감을 감지할 때 유용합니다.
  3. NetworkPacketsIn / NetworkPacketsOut
    • 인스턴스가 처리하는 네트워크 패킷의 수를 의미합니다.
    • 비정상적 트래픽이나 공격 등을 파악할 때 유용합니다.
  4. DiskReadOps / DiskWriteOps
    • 인스턴스의 EBS 볼륨에서 이루어지는 읽기/쓰기 작업 횟수를 의미합니다.
    • 디스크의 부하와 성능 상태를 파악할 때 사용합니다.
  5. DiskReadBytes / DiskWriteBytes
    • 인스턴스가 EBS 볼륨에서 읽거나 쓴 바이트 수를 의미합니다.
    • 특정 디스크 작업이 성능에 영향을 주는지 확인할 수 있습니다.

위와 같이 기본적인 지표들은 CloudWatch에서 자동으로 수집하지만, 메모리 사용률, 디스크 사용률, 스왑 사용률 등 기본적으로 수집되지 않지만 중요한 지표들이 존재합니다.

 

2. CloudWatch Agent

CloudWatch Agent는 EC2 인스턴스 내부에 설치하여 사용하는 모니터링 도구로, 인스턴스의 운영 체제로부터 직접 메모리 사용률, 디스크 사용률, 프로세스별 리소스 사용 현황 등 기본적인 CloudWatch 지표로는 확인할 수 없었던 더 깊고 다양한 추가 지표를 수집하여 CloudWatch로 전송할 수 있습니다.

  1. 메모리 사용량
    • 메모리 사용량이 갑작스럽게 급증하면 시스템 병목이 발생할 수 있고, 처음엔 눈에 띄지 않더라도 지속적인 메모리 증가로 인해 문제가 발생할 수 있기 때문에 모니터링이 필요합니다.
  2. 디스크 사용량
    • 디스크 공간이 부족하면 애플리케이션 로그가 유실되거나, 스왑 공간을 사용할 수 없어 시스템에 문제가 발생할 수 있기 때문에 모니터링이 필요합니다.
  3. 스왑 사용량
    • 메모리 부족으로 인해 디스크를 메모리처럼 임시로 사용하는 것을 의미합니다.
    • 스왑 사용량이 증가하는 것은 메모리가 부족하다는 신호이기 때문에 메모리 사용량과 함께 모니터링할 필요가 있습니다.
  4. 프로세스별 리소스 사용량
    • 개별 프로세스가 사용하는 CPU와 메모리 자원을 프로세스 단위로 측정합니다.
    • 특정 프로세스가 과도하게 CPU 또는 메모리 자원을 점유하면 서비스 전체의 성능 저하가 발생할 수 있으므르, 정확한 원인을 파악하기 위해서 모니터링이 필요합니다.
  5. 시스템 및 애플리케이션 로그
    • 인스턴스 내부의 시스템 및 애플리케이션 로그를 CloudWatch Logs로 전송합니다.
    • 로그는 에러나 장애의 원인을 파악할 수 있는 가장 기본적인 수단입니다. 인스턴스 내에서 실행한 프로세스의 로그는 기본적으로 CloudWatch에서 확인할 수 없기 때문에, CloudWatch Agent를 통해 CloudWatch로 전송해야 합니다.

 

3. EC2에 CloudWatch Agent 설치하고 설정하기

먼저 인스턴스를 하나 생성합니다. 저는 간단하게 인스턴스 타입은 t2.micro, OS는 Ubuntu를 선택해 생성했습니다. 인스턴스가 생성되었다면 CloudWatch Agent를 설치하기 전에 CloudWatch 대시보드에서 어떠한 지표들이 보이는지 확인할 수 있습니다.

 

CloudWatch 대시보드에 접속하여 위젯 추가를 클릭하면 아래와 같이 “EC2” 지표가 있습니다. 여기에서 기본적으로 제공하는 지표들을 확인할 수 있습니다.

CloudWatch 대시보드
CloudWatch 대시보드

CloudWatch Agent 설치

이제 EC2 인스턴스에 접속하여 CloudWatch Agent를 설치합니다. OS별로 링크와 설치 방법이 다를 수 있기 때문에 공식 문서를 확인하는 것을 권장합니다.

$ wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
$ sudo dpkg -i -E amazon-cloudwatch-agent.deb

 

CloudWatch Agent를 설정하기 전에 EC2에 CloudWatch 관련 권한을 부여해야 합니다. IAM에 접속하여 아래의 권한을 포함한 역할을 생성합니다.

  • CloudWatchAgentServerPolicy : CloudWatch Agent가 수집한 지표와 로그를 CloudWatch에 전송하기 위한 권한입니다.
  • CloudWatchLogsFullAccess : CloudWatch Logs에 그룹을 생성하고 전송하기 위한 권한입니다.
  • AmazonSSMFullAccess : CloudWatch Agent의 구성 파일을 SSM Parameter Store에 저장하고 가져오기 위해 필요한 권한입니다.

생성한 역할을 EC2 인스턴스에 연결합니다.

  1. 인스턴스를 선택하고 작업 → 보안 → IAM 역할 수정을 클릭합니다.
  2. 위에서 생성한 역할을 선택하고 IAM 역할 업데이트를 클릭합니다.

CloudWatch Agent 설정 파일 생성

다시 EC2 인스턴스에 접속하여 CloudWatch Agent를 설정합니다. 설정 파일은 직접 JSON 형식으로 직접 작성할 수도 있지만, 대화형으로 설정을 만들어주는 방법도 지원합니다. 여기서는 대화형 방식으로 설정 파일을 생성해보겠습니다.

 

아래 명령어를 실행하면 설정 마법사가 실행되며, 필요한 항목들을 단계별로 선택하여 설정 파일을 생성할 수 있습니다.

sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
...
On which OS are you planning to use the agent?
1. linux
2. windows
3. darwin
default choice: [1]:
1 # Ubuntu이기 때문에 linux를 선택합니다.

Trying to fetch the default region based on ec2 metadata...
I! imds retry client will retry 1 times
Are you using EC2 or On-Premises hosts?
1. EC2
2. On-Premises
default choice: [1]:
1 # 인스턴스가 AWS 리소스인지 아닌지를 구분하기 위한 단계입니다. 여기서 EC2를 선택합니다.

Which user are you planning to run the agent?
1. cwagent
2. root
3. others
default choice: [1]:
1 # CloudWatch Agent가 어떤 사용자 권한으로 실행될지를 묻는 단계입니다. 여기서 cwagent를 선택합니다.

Do you want to turn on StatsD daemon?
1. yes
2. no
default choice: [1]:
2 # StatsD는 응답 시간, 에러 횟수 등 애플리케이션에서 정의한 커스텀 지표를 수집할 수 있는 도구입니다. 여기서는 사용하지 않겠습니다.

Do you want to monitor metrics from CollectD? WARNING: CollectD must be installed or the Agent will fail to start
1. yes
2. no
default choice: [1]:
2 # CollectD는 Nginx, Redis, Apache 등 더 다양한 애플리케이션 지표까지 확장해서 수집할 수 있는 도구입니다. 여기서는 사용하지 않겠습니다.

Do you want to monitor any host metrics? e.g. CPU, memory, etc.
1. yes
2. no
default choice: [1]:
1 # CPU, 메모리, 디스크 등의 지표를 수집할 것인지 묻는 단계입니다. CloudWatch Agent를 사용하는 목적이 이것이기 때문에 yes를 선택합니다.

Do you want to monitor cpu metrics per core?
1. yes
2. no
default choice: [1]:
1 # CPU 지표를 코어별로 세분화해서 볼지를 선택하는 단계입니다.

Do you want to add ec2 dimensions (ImageId, InstanceId, InstanceType, AutoScalingGroupName) into all of your metrics if the info is available?
1. yes
2. no
default choice: [1]:
1 # 수집하는 모든 지표에 EC2의 메타데이터를 추가할지 묻는 단계입니다. 인스턴스를 식별해야 하므로 yes를 선택합니다.

Do you want to aggregate ec2 dimensions (InstanceId)?
1. yes
2. no
default choice: [1]:
1 # 지표를 인스턴스 ID를 기준으로 묶어서 보낼지 묻는 단계입니다. 인스턴스별로 필터링하기 위해서 yes를 선택합니다.

Would you like to collect your metrics at high resolution (sub-minute resolution)? This enables sub-minute resolution for all metrics, but you can customize for specific metrics in the output json file.
1. 1s
2. 10s
3. 30s
4. 60s
default choice: [4]:
4 # 지표를 얼마나 자주 수집해서 전송할지를 묻는 단계입니다.

Which default metrics config do you want?
1. Basic # CPU, 메모리, 디스크 사용률 등
2. Standard # + 디스크 I/O, 네트워크 I/O, 스왑 등
3. Advanced # + 프로세스 수, 세부 디스크/네트워크 정보 등
4. None # 모든 항목을 수동 설정해야 함 (커스텀 목적용)
default choice: [1]:
1 # 어떤 지표를 수집할지 AWS에서 제공하는 미리 정의된 세트 중 하나를 선택하는 단계입니다. 여기서는 Basic으로도 충분하기 때문에 Basic을 선택합니다.

Current config as follows:
... 설정 내용

Are you satisfied with the above config? Note: it can be manually customized after the wizard completes to add additional items.
1. yes
2. no
default choice: [1]:
1 # 지금까지 설정 내용을 확인하는 단계입니다.

Do you have any existing CloudWatch Log Agent (http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AgentReference.html) configuration file to import for migration?
1. yes
2. no
default choice: [2]:
2 # 기존에 CloudWatch Log Agent를 사용한 적이 있다면 해당 설정 파일을 가져와서 사용합니다. 여기서는 사용하지 않았기 때문에 no를 선택합니다.

Do you want to monitor any log files?
1. yes
2. no
default choice: [1]:
1 # 로그 파일을 CloudWatch Logs로 전송할지 묻는 단계입니다. 

Log file path:
/var/logs/.pm2/logs/*.log # # cwagent는 일반 사용자 디렉토리에 접근할 수 없으므로, 로그는 /var/log 아래에 저장합니다.

Log group name:
default choice: [*.log]
/pm2/logs # CloudWatch Logs에 생성될 로그 그룹 이름을 지정합니다.

Log group class:
1. STANDARD # 자주 조죄하는 로그에 적합, 조회 속도가 빠름. (저장 비용이 비싸지만, 조회 비용이 저렴함)
2. INFREQUENT_ACCESS # 자주 조회하지 않는 로그에 적합. (저장 비용이 저렴하지만, 조회 비용이 비쌈) 
default choice: [1]:
1 # CloudWatch Logs에 수집되는 로그를 어떻게 저장할지 선택하는 단계입니다.

Log stream name:
default choice: [{instance_id}] # CloudWatch Logs의 그룹 내에서 개별 스트림의 이름을 지정합니다. 여기서는 기본값을 사용합니다.

Log Group Retention in days
1. -1 # 영구 보관
2. 1
3. 3
4. 5
5. 7
6. 14
7. 30
8. 60
9. 90
10. 120
11. 150
12. 180
13. 365
14. 400
15. 545
16. 731
17. 1096
18. 1827
19. 2192
20. 2557
21. 2922
22. 3288
23. 3653
default choice: [1]:
5 # 로그를 보관할 기간을 선택하는 단계입니다. 여기서는 7일 합니다.

Do you want to specify any additional log files to monitor?
1. yes
2. no
default choice: [1]:
2 # 추가적으로 수집할 로그 파일이 있는 경우 선택합니다.

Do you want the CloudWatch agent to also retrieve X-ray traces?
1. yes
2. no
default choice: [1]:
2 # AWS X-ray는 분산 추적 도구로, 서비스 간 호출 흐름과 지연 구간 등을 시각화해서 보여줍니다. 여기서는 사용하지 않습니다.

Existing config JSON identified and copied to:  /opt/aws/amazon-cloudwatch-agent/etc/backup-configs
Saved config file to /opt/aws/amazon-cloudwatch-agent/bin/config.json successfully.
Current config as follows:
... 설정 내용

Please check the above content of the config.
The config file is also located at /opt/aws/amazon-cloudwatch-agent/bin/config.json.
Edit it manually if needed.
Do you want to store the config in the SSM parameter store?
1. yes
2. no
default choice: [1]:
1 # 지금 생성된 설정 파일을 SSM Parameter Store에 저장할지 묻는 단계입니다. SSM에 저장하면 다른 인스턴스에 동일하게 설정할 때 사용할 수 있습니다.

What parameter store name do you want to use to store your config? (Use 'AmazonCloudWatch-' prefix if you use our managed AWS policy)
default choice: [AmazonCloudWatch-linux]
AmazonCloudWatch-my-instance # SSM Parameter Store에 저장할 때 사용할 이름을 지정하는 단계입니다. 원하는 이름을 입력합니다.

Trying to fetch the default region based on ec2 metadata...
I! imds retry client will retry 1 timesWhich region do you want to store the config in the parameter store?
default choice: [ap-northeast-2] # SSM Parameter Store의 리전을 선택합니다.

Which AWS credential should be used to send json config to parameter store?
1. ABCD...(From SDK)
2. Other
default choice: [1]:
1 # SSM Parameter Store에 설정 파일을 업로드할 때 어떤 자격 증명을 사용할지 묻는 단계입니다. 1번은 현재 인스턴스에 연결된 역할에서 제공되는 자격증명이기 때문에 1번을 선택합니다.

 

! SSM Parameter Store 관련 권한 문제

아래와 같은 에러가 발생한다면 인스턴스에 연결된 역할에 SSM Parameter Store 관련 권한이 없거나 인스턴스에 역할이 제대로 연결되지 않아서 발생할 수 있습니다. 인스턴스에 연결된 권한을 확인하거나 제대로 연결되어 있다면 인스턴스를 재부팅합니다.

Please make sure the creds you used have the right permissions configured for SSM access. Error in putting config to parameter store AmazonCloudWatch-my-instance: AccessDeniedException: User: arn:aws:sts::~:assumed-role/EC2CloudWatchAgentRole/{instance_id} is not authorized to perform: ssm:PutParameter on resource: arn:aws:ssm:ap-northeast-2:~:parameter/AmazonCloudWatch-my-instance because no identity-based policy allows the ssm:PutParameter action status code: 400, request id: ~ Program exits now.

 

CloudWatch Agent 실행

설정 파일 생성이 완료되면 CloudWatch Agent를 실행합니다. 설정 파일의 위치는 생성 과정에서 확인할 수 있으며 저는 /opt/aws/amazon-cloudwatch-agent/bin/config.json 에 생성되었습니다. 아래의 명령어를 사용해 CloudWatch Agent를 실행하고 실행 상태를 확인한다.

# CloudWatch Agent 실행
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a start \
-m ec2 \
-c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json 

# CloudWatch Agnet 실행 상태 확인
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a status

 

설정 파일을 변경하고 적용하려면 아래의 명령어를 실행합니다. SSM Parameter Store에 설정 파일을 업데이트 하려면 aws-cli가 필요합니다. aws-cli 설치 방법은 공식 문서를 참고해 주세요.

# CloudWatch Agent 설정 업데이트
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a fetch-config \
-m ec2 \
-c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json \
-s # 설정을 업데이트한 후 CloudWatch Agent를 재시작합니다.

# SSM Parameter Store 업데이트
# aws-cli 설치 필요
aws ssm put-parameter \
--name "AmazonCloudWatch-my-instance" \
--type "String" \
--value "$(cat /opt/aws/amazon-cloudwatch-agent/bin/config.json)" \
--overwrite

 

4. CloudWatch 대시보드 구성

이제 CloudWatch 대시보드에 접속해서 확인해보면 CWAgent 지표가 추가된 것을 확인할 수 있습니다.

CloudWatch 대시보드
CloudWatch 대시보드

 

저는 디스크 크기와 메모리 크기를 확인하기 위해 설정을 추가했기 때문에 disk_total, disk_used, mem_total, mem_used가 보이지만, 기본 설정에서는 disk_used_percent, mem_used_percent만 보이는 것이 정상입니다.

 

CloudWatch가 기본적으로 수집하는 지표와 CloudWatch Agent가 수집하는 지표를 통해 아래와 같이 대시보드를 구성할 수 있습니다. 위젯에 임계점을 설정하여 알림을 보내도록 설정할 수도 있습니다.

CloudWatch 대시보드

 

4. CloudWatch Logs 확인

앞서 설정한 대로, 로그 파일을 CloudWatch Logs에 전송하도록 구성했으며 로그 파일 경로는 /var/logs/.pm2/logs/*.log로 지정했습니다. 하지만 현재 PM2로 실행 중인 앱이 없기 때문에 로그 파일이 생성되지 않았고, 그로 인해 CloudWatch Logs에도 로그 그룹이 아직 생성되지 않았습니다.

 

CloudWatch Logs로 로그가 제대로 전송되는지 확인하기 위해, 간단한 NestJS 앱을 생성하고 PM2로 실행해보겠습니다.

 

먼저 필요한 패키지들을 설치합니다. nvm을 통해 Nodejs를 설치하고 npm으로 @nestjs/cli와 pm2를 설치합니다.

# nvm 설치
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

nvm이 적용되도록 bash 설정을 다시 불러옵니다.
source ~/.bashrc

# Nodejs 설치
nvm install v22

# @nestjs/cli 설치
npm install -g @nestjs/cli

# pm2 설치
npm install -g pm2

 

@nestjs/cli를 사용하여 Nestjs 앱을 생성하고 pm2로 실행합니다. pm2를 실행하기 전에 위에서 지정한 로그 파일 경로에 로그 파일을 생성하고 pm2 실행 시 해당 로그 파일에 기록하도록 옵션을 추가합니다.

# Nestjs 앱 생성
nest new my-project
cd my-project
npm install

# 빌드
npm run build

# 로그 파일 생성
mkdir -p /var/log/.pm2/logs
touch /var/log/.pm2/logs/app-out.log
touch /var/log/.pm2/logs/app-error.log

# pm2로 앱 실행
pm2 start dist/main.js \
--output /var/log/.pm2/logs/app-out.log \
--error /var/log/.pm2/logs/app-out.log

# 앱이 정상적으로 실행되었는지 확인
pm2 status

# 로그 파일 경로가 정상적으로 지정되었는지 확인
pm2 info main

 

이제 AWS 콘솔에서 CloudWatch > 로그 > 로그 그룹에 접속하면 /pm2/logs 로그 그룹이 생성된 것을 확인할 수 있고, 해당 로그 그룹을 클릭하면 인스턴스 ID를 이름으로 로그 스트림이 생성되어 있는 것을 확인할 수 있습니다.

로그 그룹
로그 스트림

 

로그 스트림을 클릭하면 Nestjs 앱이 실행되면서 출력한 로그들을 확인할 수 있습니다. 추가적으로 쌓이는 로그가 CloudWatch Logs로 잘 전송되는지 확인하려면 로그 파일에 텍스트를 추가해봅니다.

$ echo "test $(date)" >> /var/log/.pm2/logs/app-out.log

출력 로그

 

! 로그 그룹이 생성되지 않았다면

로그 그룹이 생성되지 않았다면 설정 파일에 로그 파일의 경로가 잘 지정되었는지 먼저 확인한다. 로그 파일의 경로도 잘 지정되었는데 해결되지 않는다면 해당 로그 파일을 cwagent가 읽을 수 있는지 아래의 명령어를 통해 확인한다. 해당 로그 파일뿐만 아니라 상위 디렉토리에도 접근할 수 있어야 한다.

sudo -u cwagent cat /var/log/.pm2/logs/app-out.log
sudo -u cwagent ls -al /var/log/.pm2/logs

 

만약 Permission Denied가 출력된다면 해당 디렉토리와 파일에 권한을 부여하거나 CloudWatch Agent를 root 권한으로 실행한다.

반응형