Merge pull request #88 from Team-Senifit/release-1.0.1 #53
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI/CD Deploy | |
| on: | |
| push: | |
| branches: ["develop"] | |
| workflow_dispatch: {} | |
| concurrency: | |
| group: deploy-develop | |
| cancel-in-progress: true | |
| jobs: | |
| build-and-deploy: | |
| runs-on: ubuntu-latest | |
| env: | |
| APP_DIR: /srv/senifit-front | |
| RELEASE_NAME: ${{ github.sha }} | |
| NODE_ENV: production | |
| NEXT_PUBLIC_API_BASE: ${{ secrets.NEXT_PUBLIC_API_BASE }} | |
| NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }} | |
| API_PREFIX: ${{ secrets.API_PREFIX }} | |
| NEXT_PUBLIC_SITE_URL: ${{ secrets.NEXT_PUBLIC_SITE_URL }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22.x" | |
| cache: "npm" | |
| - name: Install deps | |
| run: npm ci | |
| - name: Build | |
| run: npm run build | |
| # next는 dependencies에 있어야 함. devDeps는 제거해 산출물 슬림화 | |
| - name: Prune devDependencies | |
| run: npm prune --omit=dev | |
| - name: Create deploy package | |
| run: | | |
| set -euo pipefail | |
| mkdir -p deploy | |
| # 실행에 필요한 산출물만 포함 (.next, node_modules, 정적파일, 설정) | |
| cp -r .next node_modules package.json package-lock.json public next.config.* deploy/ 2>/dev/null || true | |
| tar -C deploy -czf release.tgz . | |
| - name: Add SSH key | |
| uses: webfactory/ssh-agent@v0.9.0 | |
| with: | |
| ssh-private-key: ${{ secrets.EC2_SSH_KEY }} | |
| - name: Known hosts | |
| run: | | |
| set -euo pipefail | |
| mkdir -p ~/.ssh | |
| ssh-keyscan -H "${{ secrets.EC2_HOST }}" >> ~/.ssh/known_hosts | |
| - name: Remote prep (cleanup & prepare) | |
| env: | |
| EC2_USER: ${{ secrets.EC2_USER }} | |
| EC2_HOST: ${{ secrets.EC2_HOST }} | |
| run: | | |
| ssh "$EC2_USER@$EC2_HOST" bash -se <<'PREP' | |
| set -euo pipefail | |
| echo "==== System Health Check ====" | |
| df -h / | |
| free -m | |
| APP_DIR="/srv/senifit-front" | |
| echo "==== Cleanup Old Releases ====" | |
| # 폴더가 없으면 생성 | |
| if [ ! -d "$APP_DIR/releases" ]; then | |
| sudo mkdir -p "$APP_DIR/releases" "$APP_DIR/shared" | |
| sudo chown $USER:$USER "$APP_DIR" "$APP_DIR/releases" "$APP_DIR/shared" | |
| fi | |
| cd "$APP_DIR/releases" | |
| # 최신 3개 제외 나머지 리스트업 | |
| OLD_RELEASES=$(ls -1t | tail -n +4) | |
| if [ -z "$OLD_RELEASES" ]; then | |
| echo "No old releases to clean up." | |
| else | |
| for rel in $OLD_RELEASES; do | |
| echo "Removing old release: $rel" | |
| # current와 중복 여부 체크 (안전을 위해) | |
| CURR="$(readlink -f "$APP_DIR/current" || true)" | |
| REL_PATH="$(readlink -f "$rel")" | |
| if [ "$REL_PATH" != "$CURR" ]; then | |
| rm -rf "$rel" || echo "Warning: Failed to remove $rel" | |
| else | |
| echo "Skipping current release: $rel" | |
| fi | |
| done | |
| fi | |
| # current가 아닌 릴리즈 내부의 캐시 정리 | |
| echo "==== Optimizing Passive Releases ====" | |
| CURR="$(readlink -f "$APP_DIR/current" || true)" | |
| for d in "$APP_DIR"/releases/*; do | |
| [ -d "$d" ] || continue | |
| if [ "$(readlink -f "$d")" != "$CURR" ]; then | |
| echo "Cleaning cache/modules in inactive release: $(basename "$d")" | |
| rm -rf "$d/.next/cache" "$d/node_modules" || true | |
| fi | |
| done | |
| PREP | |
| - name: Remote deploy (stream extract, swap, restart) | |
| env: | |
| EC2_USER: ${{ secrets.EC2_USER }} | |
| EC2_HOST: ${{ secrets.EC2_HOST }} | |
| RELEASE_NAME: ${{ env.RELEASE_NAME }} | |
| SERVICE_USER: ${{ secrets.SERVICE_USER }} | |
| run: | | |
| set -euo pipefail | |
| APP_DIR="/srv/senifit-front" | |
| REL="${RELEASE_NAME}" | |
| SVC="${SERVICE_USER:-ubuntu}" | |
| cat release.tgz | ssh -o StrictHostKeyChecking=yes "$EC2_USER@$EC2_HOST" \ | |
| "set -euo pipefail; APP_DIR='$APP_DIR'; REL='$REL'; \ | |
| sudo mkdir -p \"\$APP_DIR/releases/\$REL\"; \ | |
| sudo chown \$USER:\$USER \"\$APP_DIR/releases/\$REL\"; \ | |
| tar -xzf - -C \"\$APP_DIR/releases/\$REL\"" | |
| ssh -o StrictHostKeyChecking=yes "$EC2_USER@$EC2_HOST" \ | |
| "set -euo pipefail; APP_DIR='$APP_DIR'; REL='$REL'; SVC='$SVC'; \ | |
| echo '==== Finalizing Release ===='; \ | |
| ln -sfn \"\$APP_DIR/releases/\$REL\" \"\$APP_DIR/current\"; \ | |
| sudo systemctl daemon-reload; \ | |
| sudo systemctl restart senifit-front" | |
| - name: Public healthcheck (non-blocking) | |
| continue-on-error: true | |
| run: | | |
| curl -fsS -o /dev/null https://senifit.co.kr || echo "::warning::Public healthcheck failed" |