ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Docker Compose][migration 순서] service_completed_successfully로 앱 시작을 안전하게 기다리는 법
    기타개발지식/풀스택개발 2026. 9. 6. 20:05

    IT 리서치 노트

    [Docker Compose][migration 순서] service_completed_successfully로 앱 시작을 안전하게 기다리는 법

    Docker Compose에서 앱과 migration을 동시에 시작하면 새 앱이 이전 스키마를 읽거나 여러 인스턴스가 같은 migration을 경쟁할 수 있다. 2026년 9월 6일 KST 기준 Docker 공식 문서는 depends_on의 service_completed_successfully 조건으로 일회성 서비스가 성공 종료할 때까지 기다릴 수 있다고 설명한다. DB 준비와 스키마 변경 완료를 분리해 안전한 시작 순서를 만드는 법을 정리한다.

    1. 개요

    DB에는 service_healthy, migration에는 service_completed_successfully를 사용한다. migration 프로세스가 exit 0으로 끝난 뒤에만 앱이 시작되며, 실패하면 앱 시작도 막힌다. 핵심은 migration 명령이 실패를 정확한 non-zero 코드로 반환하고 재실행 가능해야 한다는 점이다.

    시작 순서가 의심되면 depends_on과 service_healthy 설정, 검사 시간값이 의심되면 healthcheck 시간 필드 비교, 종료 뒤 복구 규칙은 Docker 재시작 정책 선택 기준에서 먼저 경계를 확인할 수 있다.

    2. 어디서 실제로 막히는가

    대표 증상은 배포 직후 앱 로그에 column does not exist가 잠깐 나타나거나, 두 앱 인스턴스가 시작하며 같은 DDL을 동시에 실행하는 경우다. 앱 entrypoint 안에 migration과 서버 시작을 한 줄로 묶으면 완료 조건과 실패 원인이 잘 보이지 않는다.

    • DB 컨테이너 running을 쿼리 가능 상태로 본다.
    • migration 실패를 shell이 exit 0으로 바꾼다.
    • restart: always 때문에 성공한 migration이 반복된다.
    • rollback 불가능한 DDL을 자동 시작 경로에 넣는다.

    migration을 독립 서비스로 분리하면 ps --all과 logs에서 exit code와 실행 기록을 따로 확인할 수 있다. 앱은 migration 구현을 알 필요 없이 성공 완료라는 사건만 기다린다.

    재현 기록에는 사용한 이미지 태그와 Compose 프로젝트 이름, 실행 명령, 관찰 시각을 함께 남긴다. 같은 파일이라도 이미지가 바뀌거나 다른 override가 적용되면 결과가 달라진다. 정상 사례 하나와 실패 사례 하나를 같은 순서로 수집해야 관찰 기준이 충분히 민감한지도 확인할 수 있다.

    수정할 때는 파일 여러 곳을 한 번에 바꾸지 않는다. 현재 출력과 설정을 저장하고 첫 불일치 한 항목만 고친 뒤 같은 입력으로 다시 실행한다. 그래야 우연한 재시작이나 캐시 효과를 해결로 잘못 기록하지 않는다.

    3. 실무에서 적용하는 순서

    먼저 DB healthcheck가 실제 쿼리 수락 가능성을 확인하도록 만든다. migration 서비스는 같은 앱 이미지를 사용해도 command를 별도로 두고 restart는 no로 둔다. 앱 depends_on은 migration의 service_completed_successfully를 기다리게 한다.

    1. migration 명령을 단독 실행해 성공과 실패 exit code를 확인한다.
    2. DB 의존성에는 service_healthy를 연결한다.
    3. migration을 일회성 서비스로 분리한다.
    4. 앱이 completed_successfully를 기다리게 한다.
    5. 의도적 migration 실패에서 앱이 시작되지 않는지 검증한다.
    docker compose run --rm migrate
    echo $?
    docker compose up -d
    docker compose ps --all

    운영 검증에서는 빈 DB, 이전 버전 DB, 이미 최신인 DB를 모두 테스트한다. 세 경우 모두 migration이 결정적으로 끝나고 앱이 같은 스키마 버전을 읽어야 한다.

    변경 뒤에는 깨끗한 시작과 기존 상태를 유지한 재시작을 모두 확인한다. 결과 표에는 기대 상태, 실제 상태, 첫 실패 시각, 마지막 성공 시각을 분리해 적는다. 이 네 값이 있어야 다음 배포에서도 같은 기준으로 회귀 여부를 판정할 수 있다.

    4. 공식 문서와 예시 화면으로 확인하기

    첫 자료에서는 일회성 의존 서비스가 성공 종료할 때까지 기다리는 조건을 확인한다. 화면의 강조된 문장이나 옵션을 현재 설정과 같은 이름의 필드로 대조한다.

    service_completed_successfully는 실행 중 상태가 아니라 exit code 0 완료를 기다린다.
    service_completed_successfully는 실행 중 상태가 아니라 exit code 0 완료를 기다린다.

    DB 준비와 migration 완료를 서로 다른 조건으로 연결해야 한다. 이 값을 변경 전 기록에 남기고 다음 단계의 성공 신호와 연결한다.

    두 번째 자료에서는 depends_on의 restart 속성이 명시적 Compose 작업과 연결되는 경계를 확인한다. 화면의 강조된 문장이나 옵션을 현재 설정과 같은 이름의 필드로 대조한다.

    의존성 재시작 옵션과 컨테이너 restart policy는 같은 설정이 아니다.
    의존성 재시작 옵션과 컨테이너 restart policy는 같은 설정이 아니다.

    migration을 매번 반복 실행해야 한다는 뜻으로 해석하지 않는다. 이 값을 변경 전 기록에 남기고 다음 단계의 성공 신호와 연결한다.

    시작 순서는 DB 준비, migration 성공, 앱 시작의 세 사건으로 나눈다. 화면의 강조된 문장이나 옵션을 현재 설정과 같은 이름의 필드로 대조한다.

    Compose 의존성 DAG와 성공 신호다.
    Compose 의존성 DAG와 성공 신호다.

    각 단계가 이전 단계의 정확한 완료 조건을 기다려야 한다. 이 값을 변경 전 기록에 남기고 다음 단계의 성공 신호와 연결한다.

    YAML에서는 DB와 migration, 앱의 역할을 각각 서비스로 분리한다. 화면의 강조된 문장이나 옵션을 현재 설정과 같은 이름의 필드로 대조한다.

    migration 성공 뒤에만 앱이 시작되는 Compose 예시다.
    migration 성공 뒤에만 앱이 시작되는 Compose 예시다.

    migration 명령은 재실행 안전성과 실패 exit code를 반드시 가져야 한다. 이 값을 변경 전 기록에 남기고 다음 단계의 성공 신호와 연결한다.

    마지막에는 성공 경로뿐 아니라 migration 실패 때 앱이 시작되지 않는지 확인한다. 화면의 강조된 문장이나 옵션을 현재 설정과 같은 이름의 필드로 대조한다.

    일회성 서비스 exit code와 앱 생성 상태를 확인하는 명령이다.
    일회성 서비스 exit code와 앱 생성 상태를 확인하는 명령이다.

    실패를 0으로 삼키는 shell 래퍼가 있으면 이 조건은 안전장치가 되지 못한다. 이 값을 변경 전 기록에 남기고 다음 단계의 성공 신호와 연결한다.

    5. 주의사항과 리스크

    이 설정은 여러 호스트나 여러 배포 파이프라인에서 동시에 실행되는 migration까지 잠그지 않는다. 애플리케이션 수준 advisory lock이나 배포 플랫폼의 단일 실행 job이 필요할 수 있다. 오래 걸리는 DDL, rollback 전략, 구버전 앱과의 호환 기간도 Compose 시작 순서만으로 해결되지 않는다.

    6. 결론

    안전한 순서는 DB running이 아니라 DB healthy, 그다음 migration exit 0, 마지막 앱 readiness다. 각 사건을 독립 서비스와 조건으로 표현하면 실패가 앱 로그에 숨지 않고 배포 중단 지점으로 드러난다.

    7. 참고 링크

    1. https://docs.docker.com/compose/how-tos/startup-order/
    2. https://docs.docker.com/reference/compose-file/services/
Designed by Tistory.