Docker 테스트 및 코드품질 미드레벨 기술면접
새 면접Q. Docker 컨테이너로 실행되는 마이크로서비스의 통합 테스트를 작성할 때, 테스트 환경의 컨테이너 격리성과 재현성을 보장하기 위한 전략을 설명하고, Testcontainers 같은 라이브러리를 활용한 테스트 자동화 방법과 테스트 후 리소스 정리(cleanup) 전략을 제시해주세요.
테스트마다 독립적인 컨테이너 인스턴스를 생성하고 종료하는 방식과 네트워크 격리를 고려해보세요.
통합 테스트에서는 각 테스트 케이스마다 독립적인 컨테이너 인스턴스를 생성하여 테스트 간 상태 공유를 방지해야 합니다. Testcontainers 라이브러리를 사용하면 테스트 코드 내에서 프로그래매틱하게 컨테이너를 시작하고, 테스트 완료 후 자동으로 컨테이너를 제거할 수 있습니다. 데이터베이스나 메시지 큐 같은 의존성 서비스를 실제 컨테이너로 실행하여 프로덕션 환경과 유사한 조건에서 테스트할 수 있습니다. 테스트 격리를 위해 각 테스트마다 별도의 Docker 네트워크를 생성하고, @AfterEach나 try-finally 블록에서 컨테이너와 네트워크를 명시적으로 정리해야 합니다. docker-compose.test.yml 파일을 별도로 관리하여 테스트 전용 설정을 분리하고, CI/CD 파이프라인에서 일관된 테스트 환경을 보장할 수 있습니다.
- • 각 테스트마다 독립적인 컨테이너 인스턴스 생성으로 격리성 보장
- • Testcontainers를 활용한 프로그래매틱 컨테이너 라이프사이클 관리
- • 테스트 후 컨테이너와 네트워크 자동 정리로 리소스 누수 방지
- • docker-compose.test.yml로 테스트 환경 설정 분리
마이크로서비스 개발 시 실제 PostgreSQL, Redis 컨테이너를 사용한 통합 테스트로 프로덕션 환경과 동일한 조건에서 검증합니다.
CI/CD 파이프라인에서 병렬로 실행되는 여러 테스트 작업이 동일한 Docker 호스트를 공유할 때 포트 충돌이나 리소스 경합을 방지하기 위한 방법은 무엇인가요?
Q. 팀원이 작성한 Dockerfile에서 RUN 명령어마다 apt-get update와 패키지 설치를 별도 레이어로 분리하고, 소스 코드 복사를 Dockerfile 상단에 배치한 것을 발견했습니다. 이러한 구조가 빌드 캐시 효율성과 이미지 크기에 미치는 부정적 영향을 설명하고, 코드 리뷰 시 제안해야 할 개선 방안을 제시해주세요.
레이어 캐싱 원리와 명령어 체이닝, 파일 변경 빈도에 따른 배치 순서를 고려해보세요.
apt-get update를 별도 레이어로 분리하면 캐시된 오래된 패키지 인덱스를 사용하여 잘못된 버전의 패키지가 설치될 수 있으므로, RUN apt-get update && apt-get install을 하나의 명령어로 체이닝해야 합니다. 소스 코드를 Dockerfile 상단에 배치하면 코드 변경 시마다 모든 하위 레이어의 캐시가 무효화되어 빌드 시간이 크게 증가합니다. 변경 빈도가 낮은 작업(시스템 패키지 설치, 의존성 설치)을 상단에, 변경 빈도가 높은 작업(소스 코드 복사)을 하단에 배치해야 캐시를 효율적으로 활용할 수 있습니다. package.json 같은 의존성 파일만 먼저 복사하여 npm install을 실행하고, 그 이후에 소스 코드를 복사하는 순서로 개선해야 합니다. 또한 apt-get clean과 rm -rf /var/lib/apt/lists/*를 같은 RUN 명령어에 포함시켜 불필요한 캐시 파일을 제거하고 이미지 크기를 줄여야 합니다.
- • apt-get update와 install을 하나의 RUN으로 체이닝하여 캐시 문제 방지
- • 변경 빈도가 낮은 레이어를 상단에 배치하여 캐시 효율성 극대화
- • 의존성 파일과 소스 코드 복사를 분리하여 빌드 시간 단축
- • 불필요한 캐시 파일 정리로 이미지 크기 최소화
프론트엔드 애플리케이션 빌드 시 node_modules 설치 레이어를 소스 코드보다 앞에 배치하여 코드 변경 시에도 의존성 캐시를 재사용합니다.
멀티 스테이지 빌드에서 각 스테이지의 캐시를 독립적으로 관리하면서도 스테이지 간 공통 의존성을 효율적으로 공유하기 위한 방법은 무엇인가요?
Q. Docker 컨테이너의 HEALTHCHECK 명령어를 사용하여 애플리케이션의 정상 상태를 검증할 때, 단순 HTTP 200 응답 확인을 넘어서 데이터베이스 연결 상태, 외부 API 응답 시간, 메모리 사용률 등을 종합적으로 판단하는 헬스체크 스크립트를 설계하는 방법을 설명하고, false positive와 false negative를 최소화하기 위한 전략과 헬스체크 실패 시 자동 복구 메커니즘을 제시해주세요.
여러 체크 항목의 가중치, 재시도 로직, graceful degradation 개념을 고려해보세요.
종합적인 헬스체크는 여러 레벨의 검증을 포함해야 하며, liveness와 readiness를 구분하여 설계해야 합니다. HTTP 엔드포인트는 /health/live(프로세스 살아있음)와 /health/ready(트래픽 받을 준비됨)로 분리하고, readiness에서 데이터베이스 연결, 캐시 서버 응답, 필수 외부 API 접근성을 검증합니다. 각 체크 항목에 타임아웃을 설정하고(예: DB 연결 2초, API 호출 3초), 일시적 네트워크 지연으로 인한 false positive를 방지하기 위해 연속 3회 실패 시에만 unhealthy로 판단하는 로직을 구현합니다. 헬스체크 스크립트 내부에서 circuit breaker 패턴을 적용하여 외부 의존성 장애가 전체 서비스를 중단시키지 않도록 하고, 비필수 서비스는 degraded 상태로 표시하되 healthy를 유지합니다. Docker의 --health-retries, --health-interval, --health-start-period 옵션을 적절히 조정하여 컨테이너 시작 시 초기화 시간을 고려하고, 오케스트레이션 도구(Kubernetes, Swarm)와 연동하여 unhealthy 컨테이너를 자동으로 재시작하거나 트래픽에서 제외시킵니다.
- • liveness와 readiness 헬스체크 분리로 목적에 맞는 검증 수행
- • 여러 의존성 체크에 타임아웃과 재시도 로직 적용
- • circuit breaker 패턴으로 외부 장애 전파 방지
- • 헬스체크 파라미터 튜닝과 오케스트레이션 도구 연동으로 자동 복구
마이크로서비스에서 데이터베이스 장애 시에도 캐시된 데이터로 제한적 서비스를 제공하면서 readiness는 통과시키는 degraded 모드를 구현합니다.
Kubernetes 환경에서 readinessProbe와 livenessProbe의 실패 임계값과 주기를 설정할 때, 트래픽 패턴과 애플리케이션 특성을 고려한 최적값을 결정하는 방법은 무엇인가요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!