Skip to content

[Chore] API CI/CD 리팩토링 및 AWS EC2 배포 전환 - #88

Merged
JangDongHo merged 10 commits into
devfrom
chore/api-cicd-aws
Sep 24, 2026
Merged

JangDongHo merged 10 commits into
devfrom
chore/api-cicd-aws

Conversation

@JangDongHo

@JangDongHo JangDongHo commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

📌 개요

  • API 배포 대상을 GCP VM에서 AWS EC2(/opt/connectgnu/api)로 전환하고, GitHub Actions CI/CD를 CI 통과 → 이미지 빌드/푸시 → 배포 → 헬스체크 흐름으로 정리했습니다.
  • 운영 docker-compose.yml과 nginx/prod.conf를 EC2 서버 반영본으로 동기화했습니다.

✨ 작업 내용

CI (api-ci.yml)

  • workflow_call 트리거를 추가해 CD에서 재사용하도록 전환했습니다.
  • job을 verify로 바꾸고 lint → test 뒤에 pnpm build 검증을 추가했습니다.
  • pnpm 버전을 app/package.json의 packageManager에서 읽도록 하고 액션을 최신 메이저로 올렸습니다.

CD (api-cd.yml)

  • ci → build-and-push → deploy 순서로 실행해 CI를 통과한 커밋만 배포합니다.
  • 이미지 빌드에 target: prod를 명시하고 빌드에 영향을 주는 경로(.dockerignore, tsconfig*.json, nest-cli.json)를 트리거에 추가했습니다.
  • 배포 concurrency(cancel-in-progress: false)로 진행 중인 배포가 취소되지 않게 했습니다.
  • 배포 대상은 /opt/connectgnu/api로, docker compose(v2) 문법을 쓰고 sudo는 제거했습니다.
  • 서버에는 docker-compose.yml, nginx/prod.conf만 동기화합니다. letsencrypt/, .env는 건드리지 않습니다.
  • 배포 후 app 헬스체크를 최대 약 90초 기다리고, unhealthy이거나 healthcheck가 없으면 로그를 출력하고 실패합니다.
  • nginx 설정은 일회성 컨테이너(compose run --rm)로 nginx -t를 먼저 검사하고, 통과하면 반영하고 reload합니다.
  • image prune -af를 -f로 바꿨습니다.

운영 설정

  • gcplogs를 제거하고 모든 서비스를 json-file 로깅(10m × 3)으로 통일했습니다.
  • nginx 설정을 단일 파일 마운트에서 디렉터리 마운트(./nginx:/etc/nginx/conf.d:ro)로 변경했습니다.
  • prod.conf 도메인을 api.connectgnu.kro.kr로 통일하고 /api/metrics IP 제한을 유지했습니다.

기타

  • 루트 test:api/test:mobile 스크립트를 pnpm --dir <pkg> exec jest --runInBand로 변경했습니다. mobile은 packageManager가 없어 최신 pnpm이 실행되는데, 이 버전이 --를 jest에 그대로 넘겨 No tests found로 pre-push 훅이 실패하던 문제입니다. (pnpm 9는 반대로 -- 없이는 --runInBand를 pnpm 옵션으로 해석)

문서

  • 설계: docs/superpowers/specs/2026-09-24-api-cicd-aws-migration-design.md
  • 구현 계획: docs/superpowers/plans/2026-09-24-api-cicd-aws-migration.md

🔥 변경 이유

  • gcplogs 로깅 드라이버는 AWS에서 동작하지 않아 컨테이너 기동이 실패합니다.
  • 기존 CD는 테스트 없이 main push만으로 바로 배포했고, 배포 후 앱이 정상인지 확인하지 않았습니다.
  • 단일 파일 bind mount는 scp가 파일을 새로 만들면(inode 변경) 컨테이너가 예전 파일을 계속 참조하므로, reload해도 prod.conf 변경이 반영되지 않습니다.
  • 먼저 nginx를 올리고 nginx -t를 하면, 잘못된 설정일 때 재생성된 nginx가 crash-loop로 80/443을 내립니다. 검사를 먼저 하도록 순서를 바꿨습니다.
  • target: prod는 Dockerfile 단계 순서가 바뀌어도 운영 이미지가 개발 단계로 빌드되지 않도록 명시했습니다.

