AWS 기술 블로그
AWS IoT Core를 활용해 CloudWatch 알람을 음성으로 수신하기
AWS 사용자들은 CloudWatch를 사용해 AWS 리소스들을 모니터링하고 알람을 생성해 이상 상황을 확인 할 수 있습니다. 나아가 Amazon SNS와 연계하여 CloudWatch에서 생성한 알람들을 텍스트 기반의 이메일/SMS/슬랙과 같은 방법으로 수신 할 수 있습니다. 그러나 사용자의 서비스에 영향을 줄 수 있는 중요한 알람이 발생했지만, AWS 사용자들이 텍스트 알람을 즉시 확인하지 못하는 상황이라면 어떻게 될까요? 사용자가 알람을 확인하고 조치하기까지 많은 시간이 소요 될 것이고 결국 서비스 장애로 이어질 것입니다. 이러한 문제를 예방하기 위해 운영 상황실에 알람을 음성으로 전파하는 방식처럼 사용자들이 알람을 바로 확인 할 수 있는 새로운 방안이 필요합니다.
이번 게시글에서는 CloudWatch 알람을 텍스트가 아닌 음성으로 생성하여 사용자에게 전달하는 방법을 소개합니다. 나아가 영문에 익숙하지 않은 국내 AWS 사용자들을 위해 음성 알람을 한글로 생성하는 방법도 함께 제시합니다. 이를 통해 AWS 사용자들이 텍스트 알람을 확인하지 못하는 상황이더라도 사용자는 같은 공간에 위치한 스피커를 통해 음성으로 알람을 수신하고 알람 내용을 확인 할 수 있습니다.
솔루션 개요
이번 게시글에서 소개하는 솔루션은 CloudWatch 알람을 한국어로 번역하고 번역된 알람을 음성 메세지로 변환 후 S3 버킷에 저장합니다. 최종적으로 AWS IoT Core를 통해 스피커가 구독한 주제로 음성 메세지의 미리 서명된 URL을 게시하여 스피커에 음성 메세지를 전달합니다. 각 과정을 처리하기 위해 사용한 AWS가 제공하는 서비스와 기능을 소개합니다.
- Amazon Translate : Amazon Translate는 고품질의 사용자 지정 가능한 언어 번역을 빠르게 제공하는 신경망 기계 번역 서비스입니다.
- Amazon Polly : Amazon Polly는 딥 러닝 기술을 사용하여 텍스트를 수십가지 언어의 자연스러운 음성으로 변환하는 서비스입니다.
- AWS IoT Core : AWS IoT Core는 인프라를 관리하지 않고도 수십억 개의 IoT 디바이스를 연결하고, 수조 개의 메세지를 AWS 서비스에 라우팅 할 수 있게 해줍니다. 또한 AWS IoT SDK를 통해서 개발자들은 IoT 서비스를 쉽게 개발 할 수 있습니다.
- 미리 서명된 URL : S3 버킷의 미리 서명된 URL을 사용하여 선택적으로 객체를 공유하거나 사용자가 AWS 보안 자격 증명이나 권한 없이 버킷에 객체를 업로드하는 것을 허용할 수 있습니다.
아키텍처 소개
이번 게시글에서 소개하는 아키텍처는 사용자들이 사용하는 AWS 리소스에 이상 상황 발생 시 AWS Lambda를 중심으로 음성 알람을 생성하고 운영 상황실로 전파합니다. 음성 알람 전파를 위한 아키텍처는 아래의 순서로 진행합니다.
- CloudWatch는 AWS 리소스를 모니터링하고 이상 상황 발생 시 알람을 생성하여 Amazon SNS로 전달합니다.
- AWS Lambda는 구독한 Amazon SNS을 통해 CloudWatch 알람을 전달받고 알람 메세지를 사용자에게 전달할 형식으로 작성합니다.
- Amazon Translate를 통해 CloudWatch에서 영문으로 생성된 알람 내용을 한글로 번역합니다.
- Amazon Polly를 통해 한글로 생성된 텍스트 알람을 음성 파일로 변환합니다.
- AWS Lambda는 Amazon Polly로 생성된 음성 파일을 Amazon S3 버킷에 저장합니다. 저장한 파일을 지정된 기한 동안에만 접근 할 수 있도록 미리 서명된 URL을 발급합니다.
- AWS Lambda는 AWS IoT Core에 스피커가 구독하고 있는 주제로 미리 서명된 URL을 게시합니다.
- 스피커는 AWS IoT Core로부터 미리 서명된 URL을 수신합니다. 미리 서명된 URL을 통해 음성 알람에 접근하여 운영 상황실에 CloudWatch 알람을 음성으로 전파합니다.
사전 준비사항
이번 글에서 제공하는 실습 내용을 실행하기 위해서는 아래의 사전 준비사항이 필요합니다.
- 실습을 진행하기 위한 AWS 계정이 필요합니다.
- 음성 알람을 수신하기 위한 개인 노트북 또는 IoT 스피커가 필요합니다. 이번 실습에서는 Mac PC로 스피커를 대체합니다.
- AWS Lambda와 노트북(스피커)에 사용될 코드는 Python을 기반으로 작성합니다. 개인 노트북 사용 시 Python 패키지가 설치되어 있어야 합니다.
- AWS IoT SDK를 사용하여 AWS IoT Core와 연결합니다. AWS IoT SDK에서 AWS IoT SDK에 대한 내용을 확인 할 수 있습니다.
단계 요약
- 단계 1 : CloudFormation 스택으로 실습을 위한 기본 환경 구성
- 단계 2 : AWS IoT Core에서 IoT 디바이스 생성
- 단계 3 : IoT 디바이스를 AWS IoT Core에 연결
- 단계 4 : 음성 알람 생성을 위한 Lambda 구성
- 단계 5 : 테스트
단계 1 : CloudFormation 스택으로 실습을 위한 기본 환경 구성
1.1 – 이번 실습에서는 인스턴스에 CPU 부하를 발생시키고 CloudWatch 알람을 음성으로 전달하는 과정으로 진행됩니다. 실습을 위한 기본 환경을 생성하기 위해 아래 ‘Launch Stack’ 버튼을 클릭합니다.
1.2 – CloudFormation의 스택 이름을 ‘cloudwatch-to-iotcore’로 작성합니다. ‘AWS CloudFormation에서 사용자 지정 이름으로 IAM 리소스를 생성할 수 있습니다.’를 동의 후 전송 버튼을 클릭합니다.
1.3 – CloudFormation 스택이 생성되는데 2~3분이 소요됩니다. CloudFormation 스택이 성공적으로 생성 된 것을 확인합니다.
1.4 – CloudFormation 출력 메뉴에서 생성한 S3의 이름을 확인합니다. 생성한 S3 버킷의 이름은 Lambda 코드 작성 시 사용합니다.
1.5 – CloudFormation을 통해 아래와 같은 기본 환경이 구성되었습니다.
단계 2 : AWS IoT Core에서 IoT 디바이스 생성
2.1 – AWS IoT Core 서비스로 이동합니다. 왼쪽 탭에서 관리 -> 모든 디바이스 -> 사물로 이동합니다. 오른쪽 상단의 사물 생성을 클릭합니다.
2.2 – 등록할 사물은 단일 사물로 지정 후 다음을 클릭합니다.
2.3 – 사물 이름은 ‘OperationSpeaker’로 지정 후 나머지 옵션을 유지한 채 다음을 클릭합니다.
2.4– IoT 디바이스에서 사용할 인증서는 ‘새 인증서 자동생성’을 지정 후 다음을 클릭합니다.
2.5 – 인증서에 정책 연결 단계에서 IoT 디바이스에 적용할 보안 정책을 생성합니다. 정책 생성 버튼 클릭 시 정책 생성을 위한 새로운 탭이 생성됩니다.
2.6 – 정책의 이름은 ‘SpeakerPolicy’로 설정하고 IoT 디바이스에 적용할 상세 정책은 아래와 같이 지정합니다. 정책 리소스는 모두 * 로 설정합니다. 각 정책의 설명은 아래 표를 참고합니다.
정책 효과 | 정책 작업 | 정책 리소스 | 설명 |
허용 | iot:Connect | * | AWS IoT Core 메세지 브로커에 연결하는 권한 |
허용 | iot:Receive | * | AWS IoT Core로부터 메세지를 수신 할 수 있는 권한 |
허용 | iot:Subscribe | * | AWS IoT Core에 게시된 주제를 구독 할 수 있는 권한 |
2.7 – 사물 생성 탭으로 돌아가 생성한 정책을 연결하고 사물 생성을 클릭합니다.
2.8 – 디바이스 인증서, 퍼블릭 키 파일, 프라이빗 키 파일, 루트 CA 인증서 총 4가지 파일을 다운로드합니다. 다운로드한 4가지 파일은 PC의 디렉토리에 잘 보관합니다.
단계 3 : IoT 디바이스를 AWS IoT Core에 연결
3.1 – 실습을 위한 환경은 Mac PC를 기반으로 진행되었습니다. PC에서 IoT 스피커를 사용하기 위해 필요한 모듈을 설치합니다.
$ pip install --upgrade pip
$ pip install requests AWSIoTPythonSDK
3.2 – PC에 아래 코드로 작성된 Python 파일을 생성합니다. Python 파일 명은 ‘Audio.py’로 작성합니다. 아래 코드 중 CERTIFICATE, PRIVATE_KEY, ROOT_CA는 2.8 단계에서 다운로드한 파일의 경로를 입력합니다. AWS IoT Core Endpoint는 AWS IoT Core 서비스에서 확인 할 수 있습니다.
import json, time, os, requests, sys
import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT
# IoT 센서가 메세지를 수신할 때 작동하는 함수입니다.
def callback(client, userdata, message):
message_json = json.loads(message.payload)
url = message_json['message']
print(f"Message from IoT Core is {url}")
sys.stdout.flush()
# 수신한 미리 서명된 URL에 접근하여 음성 파일을 다운받고, 음성파일을 재생합니다.
if url.startswith("https://") :
doc = requests.get(url)
with open('alarm.mp3', 'wb') as f :
f.write(doc.content)
os.system('afplay alarm.mp3')
# AWS IoT Core에 연결합니다.
def connect() :
# AWS IoT Core 엔드포인트, IoT 단말 ID, 증명서 경로, 개인키 경로, Amazon ROOT CA 경로를 입력합니다.
ENDPOINT = "[엔드포인트 이름]"
CLIENT_ID = "OperationSpeaker"
CERTIFICATE = "[증명서 경로]"
PRIVATE_KEY = "[프라이빗 키 경로]"
ROOT_CA = "[Root CA 경로]"
# 단말이 AWS IoT Core와 통신할 주제를 지정합니다.
TOPIC = "cloudwatch/alarm"
# 단말이 AWS IoT Core와 연결하기 위한 환경을 설정합니다.
IoTClient = AWSIoTPyMQTT.AWSIoTMQTTClient(CLIENT_ID)
IoTClient.configureEndpoint(ENDPOINT, 8883)
IoTClient.configureCredentials(ROOT_CA, PRIVATE_KEY, CERTIFICATE)
IoTClient.configureOfflinePublishQueueing(-1)
IoTClient.configureDrainingFrequency(2)
IoTClient.configureConnectDisconnectTimeout(50)
IoTClient.configureMQTTOperationTimeout(50)
# AWS IoT 단말에 연결을 시도합니다.
try :
IoTClient.connect()
print('Begin Subscription to Topic :' + TOPIC)
except :
raise("Fail to connect to Topic " + TOPIC)
while True:
IoTClient.subscribe(TOPIC, 1, callback)
time.sleep(1)
print('Subscription End')
IoTClient.disconnect()
if __name__ == "__main__" :
connect()
3.3 – PC에서 ‘Audio.py’ 파이썬 파일을 실행합니다. AWS IoT Core와 정상적으로 연결 시 ‘Begin Subscription to Topic : cloudwatch/alarm’ 이라는 메세지를 출력합니다.
3.4 – 메세지를 게시하기 위해서 AWS IoT Core 서비스 화면으로 이동합니다. AWS IoT Core에서 “cloudwatch/alarm” 주제로 메세지를 게시하고 IoT 디바이스가 메세지를 수신하는지 확인합니다. 주제 게시 메뉴에서 주제를 “cloudwatch/alarm”로 지정한 후 메세지를 게시합니다.
3.5 – PC에서 메세지를 정상적으로 수신하는 것을 확인 할 수 있습니다.
3.6 – AWS IoT Core를 통한 IoT 디바이스를 생성하고 IoT 디바이스와 AWS IoT Core와의 연결에 성공했습니다. 지금까지 실습한 환경은 아래의 그림과 같습니다.
단계 4 : 음성 알람 생성을 위한 Lambda 구성
4.1 – AWS Lambda 서비스로 이동합니다. 1 단계에서 CloudFormation으로 생성한 ‘lambda-to-iotcore’ 를 클릭합니다.
4.2 – Lambda 구성 화면에서 Lambda의 코드를 아래 코드로 수정합니다. 코드 수정 시 S3 버킷 이름과 AWS IoT Core Endpoint를 입력합니다. 코드 수정 후 Deploy 버튼을 클릭하여 수정한 코드를 반영합니다. 아래 예제에서는 S3 음성파일 저장 시 ap-northeast-2 (서울리전)을 엔드포인트로 지정하였습니다. 다른 리전의 적용을 위해서는 해당 부분을 적절하게 수정해 주시면 됩니다.
import json
import boto3
import uuid
# CloudFormation을 통해 생성한 S3 Bucket을 입력합니다.
bucket_name = '[생성한 S3 버킷 이름]'
# 단계 3에서 확인한 AWS IoT Core Endpoint를 입력합니다.
endpoint = '[Endpoint 경로]'
def make_sound_alarm(evn) :
alarm_eng = json.loads(evn['Records'][0]['Sns']['Message'])['AlarmName']
instance_id = json.loads(evn['Records'][0]['Sns']['Message'])['Trigger']['Dimensions'][0]['value']
instance_name = ''
alarm_kr = ""
# Instance-id를 통해 사용자가 지정한 인스턴스 이름을 가져옵니다.
ec2_resource = boto3.resource('ec2')
ec2_instance = list(ec2_resource.instances.filter(InstanceIds=[instance_id]))
for instance in ec2_instance:
for tag in instance.tags:
if tag['Key'] == 'Name':
instance_name = tag['Value']
# 발생한 이벤트 내용과, 인스턴스의 이름으로 알람 메세지를 국문으로 생성합니다.
translate_client = boto3.client(service_name='translate')
alarm_kr = translate_client.translate_text(Text=alarm_eng, SourceLanguageCode="en", TargetLanguageCode="ko")['TranslatedText']
message = f"AWS CloudWatch 경보 알람입니다. {alarm_kr}이 발생했습니다. {alarm_kr}이 발생했습니다. 인스턴스 이름은 {instance_name}입니다..."
# polly를 통해 생성한 알람 메세지를 음성으로 변환합니다.
polly_client = boto3.client(service_name='polly')
polly_response = polly_client.synthesize_speech(Text=message, OutputFormat="mp3", VoiceId="Seoyeon", SampleRate="16000")
polly_stream = polly_response['AudioStream'].read()
# s3에 생성한 음성 파일을 저장합니다.
s3_client = boto3.client(service_name='s3', endpoint_url=('https://s3.ap-northeast-2.amazonaws.com'))
global bucket_name
post_id = str(uuid.uuid4())
filename = post_id + '.mp3'
s3_client.put_object(
Body=polly_stream,
Bucket=bucket_name,
Key=filename)
# 음성 파일의 미리 서명된 URL을 발급합니다.
url = s3_client.generate_presigned_url('get_object', Params = {'Bucket' : bucket_name,'Key' : filename}, ExpiresIn=1000)
return url
def publish_presigned_url(url) :
message = {'message' : url}
# AWS IoT Core에 연결합니다.
global endpoint
iot_client = boto3.client(
"iot-data",
endpoint_url = f"https://{endpoint}")
# 'cloudwatch/alarm' 주제로 음성파일의 미리 서명된 URL을 게시합니다.
iot_client.publish(
topic = 'cloudwatch/alarm',
qos = 1,
payload = json.dumps(message))
def lambda_handler(event, context):
# TODO implement
presigned_url = make_sound_alarm(event)
publish_presigned_url(presigned_url)
4.3– 실습을 위한 아키텍처가 아래와 같이 모두 구성이 완료됐습니다.
단계 5 : 테스트
5.1 – AWS Console에서 EC2 메뉴로 이동합니다. CloudFormation으로 생성한 TestServer 인스턴스를 확인합니다. TestServer 인스턴스를 선택 후 연결 -> EC2 인스턴스 연결에서 연결 버튼 클릭 후 SSH로 접속합니다.
5.2 – 아래 명령어를 입력하여 TestServer CPU에 부하를 생성합니다.
$ stress --cpu 1 --timeout 500
5.3 – CloudWatch 서비스로 이동하여 경보 메뉴의 모든 경보를 클릭합니다. 경보 메뉴에서 CloudFormation으로 생성한 ‘EC2-CPU-Utilization-Alarm’을 선택합니다. 기록 탭을 클릭하여 경보가 발생 된 것을 확인합니다. 경보가 발생하기까지 1~2분의 시간이 소요됩니다.
5.4 – Lambda가 음성 알람을 생성하고 PC에 실행 중인 Audio.py로 음성 파일의 미리 서명된 URL을 게시합니다. Audio.py에서 미리 서명된 URL을 정상적으로 수신하고 CloudWatch의 음성 알람이 재생되는 것을 확인 할 수 있습니다.
리소스 정리하기
1. S3 버킷에 저장되어 있는 음성 알람 파일을 삭제합니다.
2. AWS IoT Core에 이동하여 생성한 IoT 단말을 삭제합니다.
3. CloudFormation으로 이동하여 단계 1에서 생성한 CloudFormation 스택을 삭제하여 모든 리소스를 삭제합니다.
결론
AWS IoT Core를 활용해 CloudWatch 알람을 음성으로 수신하면서 운영자들은 AWS 리소스에서 발생한 이상 상황을 즉시 확인 할 수 있습니다. 또한 Amazon Polly와 Amazon Translate를 사용하여 맞춤화 된 알람을 생성해 운영자는 알람 내용을 쉽게 파악 할 수 있습니다. 운영자들은 맞춤화 된 음성 알람을 통해 서비스에 영향을 줄 수 있는 중요한 이벤트들을 즉시 대응하여 서비스 장애를 예방하고 가용성을 확보 할 수 있습니다.