
'모또’는 모임 정산 과정에서 발생하는 정산 지연등의 여러 문제에 대한 총무의 부담을 줄이기 위해 게이미피케이션 요소를 더하여 모임원들의 적극적인 정산 참여를 유도하는 서비스입니다.
Spring REST Docs와 Redis 기반 캐시를 도입한 뒤 서버 배포 과정에서 테스트 실패로 인해 배포가 중단되는 문제가 발생했습니다.

처음에는 "왜 Redis 테스트에서만 실패하지?"라는 의문이 들었습니다. 새로 추가된 부분과 Spring REST Docs 설정을 살펴봤지만 설정 자체에는 특별한 문제가 없어 보였습니다. 혹시 Redis를 테스트하기 위해 도입한 Testcontainers 쪽 이슈가 아닌지 의심하며 여러 가능성을 테스트했습니다.
이 과정에서 Dockerfile로 배포할 때 ./gradlew bootJar를 실행하면 테스트가 실패한다는 사실을 알게 됐습니다. 그래서 혹시 명시적으로 테스트를 실행하면 다를까 싶어 Dockerfile에 ./gradlew test를 추가해봤지만 역시 동일하게 실패했습니다.
여기서 "왜 로컬이나 CI에서는 통과하던 테스트가 Dockerfile 빌드 환경에서는 실패하지?"라는 의문이 들었고 원인을 추적하다가 Docker 컨테이너 내부에서 Testcontainers가 Redis 컨테이너를 띄우려고 할 때 호스트의 Docker 데몬에 접근할 수 없다는 사실을 알게 되었습니다.
GitHub Actions와 같은 CI 환경에서는 호스트의 Docker 데몬에 접근할 수 있어서 Testcontainers 기반 테스트가 정상적으로 동작합니다.
하지만 Dockerfile에서 ./gradlew bootJar를 실행할 때는 Docker 컨테이너 내부에서 다시 Docker 컨테이너(Testcontainers로 띄우는 Redis 등)를 실행해야 하는 상황이 됩니다.
이런 구조를 "Docker in Docker"라고 하는데 일반적인 Docker 빌드 환경에서는 도커 내부에 도커가 설치되어 있지 않기 때문에 Testcontainers가 동작하지 않고 이로 인해 테스트가 실패하게 되는 것입니다.
이 문제를 해결하기 위해 기존에는 Dockerfile에서 빌드와 테스트 실행 환경을 모두 처리했지만 아래와 같이 워크플로우를 분리했습니다.
# 1단계: 빌드 환경 (Gradle 빌드)
FROM gradle:7.4.2-jdk17 AS builder
WORKDIR /app
COPY gradlew .
COPY gradle gradle
COPY build.gradle .
COPY settings.gradle .
RUN chmod +x ./gradlew
RUN ./gradlew dependencies
COPY src src
RUN ./gradlew bootJar --no-daemon
# 2단계: 실행 환경 (최종 실행 이미지만 남김)
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar /app/moddo.jar
ENTRYPOINT ["java", "-Dspring.profiles.active=prod", "-jar", "moddo.jar"]
이 방식에서는 빌드 단계에서 테스트가 실행되어야 하는데 Docker 컨테이너 내부에서 Testcontainers가 동작하지 않아 실패합니다.
...
- name: Run tests (Testcontainers, Spring REST Docs)
run: ./gradlew test --no-daemon
- name: Build JAR
run: ./gradlew bootJar -x test
...
# 실행 환경 (최종 실행 이미지만 남김)
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY build/libs/*.jar /app/moddo.jar
ENTRYPOINT ["java", "-Dspring.profiles.active=prod", "-jar", "moddo.jar"]
이렇게 빌드와 테스트는 CI(GitHub Actions)에서 미리 수행하고 Dockerfile에서는 빌드된 JAR 파일만 복사해서 실행 환경만 구성하도록 분리했습니다. 이로써 Docker 빌드 단계에서 Testcontainers가 동작하지 않아 발생하던 테스트 실패 문제를 해결할 수 있었습니다.