🧪 테스트

  • 정상 동작 확인
  • 예외 케이스 확인
  • actionlint: api-ci.yml, api-cd.yml 통과
  • services/api/app에서 pnpm lint:check, pnpm test(74/74), pnpm build 통과
  • docker build --target prod 통과
  • docker compose config 통과, prod.conf만 담은 디렉터리로 nginx -t 통과(dev.conf가 섞이면 duplicate upstream 실패 확인)
  • 헬스 대기 로직 로컬 시뮬레이션: healthy → exit 0, unhealthy → exit 1(약 3초), healthcheck 없음 → exit 1(즉시)
  • nginx 검사 순서 시뮬레이션: 변경 전에는 잘못된 설정에서 nginx crash-loop 발생, 변경 후에는 배포가 중단되고 기존 nginx가 유지됨
  • 배포 스크립트 bash -n, shellcheck 통과
  • 루트 pnpm test: api 74/74, mobile 7/7 통과

머지 전 확인 (배포 사전 조건)

  • GitHub Secrets API_SSH_HOST(EC2 EIP), API_SSH_USERNAME(ec2-user), API_SSH_PRIVATE_KEY 교체
  • EC2: docker compose version, ec2-user의 docker 그룹 소속, 로그인 셸이 bash
  • EC2: /opt/connectgnu/api/nginx/에 prod.conf만 있음, letsencrypt/conf/live/api.connectgnu.kro.kr-0001 존재

참고

  • 첫 배포 때 nginx 볼륨 정의가 바뀌어 nginx 컨테이너가 한 번 재생성됩니다(1~2초 끊김 가능).
  • 범위 밖: 자동 롤백, SHA 태그 배포, batch/monitoring 배포

🔗 관련 이슈

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 배포 및 안정성
    • 배포 전 린트·테스트·빌드를 수행하고, 앱 상태와 Nginx 설정을 확인한 뒤 배포하도록 개선했습니다.
    • 로그 용량을 관리하고, Nginx 설정 변경을 반영하도록 배포 절차를 정비했습니다.
  • 서버 설정
    • API 도메인과 SSL 인증서 설정을 갱신했습니다.
    • API 문서와 메트릭 경로의 IP 접근 제한이 제거되었습니다.
  • 문서
    • API 배포 파이프라인의 설계와 실행 계획을 추가했습니다.

@coderabbitai

coderabbitai Bot commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Repository: GNU-connect/Server-Node/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 807afd64-1d53-4092-aa11-85cff9e4cf39

📥 Commits

Reviewing files that changed from the base of the PR and between 887a270 and 12b0fab.

📒 Files selected for processing (7)
  • .github/workflows/api-cd.yml
  • .github/workflows/api-ci.yml
  • docs/superpowers/plans/2026-09-24-api-cicd-aws-migration.md
  • docs/superpowers/specs/2026-09-24-api-cicd-aws-migration-design.md
  • package.json
  • services/api/docker-compose.yml
  • services/api/nginx/prod.conf
 ____________________________________________
< 99 little bugs in the code... I filed 100. >
 --------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

JangDongHo and others added 10 commits September 24, 2026 22:02
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- app healthcheck, nginx depends_on 유지
- gcplogs 제거, 전 서비스 json-file 로깅(10m x 3)으로 통일
- prod.conf 도메인 api.connectgnu.kro.kr로 통일, /api/metrics 접근 제한 유지

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
잘못된 설정이 배포될 때 nginx가 재생성되며 crash-loop로 80/443이 내려가는 문제를 막는다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JangDongHo
JangDongHo merged commit 3f5eacc into dev Sep 24, 2026
2 checks passed
@JangDongHo
JangDongHo deleted the chore/api-cicd-aws branch September 25, 2026 08:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant