둘 이상의 시작 경로, 컨테이너 또는 스케줄러가 동일한 업그레이드 단계를 자신이 담당한다고 판단하면 데이터베이스 마이그레이션이 두 번 실행될 수 있습니다.
셀프 호스팅 애플리케이션은 엔트리포인트, 웹 프로세스, 워커, 사이드카, systemd 유닛 또는 배포 훅에서 마이그레이션을 시작하는 경우가 많습니다. 재배포 후 기존 컨테이너가 새 컨테이너와 겹쳐 실행되거나, 재시작 정책이 실패한 마이그레이션 실행기를 다시 시작하거나, 한 복제본이 완료 상태를 기록하기 전에 두 복제본이 데이터베이스에 도달할 수 있습니다. 데이터 복구를 시작하기 전에 모든 잠재적 실행기를 식별하고, 마이그레이션 프레임워크가 영구 잠금 또는 스키마 기록을 사용하는지 입증해야 합니다.
마이그레이션을 시작할 수 있는 모든 프로세스 식별
이미지 엔트리포인트, Compose 명령, 워커 명령, systemd 유닛, cron 작업, 배포 스크립트 및 애플리케이션 시작 로그에서 마이그레이션 명령을 검색합니다. 두 실행 시점의 프로세스 ID와 컨테이너 이름을 기록합니다.
Docker Compose는 선언된 종속성에 따라 서비스를 시작할 수 있지만, 시작 순서만으로 애플리케이션 수준의 마이그레이션 단일 소유자가 보장되지는 않습니다. 공식 시작 순서 안내는 데이터베이스를 사용할 수 있는 상태와 마이그레이션을 단일 프로세스가 독점적으로 담당하는 것이 서로 다른 조건임을 보여줍니다.
웹 엔트리포인트와 전용 마이그레이션 서비스에 동일한 명령이 모두 있다면 한쪽 소유자를 제거합니다. 명령이 하나뿐이라면 복제본, 재시작 루프 및 마이그레이션 상태 기록을 계속 확인합니다.
기존 컨테이너와 새 컨테이너의 중복 실행 확인
배포 중 실행 중이거나 재시작 중인 컨테이너, 종료된 컨테이너 및 고아 컨테이너를 나열합니다. 프로젝트 이름, 서비스 이름, 컨테이너 ID 및 생성 타임스탬프를 비교합니다.
systemd는 유닛 설정에 따라 서비스 재시작 정책이 실패한 명령을 다시 실행할 수 있다고 설명합니다. systemd의 서비스 재시작 모델은 컨테이너에서 실행된 시도가 0이 아닌 종료 코드로 끝난 후 호스트 실행기가 마이그레이션을 다시 실행할 수 있는 이유를 설명합니다.
로그를 보존한 후에만 고아 실행기로 입증된 항목을 제거합니다. 첫 번째 실행 직후에 두 번째 마이그레이션 타임스탬프가 나타난다면 별도의 예약 작업이 아니라 재시도일 가능성이 높습니다.
스키마 변경 적용 전에 데이터베이스 잠금 사용
애플리케이션이 마이그레이션 상태를 읽고 변경 사항을 적용하기 전에 데이터베이스 수준의 잠금을 획득하는지 확인합니다. 폐기 가능한 환경에서 두 번의 동시 시작 시도를 테스트합니다.
PostgreSQL은 애플리케이션 정의 조정을 위한 advisory lock을 제공하므로 두 마이그레이션 실행기가 거의 동시에 시작되더라도 한 실행기가 다른 실행기를 배제할 수 있습니다.
잠금은 전체 판단 및 실행 구간을 포함해야 합니다. 잠금을 획득하기 전에 현재 스키마 버전을 확인하면 두 실행기가 동일한 보류 중인 마이그레이션을 선택할 수 있습니다.
MySQL 또는 MariaDB에서 잠금 의미 확인
MySQL 호환 애플리케이션의 경우 마이그레이션 도구가 이름 기반 잠금, 트랜잭션 또는 잠금 테이블을 사용하는지, 그리고 전체 마이그레이션 동안 연결이 유지되는지 확인합니다.
MySQL은 연결 범위 이름 기반 잠금을 설명합니다. 이 잠금은 소유 세션이 종료되면 해제되므로 충돌이나 재시작 후 안전하게 다시 획득해야 합니다.
마이그레이션 프레임워크가 완료 상태를 기록하기 전에 연결에 장애가 발생하면 잠금이 해제될 수 있습니다. 이 순서를 확인하려면 데이터베이스 로그와 컨테이너 재시작 타임스탬프를 비교합니다.
마이그레이션 프레임워크의 이력 테이블 검사
마이그레이션 식별자, 실행 순서, 성공 플래그, 체크섬 및 타임스탬프를 나열합니다. 로그에 기록된 두 번의 실행과 실제로 데이터베이스에 커밋된 기록을 비교합니다.
Flyway는 스키마 이력 테이블을 사용하여 적용된 마이그레이션과 해당 상태를 추적합니다.
첫 번째 실행이 스키마를 변경했지만 성공 상태를 기록하기 전에 실패했다면, 두 번째 실행은 멱등성이 보장되지 않은 마이그레이션을 다시 시도할 수 있습니다. 이력을 복구하기 전에 실제 스키마를 마이그레이션의 예상 결과와 비교합니다.
변경 로그 식별자와 체크섬 변경 확인
이미지 업데이트 전후의 마이그레이션 파일 이름, ID, 작성자, 경로 및 체크섬을 비교합니다. 이미지에 중복되거나 이름이 변경된 변경 로그 항목이 포함되어 있는지 확인합니다.
Liquibase는 DATABASECHANGELOG 테이블에 실행된 변경 사항을 기록하며, 변경 사항의 식별 정보는 ID, 작성자 및 파일 경로에 따라 결정됩니다.
변경 로그 파일을 이동하거나 식별자를 다시 생성하면 SQL이 유사하더라도 기존 작업이 새로운 작업으로 인식될 수 있습니다. 광범위한 이력 범위를 수동으로 삭제하지 말고 안정적인 마이그레이션 식별자를 복원합니다.
마이그레이션 소유자 한 명으로 재배포하고 멱등성 확인
마이그레이션 소유자를 한 명으로 정하고, 영구 잠금을 추가하며, 웹 및 워커 서비스가 성공적인 완료를 기다리도록 설정한 후 데이터베이스 테스트 복사본에 재배포합니다.
ZimaSpace의 컨테이너 스케줄링 경계 문서는 관련 원칙을 제시합니다. 하나의 유지 관리 작업에는 검증된 실행 소유자가 한 명만 있어야 합니다.
동시 또는 반복 시작으로 마이그레이션 하나만 적용되고, 영구적인 이력 기록 하나만 남으며, 재시작 후 두 번째 스키마 변경이 발생하지 않으면 문제가 해결된 것입니다.
자주 묻는 질문
마이그레이션을 두 번 실행하면 항상 데이터베이스가 손상되나요?
아닙니다. 멱등성 마이그레이션은 기존 객체를 안전하게 감지할 수 있지만, 멱등성이 없는 데이터 변환, 인덱스 생성 또는 열 변경은 실패하거나 데이터를 중복할 수 있습니다.
모든 웹 복제본에서 마이그레이션을 실행하도록 허용해야 하나요?
프레임워크가 안정적인 데이터베이스 수준 조정을 제공하는 경우에만 허용해야 합니다. 홈 서버 배포에서는 전용 일회성 마이그레이션 소유자가 감사하기 더 쉽습니다.
마이그레이션을 수동으로 완료 처리해도 되나요?
실제 스키마와 데이터가 마이그레이션의 예상 결과와 일치한다는 것을 입증한 경우에만 가능합니다. 이력을 먼저 편집하면 일부만 적용된 변경 사항이 숨겨질 수 있습니다.
지원 및 팁
더 읽어보기

Docker 볼륨을 복원하면 파일 내용은 복원되지만 확장 속성은 사라지는 이유는 무엇인가요?
xattr 인벤토리, tar 및 Rsync 옵션, 네임스페이스, 대상 지원, 권한, 레이블, 앱 메타데이터와 테스트를 다루는 볼륨 복원 진단.

Compose 파일을 변경한 후에도 실행 중인 컨테이너의 메모리 제한이 기존 값으로 유지되는 이유는 무엇인가?
실행 중인 cgroup, 재시작과 재생성, Compose 필드, 하드 및 소프트 제한, 상위 범위, 스왑, 런타임 힙을 다루는 메모리 제한 진단입니다.

리버스 프록시를 재시작하면 셀프 호스팅 앱 하나의 모든 세션이 무효화되는 이유는 무엇인가요?
재시작 범위, 쿠키 소유권, 비밀 키 순환, 캐시 기반 세션, 스티키 라우팅, 인증 게이트웨이 및 복구를 다루는 세션 손실 진단.

