[FE]피드백 모달 수정 (#325) #29
Workflow file for this run
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: Build & Deploy Prod (SSH & Tag-based) | |
| on: | |
| push: | |
| tags: | |
| - "v*" # ⬅ v1.0.0 이런 태그 push 시에만 빌드+배포 | |
| concurrency: | |
| group: deploy-prod | |
| cancel-in-progress: true | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_BACK: ghcr.io/sisc-it/sisc-web-back | |
| IMAGE_FRONT: ghcr.io/sisc-it/sisc-web-front # 프론트 이미지 추가 | |
| jobs: | |
| # ----------------------------- | |
| # 1) 백엔드 Docker 빌드 + GHCR 푸시 (S3 대신 Docker 이미지로 빌드) | |
| # ----------------------------- | |
| build-back: | |
| runs-on: ubuntu-latest | |
| environment: production | |
| permissions: { contents: read, packages: write } | |
| #defaults: # 직접 셸 명령어를 칠 때 기본 경로를 잡아주는 역할 | |
| #run: | |
| #working-directory: backend | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build & Push (backend) | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ./backend | |
| push: true | |
| tags: | | |
| ${{ env.IMAGE_BACK }}:${{ github.ref_name }} | |
| ${{ env.IMAGE_BACK }}:latest | |
| #cache-from: type=gha | |
| #cache-to: type=gha,mode=max | |
| # ----------------------------- | |
| # 2) 프론트 | |
| # ----------------------------- | |
| build-front: | |
| runs-on: ubuntu-latest | |
| environment: production | |
| permissions: { contents: read, packages: write } | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: docker/setup-buildx-action@v3 | |
| - name: Build & Push (frontend) | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ./frontend | |
| push: true | |
| platforms: linux/amd64 | |
| tags: | | |
| ${{ env.IMAGE_FRONT }}:${{ github.ref_name }} | |
| ${{ env.IMAGE_FRONT }}:latest | |
| build-args: | | |
| VITE_API_URL=${{ secrets.SPRING_API_URL }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # ----------------------------- | |
| # 3) 배포: 백엔드, 프론트 | |
| # ----------------------------- | |
| deploy: | |
| needs: [build-back, build-front] | |
| runs-on: ubuntu-latest | |
| environment: production | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Make .env file for Prod | |
| run: | | |
| echo "SPRING_PROFILES_ACTIVE=prod" > .env | |
| echo "TAG=${{ github.ref_name }}" >> .env # ⬅ docker-compose에서 사용할 태그 버전 | |
| # DB & 기타 시크릿 (production 환경에 등록된 값을 자동으로 불러옴) | |
| echo "DB_URL=${{ secrets.DB_URL }}" >> .env | |
| echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> .env | |
| echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env | |
| echo "SPRING_API_URL=${{ secrets.SPRING_API_URL }}" >> .env | |
| echo "FRONTEND_URL=${{ secrets.FRONTEND_URL }}" >> .env | |
| echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env | |
| echo "MAIL_USERNAME=${{ secrets.MAIL_USERNAME }}" >> .env | |
| echo "MAIL_PASSWORD=${{ secrets.MAIL_PASSWORD }}" >> .env | |
| echo "SBA_ADMIN_NAME=${{ secrets.SBA_ADMIN_NAME }}" >> .env | |
| echo "SBA_ADMIN_PASSWORD=${{ secrets.SBA_ADMIN_PASSWORD }}" >> .env | |
| - name: SCP Transfer (docker-compose.yml & .env) | |
| uses: appleboy/scp-action@master | |
| with: | |
| host: ${{ secrets.SSH_HOST }} | |
| username: ${{ secrets.SSH_USER }} | |
| key: ${{ secrets.SSH_PRIVATE_KEY }} | |
| port: ${{ secrets.SSH_PORT }} | |
| source: "docker-compose.yml, .env" | |
| target: "/home/${{ secrets.SSH_USER }}/app/sisc-web/" | |
| - name: SSH Deploy | |
| uses: appleboy/ssh-action@v1.2.0 | |
| with: | |
| host: ${{ secrets.SSH_HOST }} | |
| username: ${{ secrets.SSH_USER }} | |
| key: ${{ secrets.SSH_PRIVATE_KEY }} | |
| port: ${{ secrets.SSH_PORT }} | |
| script_stop: true | |
| script: | | |
| set -euo pipefail | |
| # 필수 폴더 생성 및 DB 권한(UID 70) 부여. 운영 서버에 HDD가 마운트된 경로(/mnt/storage)가 있는지 확인 필요. (완료되어 주석처리) | |
| # sudo mkdir -p /mnt/storage/pg_ai_data /mnt/storage/logs /mnt/storage/uploads ./data/postgres | |
| # sudo chown -R 70:70 /mnt/storage/pg_ai_data ./data/postgres | |
| cd ~/app/sisc-web | |
| # GHCR 로그인 | |
| echo "${{ secrets.GHCR_READ_TOKEN }}" | docker login ghcr.io -u ${{ secrets.GHCR_READ_USER }} --password-stdin | |
| # 컨테이너 기동 | |
| docker compose pull api web redis npm | |
| docker compose up -d --remove-orphans api web redis npm db | |
| docker image prune -f | |
| # 서버 헬스체크 | |
| if docker ps --format '{{.Names}}' | grep -q "^api$"; then | |
| echo "Waiting for api to be healthy..." | |
| for i in {1..30}; do | |
| status=$(docker inspect --format='{{json .State.Health.Status}}' api 2>/dev/null || echo '"none"') | |
| if echo "$status" | grep -q healthy; then | |
| echo "=== 운영 서버 정상 작동 확인 ==="; break | |
| fi | |
| sleep 2 | |
| done | |
| fi | |
| # 도커 용량 최적화 | |
| - name: Cleanup Docker | |
| run: | | |
| # 빌드 과정에서 생긴 모든 캐시 삭제 (-a 옵션이 핵심) | |
| docker builder prune -a -f | |
| # 태그가 없어진 이미지 삭제 | |
| docker image prune -f |