콘텐츠로 이동

API 운영 배포 런북

문서 역할

  • 역할: 시나리오
  • 문서 종류: flow
  • 충돌 시 우선 문서: 릴리스 프로세스
  • 기준 성격: as-is

목적

  • coupler-apimain 계보에서 릴리스 기록에 고정한 commit을 운영 PM2 production 설정으로 배포·검증한다.

범위

  • 시작 조건: 운영 릴리스 실행 런북의 공통 preflight가 같은 입력으로 PASS했고 운영 EC2 접근·package 인증이 준비된 상태
  • 종료 조건: exact commit이 PM2 production 설정으로 실행되고 내부·외부 smoke와 로그 확인이 끝난 상태
  • 제외 범위: DB migration, Admin 정적 artifact, Mobile, 서비스 태그

실행 흐름

운영 배포와 릴리스 기록이 허용한 previous-release rollback은 각각의 exact TARGET_COMMIT을 고정하고 운영 EC2에 접속한 뒤 sudo -i로 전환한 새 root login shell에서 같은 블록을 실행한다. 운영 repo와 PM2 process namespace가 root 소유이므로 ubuntu shell에서 fetch·install·PM2 명령을 실행하지 않는다. 기능별 smoke와 적용 지표는 릴리스 기록 또는 해당 도메인 문서가 소유한다.

set -euo pipefail
: "${TARGET_COMMIT:?set TARGET_COMMIT}"
[[ "${TARGET_COMMIT}" =~ ^[0-9a-f]{40}$ ]]
test "$(id -u)" -eq 0

DEPLOY_ROOT=/home/projects/coupler-api
cd "${DEPLOY_ROOT}"
test "$(pwd -P)" = "${DEPLOY_ROOT}"

test -z "$(git status --porcelain)"
git fetch --no-tags origin main:refs/remotes/origin/main

git merge-base --is-ancestor "${TARGET_COMMIT}" origin/main
git checkout --detach "${TARGET_COMMIT}"

pnpm install --frozen-lockfile
pm2 startOrReload ./pm2.json --env production --only coupler-api
pm2 save
PM2_STATE="$(
  pm2 jlist | node -e '
    let input = "";
    process.stdin.on("data", (chunk) => { input += chunk; });
    process.stdin.on("end", () => {
      const app = JSON.parse(input).find((item) => item.name === "coupler-api");
      process.stdout.write([
        app?.pm2_env?.status ?? "",
        app?.pm2_env?.NODE_ENV ?? "",
        app?.pm2_env?.pm_cwd ?? "",
      ].join("|"));
    });
  '
)"
test "${PM2_STATE}" = "online|production|${DEPLOY_ROOT}"

curl --retry 10 --retry-all-errors --retry-delay 1 \
  --fail-with-body --show-error -i http://127.0.0.1:3002/
curl --fail-with-body --show-error -i https://api.ritzy.fourhundred.co.kr/
pm2 logs coupler-api --lines 100 --nostream

exact commit, action, PM2 상태, 내부·외부 응답과 릴리스 기록의 기능별 smoke·지표를 모두 증빙한다. 하나라도 실패하면 배포 완료나 서비스 태그 가능 상태로 판정하지 않는다.

API source 배포는 운영 root crontab을 변경하거나 매 릴리스마다 재검증하지 않는다. cron route·주기가 바뀌는 릴리스만 Cron 작업의 현재 계약과 해당 운영 변경 검증을 별도로 적용한다.

예외 흐름

  • install 또는 PM2 반영이 중단되면 블록을 처음부터 재실행하지 않는다. checkout, PM2 상태, 내부·외부 응답과 로그로 실제 반영 지점을 먼저 확인한다.
  • rollback은 릴리스 기록이 exact commit과 현재 TARGET DB 계약의 호환성을 증명한 경우에만 수행한다. 근거가 없으면 forward fix를 사용한다.

비포함 / 금지

  • 운영에서 node app.ts 또는 pm2 start app.tspm2.jsonprestart 검사를 우회하지 않는다.
  • 개발계 성공을 운영 배포·검증 또는 서비스 태그 근거로 사용하지 않는다.
  • DB migration 뒤 이전 API 복구 가능성을 API 응답만으로 추론하지 않는다.

관련 문서