diff --git a/.github/workflows/api-cd.yaml b/.github/workflows/api-cd.yaml index 83c5698..948a6ca 100644 --- a/.github/workflows/api-cd.yaml +++ b/.github/workflows/api-cd.yaml @@ -1,8 +1,109 @@ name: API CD on: + push: + tags: + - 'v*' workflow_dispatch: + inputs: + version: + description: '롤백할 버전 (ex: v1.6.0)' + required: true jobs: - docker-deploy: + build-and-push: runs-on: ubuntu-latest + if: github.event_name == 'push' + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and Push Docker Image + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: | + ${{ secrets.DOCKER_USERNAME }}/velog-dashboard-v2-api:latest + ${{ secrets.DOCKER_USERNAME }}/velog-dashboard-v2-api:${{ github.ref_name }} + platforms: linux/amd64 + cache-from: type=gha + cache-to: type=gha,mode=max + + deploy: + runs-on: ubuntu-latest + needs: [build-and-push] + if: always() && (needs.build-and-push.result == 'success' || needs.build-and-push.result == 'skipped') + + steps: + - name: Validate deploy version + id: version + run: | + RAW="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }}" + if [[ ! "$RAW" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Invalid version format: $RAW" + exit 1 + fi + echo "value=$RAW" >> $GITHUB_OUTPUT + + - name: Deploy to Server 1 + uses: appleboy/ssh-action@v1 + with: + host: ${{ secrets.DEPLOY_HOST_1 }} + username: ${{ secrets.DEPLOY_USER }} + key: ${{ secrets.DEPLOY_SSH_KEY_1 }} + command_timeout: 15m + script: | + export GIT_SSH_COMMAND='ssh -i ~/.ssh/velog-dashboard-v2-api' + export API_VERSION="${{ steps.version.outputs.value }}" + cd ${{ secrets.DEPLOY_PATH }} + git fetch --tags + git checkout "$API_VERSION" + bash run.sh + + - name: Deploy to Server 2 + uses: appleboy/ssh-action@v1 + with: + host: ${{ secrets.DEPLOY_HOST_2 }} + username: ${{ secrets.DEPLOY_USER }} + key: ${{ secrets.DEPLOY_SSH_KEY_2 }} + command_timeout: 15m + script: | + export GIT_SSH_COMMAND='ssh -i ~/.ssh/velog-dashboard-v2-api' + export API_VERSION="${{ steps.version.outputs.value }}" + cd ${{ secrets.DEPLOY_PATH }} + git fetch --tags + git checkout "$API_VERSION" + bash run.sh + + - name: Notify Slack on Success + if: success() + uses: slackapi/slack-github-action@v1.24.0 + with: + payload: | + { + "text": "✅ API 배포 성공\n• 버전: ${{ steps.version.outputs.value }}\n• 트리거: ${{ github.actor }}\n• <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|액션 로그>" + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + + - name: Notify Slack on Failure + if: failure() + uses: slackapi/slack-github-action@v1.24.0 + with: + payload: | + { + "text": "❌ API 배포 실패\n• 버전: ${{ steps.version.outputs.value }}\n• 트리거: ${{ github.actor }}\n• <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|액션 로그>" + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/api-ci-cd.yaml b/.github/workflows/api-ci.yaml similarity index 72% rename from .github/workflows/api-ci-cd.yaml rename to .github/workflows/api-ci.yaml index e13c71e..b7bcc04 100644 --- a/.github/workflows/api-ci-cd.yaml +++ b/.github/workflows/api-ci.yaml @@ -1,4 +1,4 @@ -name: Test CI +name: API CI on: workflow_dispatch: @@ -80,32 +80,3 @@ jobs: - name: Run build run: pnpm run build - - # 환경 변수 이슈로 잠깐 disable - # docker-deploy: - # runs-on: ubuntu-latest - # needs: build-and-test - # # 하나의 버전이라도 성공하면 실행 (일부 실패해도 진행) - # if: ${{ !cancelled() && contains(needs.build-and-test.result, 'success') }} - - # steps: - # - name: Checkout repository - # uses: actions/checkout@v4 - - # # Docker 로그인 - # - name: Log in to Docker Hub - # uses: docker/login-action@v3 - # with: - # username: ${{ secrets.DOCKER_USERNAME }} - # password: ${{ secrets.DOCKER_PASSWORD }} - - # # Docker 이미지 빌드 - # - name: Build Docker Image - # run: | - # docker build -t velog-dashboard-v2-api:latest . - - # # Docker Hub에 푸시 - # - name: Push Docker Image - # run: | - # docker tag velog-dashboard-v2-api:latest ${{ secrets.DOCKER_USERNAME }}/velog-dashboard-v2-api:latest - # docker push ${{ secrets.DOCKER_USERNAME }}/velog-dashboard-v2-api:latest \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index a83a957..c678777 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: # context: . # dockerfile: Dockerfile # image: velog-dashboard-v2-api - image: nuung/velog-dashboard-v2-api:latest + image: nuung/velog-dashboard-v2-api:${API_VERSION:-latest} hostname: velog-dashboard-v2-api container_name: velog-dashboard-v2-api ports: diff --git a/run.sh b/run.sh index 11c8f4c..fa58719 100755 --- a/run.sh +++ b/run.sh @@ -144,6 +144,15 @@ check_services() { fi } +# 인자 파싱 +FOLLOW=false +while [[ $# -gt 0 ]]; do + case $1 in + -f) FOLLOW=true; shift ;; + *) shift ;; + esac +done + # 메인 실행 로직 main() { print_step "Velog Dashboard V2 배포 스크립트 시작" @@ -162,9 +171,11 @@ main() { echo -e " Frontend: ${YELLOW}http://localhost:3000${NC}" echo -e " API Health Check: ${YELLOW}http://localhost:8080/health${NC}" - echo -e "\n${YELLOW}로그 모니터링을 시작합니다... (Ctrl+C로 종료)${NC}" - sleep 2 - docker compose logs -f + if [[ "$FOLLOW" == true ]]; then + echo -e "\n${YELLOW}로그 모니터링을 시작합니다... (Ctrl+C로 종료)${NC}" + sleep 2 + docker compose logs -f + fi } # 스크립트 실행