Files
baekjoon-bot/docs/OPERATIONS.md
sm4640 ac75dcce7e
All checks were successful
baekjoon-bot-cicd / build_push_deploy (push) Successful in 2m3s
Docs: [main] compose.apps.yml 파일에 대한 설명
2026-01-19 11:58:44 +09:00

5.7 KiB

Operations Guide

작성: AI / 수정: nkey

Supported Deployment Modes

  • Dockerfile 기반 단일 컨테이너 실행 (dockerfile)
  • (참고) 로컬에서 Uvicorn 직접 실행

Production Checklist

  • Secrets/ENV:
    • DATABASE_URL는 필수입니다.
    • Admin API를 운영에서 사용할 경우 ADMIN_PASSWORD를 반드시 설정하고, 클라이언트에서 X-Admin-Password 헤더로 전달해야 합니다.
  • Networking:
    • 인바운드: TCP 8000 (API)
    • 아웃바운드: solved.ac API, acmicpc.net(백준) 접근 필요(문제/문제집 정보 조회).
  • Storage:
    • 앱 자체는 로컬 파일 저장을 전제로 하지 않습니다.
    • DB는 외부 PostgreSQL을 사용합니다. (주의) 레포에 DDL/마이그레이션이 포함되어 있지 않으므로, 운영 DB 스키마는 별도로 준비되어 있어야 합니다.
  • Observability:
    • 기본 Uvicorn 로그(stdout) 기반. 별도 로깅/메트릭 구성은 레포에 없습니다.
  • Scaling:
    • /today의 search 모드는 DB 없이도 동작 가능(단, 코드상 DB 의존성 주입은 존재).
    • workbook 모드는 DB 상태(workbook_sends)에 의해 결과가 달라지므로, 다중 인스턴스 운영 시 동일 DB를 바라보도록 구성해야 합니다.

Deployment

Docker

# build (주의: 파일명이 'Dockerfile'이 아니라 'dockerfile' 입니다)
docker build -f dockerfile -t baekjoon-bot:prod .

# run
cat > .env <<'EOF'
DATABASE_URL=postgresql+asyncpg://USER:PASSWORD@HOST:5432/DBNAME
ADMIN_PASSWORD=change-me
EOF

docker run -d --name baekjoon-bot \
  --env-file .env \
  -p 8000:8000 \
  baekjoon-bot:prod

# verify
curl -s http://localhost:8000/ | cat

Operations

Healthcheck

  • GET /
    • 성공 조건: {"status":"ok"} 응답

Logs

  • Docker 실행 시:
docker logs -f baekjoon-bot

Security Notes (only with evidence)

  • Admin API는 X-Admin-Password 헤더 기반 단일 비밀번호 체크입니다.
    • ADMIN_PASSWORD가 비어 있으면 admin API 호출 시 500으로 실패합니다(설정 누락).
  • .env.gitignore에 포함되어 있어 커밋되지 않도록 되어 있습니다.

Incident Runbook (Top 5)

  1. env 누락
  • Symptom: 앱 시작 시 DATABASE_URL is required...로 즉시 종료
  • Cause: DATABASE_URL 미설정
  • Fix: .env 또는 런타임 환경변수에 DATABASE_URL 설정
  • Verify: 컨테이너/프로세스 정상 기동 후 GET /가 200
  1. 포트 충돌
  • Symptom: 컨테이너 실행 시 bind: address already in use 또는 접근 불가
  • Cause: 호스트 8000 포트 사용 중
  • Fix: -p 18000:8000 같이 호스트 포트 변경
  • Verify: curl http://localhost:18000/
  1. DB 연결 실패
  • Symptom: /today 또는 admin 호출 시 500, 로그에 DB 커넥션 에러
  • Cause: DATABASE_URL 잘못됨 / 네트워크/방화벽 / DB 다운
  • Fix: URL 재확인, DB 접근 허용, DB 상태 확인
  • Verify: /today?source_mode=workbook&workbook_id=...가 정상 응답(워크북 모드 사용 시)
  1. Admin 인증 실패
  • Symptom: admin API가 403 invalid admin password
  • Cause: X-Admin-Password 누락 또는 불일치
  • Fix: ADMIN_PASSWORD 값과 동일한 헤더 전달
  • Verify: POST /admin/workbooks/{id}/enrich가 200
  1. 문제집 소진
  • Symptom: GET /today?source_mode=workbook&workbook_id=...가 409 + no_more_problems_in_workbook
  • Cause: 해당 workbook에서 아직 보내지 않은 문제 후보가 없음(workbook_sends에 모두 기록됨)
  • Fix: 진행상황 초기화 API 호출(주의: 관리자 권한 필요) 또는 다른 workbook 사용
  • Verify: 초기화 후 workbook 모드 호출 시 정상 추천 반환

Supported Deployment Modes

  • (기존) Dockerfile 기반 단일 컨테이너 실행: dockerfile
  • (추가) Gitea Actions 기반 CI/CD: .gitea/workflows/cicd.yml
    • Docker Hub로 이미지 푸시 후,
    • 러너/서버에서 docker compose -f /nkeysworld/compose.apps.yml pull/up으로 배포

참고: 레포에는 Docker Compose 파일이 포함되어 있지 않습니다. CI/CD 배포는 서버에 존재하는 /nkeysworld/compose.apps.yml을 사용합니다.

Deployment

CI/CD (Gitea Actions)

Workflow: .gitea/workflows/cicd.yml

Trigger

  • main 브랜치로 pushbuild_push_deploy 잡 실행

What it does

  • (1) Manual checkout (Gitea /gitea 서브패스 고려)
  • (2) Docker Hub 로그인
  • (3) 이미지 빌드/푸시: ${DOCKERHUB_USERNAME}/baekjoon-bot:latest
  • (4) 배포: docker compose -f /nkeysworld/compose.apps.yml pull baekjoon-bot + up -d baekjoon-bot
  • (5) 정리: docker image prune -f
  • (6) 알림: Discord webhook (성공/실패 모두 전송)

Required Secrets

  • NKEY_PAT: https://${ACTOR}:${TOKEN}@nkeystudy.site/gitea/${REPO}.git fetch에 사용
  • DOCKERHUB_USERNAME, DOCKERHUB_TOKEN: docker login에 사용
  • DISCORD_WEBHOOK: 결과 알림 전송에 사용

Server/Runner Prerequisites

  • docker 실행 가능
  • docker compose 실행 가능(워크플로우에 설치 보완 단계가 있으나, 기본적으로 compose가 동작해야 함)
  • /nkeysworld/compose.apps.yml 파일이 존재해야 함
  • compose 내 서비스명이 baekjoon-bot 이어야 함(워크플로우가 해당 서비스만 pull/up 수행)

Rollback (workflow 기준)

  • 워크플로우는 :latest만 푸시/배포합니다.
  • 롤백을 하려면(운영 정책에 따라):
    • compose가 특정 태그로 pinning 되도록 변경하거나
    • latest 대신 태그 전략을 도입해야 합니다.

Operations

Notifications

  • CI/CD 결과는 Discord webhook(DISCORD_WEBHOOK)으로 전송됩니다.
    • 성공: Build & Deploy Success
    • 실패: Build or Deploy Failed
    • 포함 정보: repo, commit sha, actor, timestamp