들어가며
이전 글에서 어디GO의 예외 처리 시스템을 구축한 과정을 다루었다. 하지만 해당 시스템만으로는 예측하지 못한 런타임 에러가 발생했을 때 이를 신속하게 인지하기 어려웠다.
이 글에서는 이 문제를 해결하기 위해 실시간 에러 트래킹 도구인 Sentry를 도입하고, GitHub Actions 기반의 CI/CD 파이프라인에 통합한 과정을 설명한다.
1. Sentry 프로젝트 설정 및 알림 연동
애플리케이션에 코드를 추가하기 전, Sentry 웹사이트와 Slack에서 사전 설정 작업을 진행했다.
- Sentry 프로젝트 생성 및 키 발급
- Slack 연동 및 알림 규칙 설정
2. Spring Boot 애플리케이션 연동
Sentry 프로젝트 설정 후, Spring Boot 애플리케이션에 관련 의존성 및 설정을 추가했다.
- 의존성 및 플러그인 추가
build.gradle.kts
에sentry-spring-boot-starter
의존성과 Sentry Gradle 플러그인을 추가했다. 플러그인은 빌드 시점에 소스 컨텍스트를 Sentry 서버로 업로드하여, 에러 발생 시 정확한 코드 라인을 추적할 수 있게 돕는다.build.gradle.kts
1 2 3 4 5 6 7 8 9 10 11
plugins { id("io.sentry.jvm.gradle") version "5.9.0" } sentry { includeSourceContext.set(true) org.set("dnd1302") projectName.set("eodigo-backend") authToken.set(System.getenv("SENTRY_AUTH_TOKEN")) }
- 애플리케이션 설정
이전에 발급받은 DSN 키를application-dev.yml
에 설정했다. 개발 환경에서만 Sentry를 활성화하고, 다양한 옵션을 이곳에서 관리하도록 구성했다.application-dev.yml
1 2 3 4 5 6
sentry: dsn: ${SENTRY_DSN} environment: dev traces-sample-rate: 1.0 send-default-pii: true enabled: true
3. CI/CD 파이프라인 통합
애플리케이션 설정만으로는 Sentry의 모든 기능을 활용할 수 없다. 에러 발생 시 정확한 코드 위치를 추적하기 위해서는, Docker 이미지를 빌드하는 시점에 Sentry Gradle 플러그인이 소스 컨텍스트(Source Context)를 Sentry 서버로 업로드해야 한다. 이 과정에서 SENTRY_AUTH_TOKEN
이 필요하며, 우리는 이 민감 정보를 안전하게 처리하기 위해 GitHub Actions 워크플로우를 수정했다.
- GitHub Secrets 등록
SENTRY_AUTH_TOKEN
과SENTRY_DSN
같은 민감 정보는 코드에 노출되지 않도록 GitHub Repository의 Secrets에 등록했다. Docker 빌드 시 안전하게 Secret 주입하기
단순히 빌드 인자(-build-arg
)로 인증 토큰을 전달하면 Docker 이미지 레이어에 민감 정보가 남을 수 있는 보안 취약점이 있다. 우리는 이 문제를 해결하기 위해 Docker의 빌드 시크릿(build-time secrets) 기능을 활용했다.먼저,
dev-ci-cd.yml
워크플로우에서docker buildx build
명령에--secret
플래그를 추가했다. 이 플래그는 GitHub Secrets에 저장된SENTRY_AUTH_TOKEN
을sentryauthtoken
이라는 ID의 시크릿으로 빌드 컨텍스트에 전달한다.dev-ci-cd.yml
1 2 3 4 5 6 7 8 9
- name: Build and push Docker image # ... env: SENTRY_AUTH_TOKEN: $ run: | docker buildx build \\ --platform linux/amd64 \\ --secret id=sentryauthtoken,env=SENTRY_AUTH_TOKEN \\ # ...
다음으로,
Dockerfile
을 수정하여 Gradle 빌드 단계에서 이 시크릿을 사용하도록 했다.RUN
명령어에--mount=type=secret
옵션을 추가하면, 시크릿이 빌드 과정 중인 컨테이너 내의 특정 경로(/run/secrets/sentryauthtoken
)에 파일로 마운트된다. Gradle 빌드 전에 이 파일의 내용을 읽어 환경 변수로 설정하면, Sentry 플러그인이 이 토큰을 사용하여 소스 컨텍스트를 안전하게 업로드할 수 있다. 이 방식은 최종 이미지에는 토큰 정보가 전혀 남지 않는다는 장점이 있다.Dockerfile
1 2 3 4 5 6 7 8
# ... COPY src ./src RUN --mount=type=secret,id=sentryauthtoken \\ export SENTRY_AUTH_TOKEN=$(cat /run/secrets/sentryauthtoken) && \\ ./gradlew bootJar --no-daemon # ...
- 컨테이너 실행 시 DSN 환경 변수 주입
빌드가 완료된 이미지를 EC2에서 실행할 때는,e
옵션을 통해 GitHub Secrets에 저장된SENTRY_DSN
을 컨테이너의 환경 변수로 주입했다. 이를 통해 애플리케이션은 실행 시점에 어떤 Sentry 프로젝트로 에러를 전송해야 할지 알 수 있게 된다.dev-ci-cd.yml
1 2 3
docker run -d --name $CONTAINER_NAME -p $HOST_PORT:8080 --restart always \ -e SENTRY_DSN="$SENTRY_DSN" \ $IMAGE_URI
4. 동작 확인
필요한 설정이 완료됐다. 이제 GlobalExceptionHandler
의 마지막 handleException(e: Exception)
메서드에서 처리되지 않은 예외가 발생하면 Sentry SDK가 이를 감지한다. 감지된 에러는 Sentry 대시보드에 이슈로 등록되고, 앞서 설정한 규칙에 따라 Slack 채널로 즉시 알림이 전송된다.
한계: Sentry 무료 플랜
Sentry에서 제공하는 공식 Slack 연동 기능은 Business Plan 이상의 유료 플랜에서만 사용 가능하다. 우리는 14일짜리 Business Plan 평가판을 사용했다.
당시 MVP 개발 기간이 약 1주일 정도 남아있었기 때문에, 평가판 기간 내에 프로젝트를 마무리할 수 있다고 판단했기 때문이다. 무료 플랜에서 Slack 알림을 구현하려면 웹훅(Webhook)을 이용해 별도의 연동 로직을 구축해야 하지만, 남은 기간과 개발 리소스를 고려했을 때 평가판의 공식 연동 기능을 활용하는 것이 더 효율적이었다.
평가판 기간이 종료된 후, Sentry 계정은 무료(Developer) 플랜으로 전환되었고 Slack 연동도 비활성화되었다.
만약 이 프로젝트의 개발을 이어간다면 무료 플랜에서 사용 가능한 알림 시스템으로 전환해야 한다. 서버에서 Slack의 Incoming Webhooks으로 메시지를 전달하는 방식 등이 대안이 될 수 있다.
마치며
Sentry 연동을 통해 우리는 더 이상 서버 로그를 주기적으로 확인하지 않아도 예측하지 못한 에러 발생을 실시간으로 인지하고 대응할 수 있는 환경을 갖추게 되었다. 이는 서비스 안정성을 유지하고 잠재적인 버그를 선제적으로 수정해 나가는 데 중요한 기반이 되었다.