Infra & Cloud/AWS

[AWS] Docker Logs -f 로그를 CloudWatch에서 확인하기

류건 2025. 4. 19. 16:17
반응형

현재 문제 상황

- 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

 

참고

https://devnm.tistory.com/8

반응형