문서 / docs/deployment-report.md

Phase 8 배포 검증 보고서

Phase 8 배포 검증 결과.

로컬 검증일: 2026-08-13 UTC 공개 배포일: 2026-08-14 UTC

이 보고서는 T063의 로컬 standalone candidate·rollback 훈련과 T064의 실제 systemd, Nginx, DNS, TLS, 공개 활성화 결과를 함께 기록한다.

실행 결과

  • bash tests/deploy/build-release.test.sh: PASS. standalone root, .next/static, optional public, manifest, 안전하지 않은 ID 거부, 기존 ID 비덮어쓰기와 current 불변을 확인했다.
  • bash tests/deploy/deploy.test.sh: PASS. 후보 health 실패 시 무활성화, 정상 후보 활성화, 가짜 service restart, 활성화 뒤 외부 smoke 실패와 이전 release 자동 복구를 확인했다.
  • ./deploy/build-release.sh --release-root "$HARNESS_RELEASE_ROOT" --release-id harness-local-20260813: PASS. verify:app, Next production build와 standalone bundle 검사를 거쳐 실제 release를 만들었다.
  • ./deploy/deploy.sh --release-root "$HARNESS_RELEASE_ROOT" --release-id harness-local-20260813 --candidate-port 3631 --check-only: PASS. 실제 Next standalone의 health, 네 페이지, robots, sitemap, same-origin 정적 자산과 복구 가능한 404가 통과했고 current link는 생성하거나 변경하지 않았다.
  • npm run verify: PASS — 단위 47건, 통합 28건, typecheck, lint, production build, standalone 경계와 배포 계약.
  • npm run test:browser: PASS — Chromium 49/49.
  • 운영 후보 harness-20260814-0b665e7-r2: 내부 health와 전체 smoke PASS.

T064 공개 배포 결과

  • DNS A: harness.insapien.co.kr → 승인된 현재 서버 endpoint로 권한 DNS와 공개 재귀 DNS에서 확인.
  • 전용 실행 계정: non-login harness 시스템 계정과 계정 소유 0600 환경 파일 설치.
  • systemd: 5240lab-harness.service 설치, enabled·active 확인. Node.js 24.18.0 사용.
  • Nginx: HTTP reverse proxy 설치 후 전체 nginx -t PASS.
  • TLS: Certbot 인증서 발급·자동 갱신 등록, 만료일 2026-11-12. 갱신 dry-run PASS. HTTP→HTTPS 301과 Strict-Transport-Security: max-age=31536000; includeSubDomains 확인.
  • bootstrap release harness-20260813-0b665e7를 먼저 외부 smoke해 최초 배포의 rollback 기준점으로 확보했다.
  • 2026-08-14 13:25:13 UTC에 harness-20260814-0b665e7-r2를 원자적으로 활성화했다. 배포 기록의 source commit은 296f80b52899, candidate·external 검사는 모두 passed, rollback은 not-required다.
  • GET https://harness.insapien.co.kr/api/health: PASS — active release ID와 근거 검증일 일치.
  • node scripts/smoke.mjs https://harness.insapien.co.kr --expect-release harness-20260814-0b665e7-r2: PASS — 네 페이지, health, robots, sitemap, 정적 자산과 복구 가능한 404 확인.

판정과 경계

  • 검증 release ID: harness-local-20260813
  • candidate health와 내부 smoke: PASS
  • fixture 기반 활성화 후 rollback: PASS, 이전 ID old-release 복구 확인
  • active launcher manifest ID와 health 기대 ID 일치: PASS
  • deployment record의 근거 검증일, source commit, 실제 current symlink 기록: PASS
  • release mode 정규화, 상대경로 checksum 재계산과 변조 후보 사전 거부: PASS
  • 지연된 활성/rollback readiness 재시도와 원자적 record write preflight: PASS
  • systemd와 Nginx 실제 설치/재시작: PASS
  • 외부 URL smoke, DNS와 TLS: PASS
  • 수동 복구가 필요했던 단계: 없음

따라서 T056~T064의 로컬·공개 release 계약은 검증 완료다. bootstrap 이전 release가 유지되어 다음 활성화 실패 시 자동 rollback 대상으로 사용할 수 있다.

후속 배포 이력 (2026-08-14 ~ 2026-08-17)

기록일: 2026-08-18 UTC 출처: 배포 스크립트가 활성화마다 원자적으로 남긴 배포 기록 파일.

