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 and Deploy SpringBoot to Raspberry Pi | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| pull_request: | |
| branches: [ main ] | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| RASPBERRY_PI_HOST: ${{ secrets.RASPBERRY_PI_HOST }} | |
| RASPBERRY_PI_USER: ${{ secrets.RASPBERRY_PI_USER }} | |
| MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }} | |
| MYSQL_DATABASE: ${{ secrets.MYSQL_DATABASE }} | |
| MYSQL_USER: ${{ secrets.MYSQL_USER }} | |
| MYSQL_PASSWORD: ${{ secrets.MYSQL_PASSWORD }} | |
| DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} | |
| jobs: | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 🔄 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: ☕ Set up JDK 21 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '21' | |
| distribution: 'temurin' | |
| - name: 📦 Cache Gradle packages | |
| uses: actions/cache@v3 | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/wrapper | |
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | |
| - name: 🧪 Test SpringBoot | |
| run: | | |
| chmod +x gradlew | |
| ./gradlew clean test | |
| build-and-deploy: | |
| needs: test | |
| runs-on: ubuntu-latest | |
| if: github.ref == 'refs/heads/main' | |
| steps: | |
| - name: 🔄 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: 🐳 Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: 🔐 Log in to Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: 📝 Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=sha,prefix={{branch}}- | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| flavor: | | |
| suffix=-arm64 | |
| - name: 🏗️ Build and push SpringBoot image | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| platforms: linux/arm64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: 🚀 Deploy to Raspberry Pi | |
| uses: appleboy/[email protected] | |
| with: | |
| host: ${{ env.RASPBERRY_PI_HOST }} | |
| username: ${{ env.RASPBERRY_PI_USER }} | |
| key: ${{ secrets.RASPBERRY_PI_SSH_KEY }} | |
| script: | | |
| cd /home/yoon/goormthon-java | |
| git pull origin main | |
| export BUILD_TAG="${{ github.sha }}" | |
| export DOCKER_REGISTRY="${{ env.REGISTRY }}" | |
| export DOCKER_REPO="${{ env.IMAGE_NAME }}" | |
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin | |
| docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}-arm64 | |
| docker tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}-arm64 dormung-springboot:latest | |
| chmod +x deploy.sh | |
| ./deploy.sh deploy | |
| - name: 🧪 Verify deployment | |
| uses: appleboy/[email protected] | |
| with: | |
| host: ${{ env.RASPBERRY_PI_HOST }} | |
| username: ${{ env.RASPBERRY_PI_USER }} | |
| key: ${{ secrets.RASPBERRY_PI_SSH_KEY }} | |
| script: | | |
| cd /home/yoon/goormthon-java | |
| sleep 30 | |
| if curl -sf http://localhost/api/actuator/health; then | |
| echo "✅ SpringBoot health check passed" | |
| else | |
| echo "❌ SpringBoot health check failed" | |
| exit 1 | |
| fi | |
| ./deploy.sh status | |
| - name: 📢 Discord Success Notification | |
| if: success() | |
| uses: Ilshidur/action-discord@master | |
| env: | |
| DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} | |
| with: | |
| args: | | |
| 🎉 **배포 성공!** | |
| 📦 **프로젝트**: ${{ github.repository }} | |
| 🌿 **브랜치**: ${{ github.ref_name }} | |
| 📝 **커밋**: `${{ github.sha }}` | |
| 👤 **작성자**: ${{ github.actor }} | |
| 💬 **메시지**: ${{ github.event.head_commit.message }} | |
| - name: 📢 Discord Failure Notification | |
| if: failure() | |
| uses: Ilshidur/action-discord@master | |
| env: | |
| DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} | |
| with: | |
| args: | | |
| ❌ **배포 실패!** | |
| 📦 **프로젝트**: ${{ github.repository }} | |
| 🌿 **브랜치**: ${{ github.ref_name }} | |
| 📝 **커밋**: `${{ github.sha }}` | |
| 👤 **작성자**: ${{ github.actor }} | |
| 💬 **메시지**: ${{ github.event.head_commit.message }} | |
| 🔄 **자동 롤백이 실행됩니다** | |
| - name: 🔄 Auto Rollback on Failure | |
| if: failure() | |
| uses: appleboy/[email protected] | |
| with: | |
| host: ${{ env.RASPBERRY_PI_HOST }} | |
| username: ${{ env.RASPBERRY_PI_USER }} | |
| key: ${{ secrets.RASPBERRY_PI_SSH_KEY }} | |
| script: | | |
| cd /home/yoon/goormthon-java | |
| echo "🔄 Auto rollback initiated" | |
| ./deploy.sh rollback || echo "Rollback failed - manual intervention required" |