Spring Boot 기반 애플리케이션을 Kubernetes 환경에 배포하면서, 로그 수집 방식에서 다음과 같은 문제가 발생했다. 동일한 로그 경로에 여러 Pod가 동시에 접근하면서 로그가 덮어씌워지거나 뒤섞이는 문제가 생긴 것이다. 이를 해결하기 위해 Pod별로 로그를 분리하고, 날짜 기준으로 Rolling 되도록 설정한 경험을 정리해본다.
1. 로그 파일이 충돌하는 문제 발생
애플리케이션 로그는 app.log라는 고정된 파일명으로 기록되고 있었고, 이는 여러 Pod가 동일한 볼륨을 공유할 경우 로그 충돌을 일으켰다. 특히 상태 비저장(Stateless)한 구조에서 동시성이 높은 상황에서는 로그 유실이나 파일 잠금 문제가 발생할 수 있었다. 따라서 Pod마다 고유한 로그 파일을 생성하는 방식이 필요했다.
2. Pod 이름을 로그 파일명에 반영하는 방법 고민
처음에는 logback의 ${env:HOSTNAME}을 사용해 로그 파일명에 환경변수를 적용하려 했지만, 환경변수를 수동으로 주입하지 않고도 Kubernetes에서 자동 설정된 값을 활용하고 싶었다. Kubernetes에서는 각 Pod의 이름이 자동으로 시스템 환경변수 HOSTNAME에 할당되므로, 이를 그대로 사용할 수 있다면 간편하게 문제를 해결할 수 있을 거라 판단했다.
3. logback-spring.xml에 HOSTNAME 적용
Spring Boot에서는 일반적인 logback.xml 대신 logback-spring.xml을 사용할 경우, Spring의 Environment 기능과 통합되어 더 유연한 설정이 가능하다. logback-spring.xml 파일에서 ${env:HOSTNAME}을 정의한 뒤, 로그 파일명에 #{HOSTNAME}을 사용하는 방식으로 설정을 구성했다. 중요한 점은 ${}가 아닌 #{}을 사용해야 동적으로 치환된 값이 로그 파일명에 정상 적용된다는 점이다.
<property name="HOSTNAME" value="${env:HOSTNAME}" />
<file>logs/app-#{HOSTNAME}.log</file>
이 설정을 통해 Pod가 실행될 때 해당 Pod의 이름이 로그 파일명에 포함되도록 만들 수 있었다. Kubernetes의 Deployment 설정에서 별도로 환경변수를 주입하지 않아도 된다는 점에서 매우 간단하고 효과적인 방법이었다.
4. 날짜 기준으로 로그 파일 자동 Rolling 설정
로그가 한 파일에 무한히 누적되면 디스크 용량 관리가 어렵고, 운영 중 문제 발생 시 특정 시점의 로그만 분리해서 보기 어려워진다. 이를 해결하기 위해 logback의 TimeBasedRollingPolicy를 사용하여 날짜가 바뀔 때마다 로그 파일이 자동으로 분리되도록 구성했다.
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app-#{HOSTNAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app-#{HOSTNAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
여기서 핵심은 fileNamePattern으로, 날짜 단위로 파일을 자동 생성하고 저장하는 규칙을 정의한다. %d{yyyy-MM-dd} 형식을 사용하면 일자별로 새로운 로그 파일이 생성된다. maxHistory를 통해 최대 보관 일수를 설정하고, cleanHistoryOnStart 옵션을 활성화하면 오래된 파일은 애플리케이션 시작 시 자동 정리된다.
5. 압축 저장 옵션까지 고려
로그 파일이 많아질 경우 디스크 공간이 부족해질 수 있으므로, 로그 파일을 자동으로 압축해서 저장하도록 설정할 수도 있다. 이때는 fileNamePattern에 .zip을 추가하면 된다.
<fileNamePattern>logs/app-#{HOSTNAME}.%d{yyyy-MM-dd}.log.zip</fileNamePattern>
이렇게 하면 로그가 생성될 때마다 자동으로 압축되어 저장되며, 저장 공간도 효율적으로 관리할 수 있다.
6. 결과 및 느낀 점
이번 설정을 통해 Kubernetes 환경에서 각 Pod의 이름을 기반으로 한 개별 로그 파일을 만들 수 있었고, 날짜별로 Rolling 되도록 설정하여 디스크 용량 문제나 로그 가독성 문제도 함께 해결할 수 있었다. 무엇보다 Kubernetes에서 자동 설정되는 HOSTNAME 값을 그대로 활용했기 때문에 불필요한 환경변수 주입 없이도 깔끔한 구성이 가능했다. 이 방식은 다양한 Spring Boot 기반 마이크로서비스 구조에서도 쉽게 적용할 수 있어, 실제 운영 환경에서 매우 유용한 로그 관리 전략이라 느꼈다.
'개발 (Development) > Java' 카테고리의 다른 글
| [Java/Spring Boot] Spring Boot + MyBatis 환경에서 쿼리 조회용 API를 만들기 전에 꼭 고려해야 할 5가지 (2) | 2025.05.18 |
|---|---|
| [Java] 사내망에서 Gradle 빌드 시 PKIX 인증서 오류 해결기 (feat. 프록시 & 인증서 등록) (0) | 2025.04.19 |
| [Java/MyBatis] MyBatis <foreach>에서 #{}와 ${} 차이, 그리고 item 두 번 쓰기 (0) | 2025.04.05 |
| [Java] 리스트의 요소가 다른 리스트에 포함되지 않는지 확인 (Collections.disjoint()) (1) | 2025.03.22 |
| [Java] API 요청 및 응답 시 비동기 처리 (0) | 2024.12.30 |