위 판정은 최초 공개 배포까지의 것이다. 그 뒤 002 타이포그래피와 003 공개 문서 조회, 화면 문구 수정이 이어지며 열다섯 번의 활성화가 있었다. 아래는 그 전체 기록이다.

시각 (UTC) 릴리스 ID source commit 결과 candidate/external/rollback
2026-08-14 13:25 harness-20260814-0b665e7-r2 296f80b success passed / passed / not-required
2026-08-15 09:53 harness-20260815-bf7603c-r1 bf7603c success passed / passed / not-required
2026-08-16 00:44 harness-20260816-1ba3ee5-r1 1ba3ee5 failed passed / restart-failed / rollback-restart-failed
2026-08-16 00:45 harness-20260816-1ba3ee5-r1 1ba3ee5 success passed / passed / not-required
2026-08-17 05:05 harness-20260817-83270ff-r1 83270ff failed passed / restart-failed / rollback-restart-failed
2026-08-17 05:06 harness-20260817-83270ff-r1 83270ff success passed / passed / not-required
2026-08-17 05:16 harness-20260817-b2573d3-r2 b2573d3 success passed / passed / not-required
2026-08-17 09:13 harness-20260817-7f64693-r3 e42f0b8 success passed / passed / not-required
2026-08-17 09:45 harness-20260817-69206da-r4 cf389c1 success passed / passed / not-required
2026-08-17 10:44 harness-20260817-ab47256-r5 29c7139 success passed / passed / not-required
2026-08-17 11:03 harness-20260817-f0f3c6e-r6 22eb0a8 success passed / passed / not-required
2026-08-17 11:23 harness-20260817-65623bb-r7 bea234c success passed / passed / not-required
2026-08-17 11:29 harness-20260817-daaf20e-r8 fdcfbaf success passed / passed / not-required
2026-08-17 11:38 harness-20260817-baf8136-r9 b11f014 success passed / passed / not-required
2026-08-17 11:59 harness-20260817-a81727d-r10 5545db5 success passed / passed / not-required
2026-08-18 03:09 harness-20260818-b0ec86f-r1 b0ec86f success passed / passed(재시도 1회) / not-required

이 표는 기록을 쓴 시점까지의 활성화를 담는다. 지금 무엇이 돌고 있는지는 이 표가 아니라 GET /api/health의 releaseId와 배포 기록 디렉터리가 답한다 — 표를 고친 커밋은 그 자신을 배포하는 활성화보다 항상 한 걸음 앞서 쓰이므로, 마지막 줄이 곧 가동 릴리스라고 읽으면 언젠가 틀린다. 표는 이력이고, health가 현재다.

2026-08-18 03:09의 passed(재시도 1회)는 재시작 직후 첫 외부 스모크가 502를 받고 재시도에서 통과한 것이다. 배포 절차가 readiness를 정해진 횟수만큼 다시 확인하도록 설계돼 있어 자동으로 복구됐고, 수동 조치는 없었다.

두 번의 실패가 말해주는 것

08-16 00:44와 08-17 05:05의 실패는 후보 검사(candidate)는 통과했는데 서비스 재시작에서 막힌 것이다. 배포 계정에 서비스 재시작 권한이 없어서(polkit 규칙 미설정) 재시작이 거부됐고, 자동 rollback도 같은 이유로 재시작에 실패해 수동 복구가 필요했다. 두 경우 모두 직후(1분 이내) 재실행에서 성공했다.

  • 배운 것: 재시작 권한은 배포의 전제 조건이지 배포 중에 확인할 일이 아니다. 권한을 주는 래퍼를 쓰거나, 배포 앞단에서 재시작 가능 여부를 먼저 확인해야 한다.
  • 남은 위험: 권한 문제가 그대로면 다음 배포에서 같은 실패가 되풀이된다. 이 항목은 content/roadmap.ts의 "후보 release health·외부 스모크·롤백" 개선 과제와 이어진다.

003 이후 스모크 범위

외부 스모크는 이제 /, /guide, /5240lab, /roadmap, /docs와 문서 상세 한 편까지 확인한다. 문서 상세 경로는 매니페스트의 특정 항목과 결합돼 있어, 그 항목의 묶음·이름이 바뀌면 스모크가 막힌다. 스모크가 그 경로에서 실패하면 매니페스트를 먼저 본다.

맨 위로