2025년 11월 15일
카테고리 : AWS조회 : 15인프라AWS
EC2 로그 파일 S3 업로드 자동화
EC2 로그 파일 S3 업로드 자동화 스크립트 완벽 가이드
운영 서버에서 로그를 안전하게 보관하려면 주기적으로 S3로 백업하는 자동화 작업이 필수입니다. 특히 Auto Scaling 환경에서는 인스턴스가 계속 생성되고 종료되기 때문에, 각 인스턴스별로 로그를 안전하게 관리하기 위해 Instance ID 기반 S3 경로 구조를 사용하는 것이 가장 안정적인 방식입니다.
저는 실제 운영 환경에서 EBS 용량 부족으로 인해 심각한 장애를 경험한 적이 있습니다. 당시 EBS 용량이 충분하지 않은 작은 사이즈로 설정되어있었고, 로그 백업이나 용량 관리 체계를 제대로 구축하지 않은 상태였습니다. 그 결과 다음과 같은 문제가 발생했습니다.
- 새로운 JAR 배포를 시도했지만 디스크 용량 부족으로 배포 실패
- 애플리케이션 로그가 무제한으로 쌓여 EBS가 가득 참
- 이후 로그백 정책을 적용해 압축 및 주기적 삭제를 설정했으나, 데이터독·자비스 등 서버 내부 라이브러리들이 계속 쌓이며 다시 용량 부족 발생
- 로그 보관 기간을 원래 3개월 → 1개월로 축소했지만, 운영 중 장애 분석이 필요할 때 1개월 전 로그가 삭제되어 분석 불가능
당시 저희는 막 외주사로부터 인계받은 후 프로젝트에 합류한 상황이기도 하며 제대로 된 기존 운영 문서도 없었고, 애플리케이션 안정화가 덜 된 상태에서 장애 대응과 운영을 동시에 해야 했습니다. 사용자가 적은 서비스였고, 현재 다른 서비스는 용량이 넉넉한 서버 기반 운영을 경험했기 때문에 "로그 관리"의 중요성을 간과했던 것도 분명했습니다.
이 경험을 통해 서버 운영에서 로그 관리와 용량 관리는 결코 사소한 문제가 아니라 핵심 안정성 요소라는 점을 절실히 깨달았습니다. 이후 Auto Scaling 환경을 구성하면서 로그 저장 방식을 깊게 고민했고, 최종적으로 "EC2 내부에 쌓이는 로그를 매일 S3로 백업하는 방식"으로 결론 내렸습니다. 이를 위해 스크립트를 작성하고 Cron에 등록해 자동화하는 구조를 구축했습니다.
이번 글에서는 제가 실무에서 직접 겪은 문제와 해결 과정을 바탕으로, EC2 → S3 로그 업로드 스크립트의 설계, 작성, 실행, 자동화 과정을 단계별로 정리해 공유합니다.
1. 로그 업로드 스크립트 목적
- 운영 중인 EC2 인스턴스의 전날 로그를 매일 자동으로 S3에 백업
- Auto Scaling 환경에서도 인스턴스별 로그를 안전하게 보관
- 디스크 공간 확보 및 로그 유실 방지
2. 업로드 대상 로그 예시
다음 4개의 파일만 S3로 전송한다고 가정합니다.
app_info.log
service_api.log
app_error.log
application.log
3. S3 업로드 스크립트 작성
파일: /home/ec2-user/log_s3_backup.sh
bash1#!/bin/bash 2 3# ------------ EC2 Instance ID (IMDSv2) ------------ 4TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \ 5 -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") 6 7INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \ 8 http://169.254.169.254/latest/meta-data/instance-id) 9 10# ------------ Log & S3 Path ------------ 11LOG_DIR="/apps/logs/api" 12BUCKET="s3://api-logs" 13 14# 오늘 날짜 기반 15TODAY=$(date +%Y-%m-%d) 16DEST="$BUCKET/$INSTANCE_ID/$TODAY" 17 18echo "[$(date)] Uploading logs for $TODAY to $DEST" 19 20# ------------ Upload logs ------------ 21FILES=( 22 "app_info.log" 23 "service_api.log" 24 "app_error.log" 25 "application.log" 26) 27 28for FILE in "${FILES[@]}"; do 29 FULL_PATH="$LOG_DIR/$FILE" 30 31 if [ -r "$FULL_PATH" ]; then 32 echo "Uploading $FULL_PATH ..." 33 aws s3 cp "$FULL_PATH" "$DEST/" 34 else 35 echo "Skipping $FULL_PATH (not readable)" 36 fi 37done 38 39echo "[$(date)] Upload completed"
4. 스크립트에 IMDSv2가 필요한 이유
로그를 저장할 S3 경로를 다음처럼 구성하기 위함입니다.
s3://api-logs/<INSTANCE_ID>/<날짜>/...
Instance ID를 자동으로 얻어야 Auto Scaling 환경이나 이벤트시 대량 트래픽이 예상될 때 인스턴스를 여러개 띄우는 환경에서도 충돌 없이 운영할 수 있기 때문에, 스크립트 내부에서 EC2 메타데이터(IMDSv2)를 사용합니다.
5. 스크립트 실행 권한 부여
bash1sudo chmod +x /home/ec2-user/log_s3_backup.sh
6. 처음 한 번 수동 실행해보기
bash1sudo /home/ec2-user/log_s3_backup.sh
S3 버킷에 업로드된 경로를 직접 확인.
7. Cron 자동화 설정
로그 백업은 새벽 시간대(트래픽 적을 때) 실행하는 것이 일반적입니다.
예: 매일 02:00 수행
bash1sudo crontab -e
아래 추가:
0 2 * * * /home/ec2-user/log_s3_backup.sh >> /var/log/log_s3_backup.log 2>&1
8. S3에 저장되는 폴더 구조
로그는 다음과 같은 구조로 저장됩니다:
<s3-bucket>/<EC2_INSTANCE_ID>/<YYYY-MM-DD>/파일들...
예시:
s3://my-log-bucket/i-0abcd1234ef56789/2025-11-14/app_info.log
s3://my-log-bucket/i-0abcd1234ef56789/2025-11-14/service_api.log
s3://my-log-bucket/i-0abcd1234ef56789/2025-11-14/app_error.log
s3://my-log-bucket/i-0abcd1234ef56789/2025-11-14/application.log
이 폴더 구조는 다음 이유 때문에 사용합니다:
- Auto Scaling 환경 대응 : 인스턴스 ID로 구분되므로 여러 서버가 동시에 떠도 충돌 없음
- 문제 발생 인스턴스 추적 가능 : 어느 EC2에서 발생한 로그인지 즉시 확인 가능
- 날짜별 폴더링으로 관리 용이 : 특정 날짜 해결/모니터링 시 탐색이 쉬움
9. EC2가 S3에 업로드하기 위해 필요한 IAM 권한
스크립트가 동작하려면 EC2 인스턴스 프로파일(Instance Role)에 최소한 아래 권한이 필요합니다.
최소 권한 정책 (Least Privilege)
S3 특정 경로에만 Put 할 수 있게 제한하는 권장 정책입니다.
json1{ 2 "Version": "2012-10-17", 3 "Statement": [ 4 { 5 "Effect": "Allow", 6 "Action": [ 7 "s3:PutObject", 8 "s3:PutObjectAcl" 9 ], 10 "Resource": "arn:aws:s3:::my-log-bucket/*" 11 } 12 ] 13}
더 안전한 형태 (EC2 인스턴스 ID 기반 Restrict)
버킷 전체가 아닌 EC2 Instance ID 기반으로 저장되는 경로만 허용할 수도 있습니다.
json1{ 2 "Version": "2012-10-17", 3 "Statement": [ 4 { 5 "Effect": "Allow", 6 "Action": "s3:PutObject", 7 "Resource": "arn:aws:s3:::my-log-bucket/${aws:ec2:instance-id}/*" 8 } 9 ] 10}
※ AWS 정책 변수(Policy Variables)를 사용해 해당 EC2 본인 경로만 업로드 가능하게 제한하는 방식.
10. 로그 백업 운영 시 추가적으로 고려해야 할 요소
EC2 → S3 로그 업로드 자동화를 정교하게 운영하려면 다음 항목들도 반드시 고려해야 합니다.
1) S3 Lifecycle 정책 적용 (보관 비용 자동 절감)
로그는 장기 보관 시 비용이 크게 증가할 수 있으므로 S3 Lifecycle을 적용하여 자동 관리할 수 있습니다. 예시 정책:
- 30일 후 → Standard-IA 로 이동 (저렴한 스토리지)
- 90일 후 → Glacier Flexible Retrieval 로 이동
- 180일 후 → Glacier Deep Archive 로 이동
- 365일 후 → 자동 삭제
Lifecycle 예시 설정:
Transition: 30 days → STANDARD_IA
Transition: 90 days → GLACIER
Expiration: 365 days
로그는 "시간이 지나면 가치가 줄어드는 데이터"이므로 Lifecycle 정책을 쓰는 것이 사실상 필수입니다.
일반적인 경우 저희가 이미 운영 중인 서비스는 3개월 전의 로그도 찾는 경우가 잦습니다.
따라서 약 3개월후엔 글래시어에 이동되도록 합니다.
2) 업로드 실패 대비 Retry / Error Logging
S3 업로드는 네트워크 이슈로 실패할 수 있으므로 다음을 추가할 수 있습니다.
- 업로드 실패 시 3회 재시도
- 실패 내역을 로컬 파일 또는 CloudWatch Logs에 기록
- 반복 실패 시 관리자에게 SNS 알림 전송 가능
예: 간단한 Retry 로직
bash1aws s3 cp "$FILE" "$DEST/" || aws s3 cp "$FILE" "$DEST/" || aws s3 cp "$FILE" "$DEST/"
3) Cron 실행 시간 최적화
로그 사이즈가 큰 서비스라면 다음 시간대가 Best Practice입니다.
서버 부하가 가장 낮을 시간대인 02:00 로 설정했습니다.
또한 Cron 실행 시점과 애플리케이션 로그 로테이션 시점이 겹치지 않도록 관리해야 합니다.
4) S3 PUT 비용 최적화
S3는 저장 비용 외에도 PUT 요청당 요금이 발생합니다. 이를 줄이려면:
- 여러 파일을 하나로 묶어 업로드 (gzip / tar)
- 하루 단위 압축 파일로 업로드
- CloudWatch Logs로 실시간 전송 후 별도로 S3 Export 적용
예: 압축 업로드 버전
bash1tar -czf logs_$TODAY.tar.gz app_info.log service_api.log app_error.log application.log 2aws s3 cp logs_$TODAY.tar.gz "$DEST/"
5) 로그 무결성을 위한 MD5 체크섬 저장
로그 손상 여부를 검증하려면 파일 업로드 후 MD5 해시값도 함께 저장하는 방식이 있습니다. 예:
application.log
application.log.md5
이렇게 하면 감사(Audit) 목적으로도 활용 가능합니다.
6) S3 버킷 버전관리(Optional)
중요 로그라면 S3 Versioning을 활성화할 수 있습니다.
- 실수로 덮어쓰기 방지
- 삭제 복구 가능
비용은 증가하지만 필수에 가깝다고 생각합니다.
7) Athena + S3 연동하여 로그 쿼리 분석 환경 구축
S3에 저장된 로그를 단순 보관용이 아니라 검색 / 분석 목적으로도 활용할 수 있습니다.
- Athena 테이블 생성 → SQL 쿼리로 오류/패턴 분석
- CloudTrail, ELB 로그 등도 함께 분석 가능
예: Athena에서 로그 조회 SQL
sql1SELECT * 2FROM logs 3WHERE message LIKE '%ERROR%' 4AND log_date = '2025-11-14';