[AWS] Docker Logs -f 로그를 CloudWatch에서 확인하기
현재 문제 상황
- ec2 내 spring application log를 참고하려면, 직접 EC2에 접속하여 docker logs -f {containerID} 명령어를 실행해야 함.
[너무 번거로움]
- CI CD할 때마다 컨테이너가 중지되어 log가 사라지는 문제 발생
그래서,
1. logback.xml 및 의존성 주입, aws iam access Key를 등록하여 spring application에서 cloudwatch로 로그를 전송하고자 함
2. 하지만 이뤄지지 않았고, 구글링 결과 docker logs를 cloudwatch로 전송하여 해결하면 됨.
3. 근데, 컨테이너가 중지될 때까지 로그가 쌓이는 문제가 생기니까, CI/CD가 이뤄지는 시점을 기준으로 로그 스트림을 나눌 필요가 있었음.
4. 따라서, docker compose 및 ci - cd 코드를 수정하여 배포 시간 기준으로 로그 스트림을 나눌 수 있게 하였음.
따라서, Docker log를 AWS에서 제공하는 cloudWatch를 활용하여 로그를 관리해보자.
1. EC2에서 CloudWatch 서비스를 액세스할 권한 부여
1) CloudWatchFullAccess 역할 생성
CloudWatch를 사용하기 위해서는 가장 먼저 EC2에서 CloudWatch에 서비스를 액세스 할 권한을 부여해줘야 한다.
EC2에 부여할 IAM Role에 CloudWatchFullAccess 권한과 Cloudwatch Logs의 을 부여해주자.
2) CloudWatch 로그 그룹 생성
로그 그룹은 동일한 소스를 공유하는 로그 이벤트 시퀀스이다. 로그 보존 기간, 모니터링 및 액세스 제어 등의 설정을 공유하는 그룹입니다. 로그 그룹에서 포함할 수 있는 스트림의 수에는 제한이 없으며, 만약 여러 실행 파일에서 동일한 로그 스트림을 사용 시, 파일이 덮어씌워지는 것이 아니라 누적되는 형식으로 보관됩니다.
3) docker-compose.yml 수정
logging:
driver: awslogs
options:
awslogs-group: "gosrock-backend-log"
awslogs-region: "ap-northeast-2"
위 로깅을 추가한다.
하지만 날짜 & 시간을 기준으로 로그를 나누면 더 편하지 않을까?
위 궁금증이 들었고, 이를 해결하기 위해 ci cd 코드까지 수정하게 되었다.
결론
1) docker-compose.yml
version: "3.8"
services:
app:
container_name: web-server
image: "${DOCKER_USERNAME}/iambohyun:latest"
restart: always
ports:
- "8080:8080"
depends_on:
- redis
logging:
driver: awslogs
options:
awslogs-group: ahz-web-server-log
awslogs-region: ap-northeast-2
awslogs-stream: "ahz-web-server-${LOG_STREAM_ID}"
redis:
container_name: redis
image: redis:latest
restart: always
ports:
- "6379:6379"
command: redis-server --save 60 1 --loglevel warning
2) backend-ci-cd.yml
name: BE CI/CD with Docker Compose
on:
push:
branches:
- develop # develop 브랜치 기준으로 실행
paths:
- 'backend/**' # 백엔드 폴더 내부 파일이 변경될 때만 실행
jobs:
build-docker-image:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Setup application.yml
run: |
cd backend/src/main/resources
echo "${{ secrets.APPLICATION_DB }}" > application-db.yml
echo "${{ secrets.APPLICATION_CONFIG }}" > application-config.yml
echo "${{ secrets.APPLICATION_JWT }}" > application-jwt.yml
echo "${{ secrets.APPLICATION_SWAGGER }}" > application-swagger.yml
echo "${{ secrets.APPLICATION_ACTUATOR }}" > application-actuator.yml
echo "${{ secrets.APPLICATION_OAUTH }}" > application-oauth.yml
echo "${{ secrets.APPLICATION_AWS }}" > application-aws.yml
shell: bash
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Build with Gradle Wrapper
run: |
cd backend
./gradlew clean build -x test
- name: Docker Image Build
run: |
cd backend
docker build -t ${{ secrets.DOCKER_USERNAME }}/iambohyun:latest .
- name: DockerHub 로그인
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Docker Hub Push
run: docker push ${{ secrets.DOCKER_USERNAME }}/iambohyun:latest
deploy-to-ec2:
needs: build-docker-image
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
steps:
- name: SSH into EC2 and deploy
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_SSH_KEY }}
script: |
# EC2에 환경 변수 저장
mkdir -p ~/deploy
cd ~/deploy
# 현재 날짜/시간을 기준으로 스트림 ID 생성
LOG_STREAM_ID=$(date +"%Y%m%d-%H%M%S") # 예: 20250414-123456
echo "DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }}" > .env
echo "LOG_STREAM_ID=${LOG_STREAM_ID}" >> .env # 날짜/시간 기반 스트림 ID
# Docker 로그인
echo "${{ secrets.DOCKER_PASSWORD }}" | sudo docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
# 기존 컨테이너 제거
if [ -f "docker-compose.yml" ]; then
sudo docker-compose down
fi
# 최신 docker-compose.yml 받아오기
curl -O https://raw.githubusercontent.com/${{ github.repository }}/develop/backend/docker-compose.yml
# 최신 이미지 pull
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/iambohyun:latest
# 오래된 이미지 정리
sudo docker image prune -f
# 환경 변수로 LOG_STREAM_ID 전달하며 compose 실행
sudo --preserve-env=LOG_STREAM_ID,DOCKER_USERNAME docker-compose --env-file .env up -d --force-recreate --remove-orphans