이번 글에서는 도커로 배포한 Spring Boot 애플리케이션에서 System.out.println()이나 로그가 전혀 출력되지 않았던 문제를 해결한 과정을 정리합니다.
로컬에서는 System.out.println()을 포함한 로그가 정상적으로 출력됐지만 Docker 컨테이너에서는 어떤 출력도 확인할 수 없었습니다.
docker logs <container>로 확인해도 아무 출력이 없었고가장 먼저 의심한 건 로그 설정 문제였습니다.
application.properties 확인
logging.file.name이나 logging.file.path 설정이 적용되지 않았기 때문에 로그가 파일로 저장되는 것도 아니었음 (로그는 콘솔(stdout)로만 출력되도록 설정된 상태)Docker 환경에서 STDOUT 리디렉션 여부 점검
/dev/null로 보내는 설정은 없음ENTRYPOINT, CMD 확인
java -jar로 직접 실행하고 있어 문제 없음Gradle 의존성 확인
logback-classic, spring-boot-starter-logging 모두 포함되어 있었음문제의 원인을 좁혀보기 위해 다음과 같은 실험을 진행했습니다.
docker build -t <image-name>:debug .
docker run --rm <image-name>:debug
=> (실패) 여전히 로그는 출력되지 않았고 System.out.println() 조차 안 보였음
ENTRYPOINT ["java", "-Dspring.profiles.active=prod", "-Dlogging.level.root=DEBUG", "-jar", "/app/app.jar"]
=> 효과 없음
이후 logback-spring.xml을 명시적으로 추가했습니다.
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
<logger name="com.friends" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
이후 로그가 출력되기 시작했고 System.out.println()도 보였습니다.
logback.xml을 명시적으로 설정하면 콘솔 appender가 강제로 연결되기 때문에 System.out을 우회하거나 logback 내부 버퍼를 사용해 로그 출력이 복구된 것으로 추정됩니다.
그리고 문제의 user 설정... (보안만 생각하다 고장(?)낸 유저
RUN useradd -m appuser
USER appuser
해당 설정으로 인해 애플리케이션이 appuser 권한으로 실행되었고 이 유저는 /dev/stdout이나 /dev/stderr와 같은 표준 출력 스트림에 접근할 수 없었습니다. (수정 권한이 없는 일반 유저이기 때문)
때문에 로그 출력이 차단된 상태였습니다.
이를 검증하기 위해 진행한 실험)
USER appuser 설정을 제거하고 USER root로 변경한 뒤 실행 → 로그 정상 출력 확인logback-spring.xml을 제거하고도 로그가 계속 출력됨을 확인appuser로 실행 시 flush 문제나 stdout 접근 문제 등으로 인해 무시되거나 출력되지 않을 수 있음.교차 검증을 통해 근본 원인은 사용자 권한 설정이라는 것을 깨달았고 .. 😇
추가적으로, USER appuser를 유지하면서도 로그를 정상 출력하려면 stdout 및 stderr에 접근 가능한 권한을 부여해야 합니다.
appuser를 tty, docker 또는 적절한 그룹에 추가하거나 권한 있는 디렉토리로 작업 디렉토리를 설정하는 방법이 있다고 함.RUN useradd -m appuser && \
chown -R appuser /app # 여기!
USER appuser
무작정 root 권한을 가진 user 를 쓰는 것 대신에 필요한 최소 권한만 부여하는 것이 더 바람직할 것 같긴 하다.
배운점
USER 설정은 stdout 접근 여부에 직접적인 영향을 줄 수 있음System.out.println()조차 출력되지 않을 경우 stdout 스트림 자체에 접근이 불가능한 상태일 수 있음그래도 단순히 logback 설정을 수정하는 데 그치지 않고 애플리케이션 실행 환경과 컨테이너 내 사용자 권한 문제까지 점검해나간 과정을 통해 로깅 시스템과 Docker 환경을 좀 더 이해하게 된 것 같다 ^_^;
며칠간의 삽질 제발 끝 ~~ ⛏️