지난 포스팅 (궁금하면 클릭)에서 ECS
환경에서 컨테이너 로깅을 어떻게 야무지게 할것인지에 대해 이야기 했다.
간략하게 요약하면 실시간 로깅은 AWS Session Manager
를 통해, CloudWatch 로그는 Utern
이라는 서드파티 툴을 사용했다.
그.렇.다.면
모든 로그를 CloudWatch Log Group
에 저장하면 되는것 아닌가?
CloudWatch 로그 그룹으로 ECS
클러스터의 로그를 전달 받고 계속 저장하면 비용이 어마어마하게 불어난다.
서비스를 운영하면 기하급수적으로 늘어나는 로그를 CloudWatch 에 계속 저장하고 관리하게 된다면 그 비용은 감당하기 어려워진다.
AWS 서비스중 데이터를 저장하는 서비스라고 떠오르면 무엇이 가장 먼저 생각 나는가?
우리에겐 S3
가 있다! 🪣
외쳐 갓 S3
!
일정 기간의 로그만을 CloudWatch 에 저장 하고 기간이 지나면 CloudWatch 에 더 이상 저장하지 않고 삭제한다.
기간이 지난 로그는 S3
로 이관시켜서 보관한다.
CloudWatch Log 는 AWS Lambda
를 통해 S3
로 이관되며 Eventbridge
를 통해 일정시간마다 자동으로 작동하도록 구성한다.
CloudWatch EventBridge 의 cron 설정을 통해 AWS Lambda
가 트리깅되어 작동한다.
아키텍쳐 구현 상세
- 해당 아키텍쳐를 구현하는 순서는 다음과 같다.
- S3 Bucket 생성
- Lambda 에 부여할 IAM Role 생성
- AWS Lambda Function 구축
- CloudWatch Events Rules 생성
S3 Bucket 의 정책은 다음과 같이 설정해준다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadForGetBucketObjects",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:AbortMultipartUpload",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:GetObjectVersion",
"s3:ListMultipartUploadParts",
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::{생성한 s3 버킷 이름}/*"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:ListBucket",
"s3:GetBucketAcl",
"s3:ListBucketMultipartUploads"
],
"Resource": "arn:aws:s3:::{생성한 s3 버킷 이름}"
}
]
}
IAM 의 [역할]
탭에서 Role
을 추가한다.
생성된 Role
은 Lambda Function
을 생성할 때 부여할 것이므로 Lambda Function
생성 전에 미리 추가한다.
S3, CloudWatchLog, CloudWatchEvent
에 접근할 수 있는 정책을 해당 역할에 부여한다.
해당 Role 에 부여한 Policy 이름
- AmazonS3FullAccess
- CloudWatchLogsFullAccess
- CloudWatchEventsFullAccess
위와 같이 Lambda Function
을 생성한다.
런타임
은 함수를 작성하는 데 사용하는 언어를 의미한다.
나는 Python
으로 선택했는데, 이유는 Python
의 라이브러리 (boto3
등) 를 통해 AWS 서비스에 접근하기 편하기 때문이다.
실행 역할
은 기존 역할 사용
을 선택해주고 위에서 생성한 Role
을 선택해준다.
아래와 같이 Lambda Function
을 Python
으로 구현한다.
import boto3
import os
import datetime
GROUP_NAME = os.environ['GROUP_NAME']
DESTINATION_BUCKET = os.environ['DESTINATION_BUCKET']
PREFIX = os.environ['PREFIX']
NDAYS = os.environ['NDAYS']
nDays = int(NDAYS)
currentTime = datetime.datetime.now()
StartDate = currentTime - datetime.timedelta(days=nDays)
EndDate = currentTime - datetime.timedelta(days=nDays - 1)
fromDate = int(StartDate.timestamp() * 1000)
toDate = int(EndDate.timestamp() * 1000)
BUCKET_PREFIX = os.path.join(PREFIX, StartDate.strftime('%Y{0}%m{0}%d').format(os.path.sep))
def lambda_handler(event, context):
client = boto3.client('logs')
client.create_export_task(
logGroupName=GROUP_NAME,
fromTime=fromDate,
to=toDate,
destination=DESTINATION_BUCKET,
destinationPrefix=BUCKET_PREFIX
)
os.environ[xxx]
은 Lambda
환경 변수 설정에서 정의한 환경 변수를 가져온다는 것을 의미한다.GROUP_NAME
: CloudWatch Log Group
이름을 의미한다.DESTINATION_BUCKET
: 저장할 S3
버켓의 이름을 의미한다.PREFIX
: S3
에 저장할 로그의 폴더 명을 지정한다.NDAYS
: 며칠 전의 로그를 가져 올 것인지 지정한다.BUCKET_PREFIX
:PREFIX
와 StartDate
정보를 조합하여 S3
에 로그가 저장되는 경로를 만든다.Lambda 환경 변수 설정
- Lambda Function AWS 콘솔 아래의
구성
을 클릭하면 환경변수를 저장할 수 있다.- 위의 사진 처럼 key - value 형태로 저장한다.
[규칙]
에서 생성한다.[일정 정의]
: 이벤트를 어느 간격으로 수행할 지 정한다.[대상]
: 대상탭은 해당 이벤트가 발생할 때, 호출할 Lambda 함수를 선택하는 탭이다.ECS 환경에서 야무지게 로깅하기 에서 다뤘듯이, Lambda Function 을 이용하여 ECS 환경에서 컨테이너 로그들을 S3에 적재하는 것은 필수다.
그 이유는 첫째, Lambda Function 을 통한 자동화로 인해 로그 적재를 개발자가 신경 쓸 필요가 없어진다.
둘째, S3 에 이관함으로써 비용을 절감할 수 있다.
아무쪼록 이 글이 로그 적재 자동화를 구현하고자 하는 개발자 동료분들에게 도움이 되길 간절이 바래본다. 🙏🏻
우와 너무 섹시하세요 ❤️ 부인은 참 좋겠어요