배포 점검과 변경 기록
80분 안팎
학습 목표
권한·CRUD·롤백 점검과 리뷰 자료를 정리합니다.
개념
배포 승인은 성공 문장보다 근거를 봅니다
새 동아리 API가 /books에서 200을 반환한다고 배포 점검을 마치면 로그인이나 권한 경계가 깨진 변경을 놓칠 수 있습니다. 배포 담당자는 변경된 파일, 실제 선택된 릴리스, 환경 설정, 데이터의 상태를 연결하여 리뷰 자료를 만듭니다. 이번 레슨은 실행을 자동 승인하는 도구가 아니라 검증 가능한 전환·복구 절차를 작성하는 연습입니다. 로컬 실습은 릴리스 선택의 실패 경계를 검사하고 모듈 미션은 실제 컨테이너 HTTP 계약을 이어서 확인합니다.
릴리스 파일을 덮어쓰지 않습니다
old.jar와 candidate.jar를 별도로 보관하고 각각의 SHA-256을 old.sha256과 candidate.sha256에 기록합니다. 현재 선택은 current.txt에 릴리스 이름 한 줄로 저장합니다. 새 파일을 기존 이름 위에 바로 덮으면 복구에 필요한 이전 바이트를 잃을 수 있습니다. 현재 선택과 보관 파일을 분리하면 어떤 파일을 실행해야 하는지 명확해집니다. 파일이 있다는 사실만으로 안전하다고 보지 않고 읽은 해시가 기록과 일치한 뒤에만 선택을 바꿉니다.
해시는 무결성 근거이지 출처 인증이 아닙니다
SHA-256이 다르면 전송이나 보관 중 파일이 변했거나 잘못된 파일을 선택한 것입니다. release.py는 CHECKSUM_MISMATCH로 실패하고 current.txt를 유지해야 합니다. 공격자가 jar와 해시 파일 모두를 수정할 수 있으면 해시 비교만으로 출처를 보장할 수 없습니다. 릴리스 디렉터리를 신뢰한 담당자만 쓰게 하는 권한도 전제입니다. 제출 자료에는 jar 해시와 검증 시점을 함께 기록하여 테스트한 파일과 선택한 파일의 연결을 리뷰어가 확인하도록 합니다.
입력 이름을 경로로 바로 사용하지 않습니다
release.py는 릴리스 이름을 소문자·숫자와 하이픈으로 제한합니다. ../escape 같은 문자열을 경로에 그대로 붙이면 릴리스 디렉터리 밖을 읽게 될 수 있으므로 파일 접근 전에 거절합니다. old.jar 또는 해시 파일이 없으면 MISSING_RELEASE로 실패합니다. 사용자가 지정한 값이 실제 내부 파일과 어떻게 연결되는지 살피는 것은 API 입력 검증과 같은 태도입니다. 이번 과제는 로컬 배포 담당자의 입력이어도 잘못된 이름과 없는 버전을 경계 사례로 검사합니다.
선택 파일 교체와 서비스 전환을 구분합니다
current.tmp에 새 이름을 모두 쓰고 flush와 fsync를 한 뒤 같은 디렉터리의 current.txt로 os.replace합니다. 중간까지 쓰인 문자열을 독자가 읽는 상황을 줄이는 방법입니다. 이것이 프로세스의 교체, DB 트랜잭션, 정전 시 모든 디렉터리 메타데이터의 영속성을 함께 보장하는 것은 아닙니다. 병렬 선택자는 이 실습의 범위에서 제외합니다. 실제 실행기는 선택 파일을 읽어 해당 jar를 사용해야 하며 선택을 바꾼 것만으로 이미 실행 중인 Java가 바뀌지는 않습니다.
작은 과제는 선택 경계를 결정적으로 검사합니다
check.sh는 임시 폴더에 실행 불가능한 작은 바이트 fixture를 만들고 해시를 계산합니다. old 선택, candidate 선택, 손상된 old 거절, 경로 탈출 거절, 없는 버전 거절, old 복구의 여섯 상황을 확인합니다. fixture를 진짜 API 실행 파일로 오해하지 않습니다. starter의 누락된 해시 검사 때문에 손상 파일이 선택되어 테스트가 실패합니다. 실패 뒤 current.txt가 candidate로 유지되는지도 검사하여 오류 메시지만 맞추고 상태는 바꾸는 결함을 잡습니다.
HTTP 점검은 정상과 거부를 같이 봅니다
미션의 initial 단계는 익명 도서 조회와 로그인, 로그인 전 /me 거부를 확인합니다. candidate 단계는 CSRF 토큰을 가져와 로그인하고 새 토큰으로 대여합니다. 201의 ID와 Location을 확인한 뒤 같은 키 재생, 다른 본문 409, 다른 회원 404, 일반 회원의 도서 추가 403, 토큰 없는 쓰기 403을 검사합니다. 성공 요청만 확인하면 권한을 풀어 놓은 변경이 더 잘 동작하는 것처럼 보일 수 있습니다. 각 거부에는 어떤 보안 경계가 작동했는지 근거를 붙입니다.
클라이언트 상태도 전환의 일부입니다
세션과 CSRF 토큰은 브라우저 또는 HTTP 클라이언트 상태입니다. 로그인 뒤에는 인증 상태가 달라져 토큰을 다시 읽습니다. 컨테이너를 다시 만들면 메모리 세션이 사라질 수 있으므로 복구 검사에서도 다시 로그인합니다. 기존 쿠키로 계속 요청하다 401을 받았다고 DB 데이터가 사라졌다고 판단하지 않습니다. 데이터 이력의 영속성과 세션 수명은 서로 다릅니다. 또한 멱등 요청은 로그인 회원과 요청 키 범위에 묶여 있으므로 같은 표본 회원으로 재생을 확인합니다.
복구의 의미를 데이터와 함께 정의합니다
미션은 이전 컨테이너를 정상 종료하고 old 선택을 복원한 뒤 같은 named volume으로 기동합니다. 도서 목록과 회원의 대여 이력이 남고 기존 요청 키가 같은 결과를 재생하는지 확인합니다. old는 앞 모듈 소스에 패키징과 격리 데이터 준비 하네스를 더한 기준 jar이고 candidate는 이번 jar입니다. 별도로 빌드한 두 해시가 다른지 확인합니다. 스키마를 변경하지 않은 두 산출물의 계약 유지가 검증 범위이며 모든 과거 버전의 호환성을 보장하지 않습니다. 실제 배포했던 이전 파일로 확장할 때는 DB 읽기·쓰기 호환을 별도 리허설해야 합니다.
DB 변경이 있으면 jar 복구만으로 끝나지 않습니다
새 버전에서 컬럼을 삭제하거나 데이터 의미를 바꾸면 이전 jar가 같은 DB를 읽지 못할 수 있습니다. 그러면 파일 선택을 되돌려도 서비스 복구는 실패합니다. 배포 전에 추가형 변경인지, 두 버전이 같은 스키마를 사용할 수 있는지, 별도 데이터 복원이 필요한지 리뷰합니다. 이번 미션은 이전 스키마를 유지하여 jar 선택 절차에 집중합니다. 백업 복원과 허용할 데이터 손실 범위는 다음 모듈의 주제이며, 복구 계획에 그 검증이 아직 필요하다면 제한으로 적습니다.
리뷰 요청에는 재실행 가능한 자료를 둡니다
REVIEW.md에는 변경 이유, 이전 대비 수정 파일, jar 해시, JDK·Boot·이미지 식별 정보, 테스트 집계, HTTP별 기대와 실제, 실패 시 중단 지점, 복구 순서, 남은 제한을 작성합니다. 명령은 README-M09.md와 check.sh에서 다시 실행할 수 있어야 합니다. 실행 못 한 항목을 성공으로 채우지 않고 외부 확인 필요로 남깁니다. diff는 변경 범위를 찾는 데 쓰되 비밀값이 포함된 설정 전체를 붙이지 않습니다. 리뷰어는 사람의 판단을 요구하는 DB 호환성과 증거의 범위를 먼저 확인할 수 있습니다.
따라하기
손상 파일 검사 실패를 재현합니다
starter에서 실행합니다. 해시가 바뀐 old 선택이 성공하여 assertion이 실패한 위치를 찾습니다. fixture는 실행 불가능한 바이트 표본입니다.
bash check.sh무결성 경계를 구현합니다
release.py의 TODO에서 actual과 expected가 다르면 sys.exit("CHECKSUM_MISMATCH")로 끝냅니다. current.tmp를 만드는 코드보다 먼저 검사합니다.
선택과 복구를 검증합니다
아래는 solution의 실제 결과입니다. 수정 뒤 손상 파일과 없는 버전이 current.txt를 바꾸지 않는지 테스트 코드를 함께 확인합니다.
bash check.sh실행 결과
PASS: release selection 6 cases
미션의 리뷰 자료를 작성합니다
모듈 미션 starter를 별도로 내려받아 그 폴더에서 진행합니다. README-M09.md를 따라 REVIEW.md에 변경 이유·해시·테스트·HTTP 기대/실제·복구 범위를 작성합니다. Docker가 준비된 환경에서 미션 검사를 실행하고 앞 모듈 기준 157개와 candidate 161개 검사·두 jar 해시·외부 실행 결과를 남기고 스키마 변경 호환성은 별도 검토 사항으로 표시합니다.
bash check.sh확인 문제
실습
release.py의 해시 불일치 TODO를 구현합니다. 손상·누락·경로 탈출에서 current.txt가 바뀌지 않고 이전 선택으로 복구되는지 확인합니다. 바이트 fixture 검사와 실제 미션 HTTP 검증의 차이를 설명하고 복구 순서·중단 기준을 제출합니다.
실행 명령
bash check.sh
기대 결과
PASS: release selection 6 cases
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 실행 환경에서 API 오류를 추적하는 순서를 설명합니다.