diff --git a/.github/workflows/ci-java.yml b/.github/workflows/ci-java.yml index 1a4faaa2..42ac78b0 100644 --- a/.github/workflows/ci-java.yml +++ b/.github/workflows/ci-java.yml @@ -44,4 +44,87 @@ jobs: - name: Run Spotless Check run: ./gradlew spotlessCheck - working-directory: apps/user-service \ No newline at end of file + working-directory: apps/user-service + + build: + name: Build + runs-on: ubuntu-latest + needs: spotless-check + strategy: + matrix: + java-version: [ "21" ] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up JDK ${{ matrix.java-version }} + uses: actions/setup-java@v4 + with: + java-version: '${{ matrix.java-version }}' + distribution: 'temurin' + cache: 'gradle' + + - name: Grant execute permission for Gradle wrapper + run: chmod +x ./gradlew + working-directory: apps/user-service + + - name: Run Gradle Build + run: ./gradlew build -x test + working-directory: apps/user-service + +# - name: Run Tests +# run: | +# if [ "${{ github.base_ref }}" == "main" ]; then +# ./gradlew test +# else +# ./gradlew prTest +# fi +# working-directory: apps/user-service + - name: Upload build artifacts + if: matrix.java-version == '21' && github.ref == 'refs/heads/main' && github.event_name == 'push' + uses: actions/upload-artifact@v4 + with: + name: build-artifacts + path: apps/user-service/build/libs/ + + docker: + name: Build Spring Boot Docker Image and push to registry + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + needs: + - build + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download build artifacts (JAR) + uses: actions/download-artifact@v4 + with: + name: build-artifacts + path: apps/user-service/build/libs/ + + - name: Login to Docker Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set repo lowercase + run: echo "REPO_LC=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: ./apps/user-service + push: true + tags: | + ghcr.io/${{ env.REPO_LC }}/user-service:latest + ghcr.io/${{ env.REPO_LC }}/user-service:${{ github.sha }} + + - name: Analyze image layers + run: | + echo "=== Image Layer Analysis ===" + docker history ghcr.io/${{ env.REPO_LC }}/user-service:latest --human --no-trunc \ No newline at end of file diff --git a/.github/workflows/deploy-java.yml b/.github/workflows/deploy-java.yml new file mode 100644 index 00000000..9d1e2e03 --- /dev/null +++ b/.github/workflows/deploy-java.yml @@ -0,0 +1,74 @@ +name: Deploy + +on: + workflow_dispatch: + push: + tags: + - 'v*' + +jobs: + deploy: + name: Deploy to AWS EC2 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set repo lowercase + run: echo "REPO_LC=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV + + - name: Copy docker compose files to EC2 + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.SERVER_HOST }} + username: ${{ secrets.SERVER_USER }} + key: ${{ secrets.SERVER_SSH_KEY }} + source: "docker/production/docker-compose.yml" + target: "~/app" + + - name: Deploy on EC2 + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.SERVER_HOST }} +# username: ${{ secrets.SERVER_USER }} + username: ubuntu + key: ${{ secrets.SERVER_SSH_KEY }} + script: | + cd ~/app/docker/production + echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + + docker pull ghcr.io/${{ env.REPO_LC }}/user-service:latest + + docker compose down + docker compose up -d + + sleep 10 + docker compose ps + + docker image prune -f + +# - name: Send Discord notification - Success +# if: success() +# uses: Ilshidur/action-discord@master +# env: +# DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL }} +# with: +# args: | +# **배포 성공** +# **Repository:** ${{ env.REPO_LC }} +# **Tag:** ${{ github.ref_name }} +# **Server:** ${{ secrets.SERVER_HOST }} +# **Status:** Success! +# +# - name: Send Discord notification - Failure +# if: failure() +# uses: Ilshidur/action-discord@master +# env: +# DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL }} +# with: +# args: | +# **배포 실패** +# **Repository:** ${{ env.REPO_LC }} +# **Tag:** ${{ github.ref_name }} +# **Error:** 배포 중 오류가 발생했습니다. +# **Check:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/apps/user-service/Dockerfile b/apps/user-service/Dockerfile index 3fb9d854..e3fb24a4 100644 --- a/apps/user-service/Dockerfile +++ b/apps/user-service/Dockerfile @@ -1,42 +1,9 @@ -# 1단계: 빌드 스테이지 -# Java 21 JDK가 포함된 경량 이미지를 사용합니다. -# 이 단계에서 애플리케이션을 빌드합니다. -FROM openjdk:21-jdk-slim AS builder +FROM eclipse-temurin:21-jre -# 컨테이너 내부에 작업 디렉토리를 생성하고 설정합니다. WORKDIR /app -# Gradle Wrapper, 설정 파일, 소스 코드를 복사합니다. -# Docker의 레이어 캐싱을 활용하여 빌드 속도를 높입니다. -COPY gradlew . -COPY gradle/ gradle/ -COPY build.gradle . -COPY settings.gradle . +COPY build/libs/*.jar app.jar -# 애플리케이션 소스 코드를 복사합니다. -COPY src src - -# 애플리케이션을 빌드하여 실행 가능한 JAR 파일을 만듭니다. -# `-x test`는 이미지 빌드 시 테스트를 건너뛰는 명령입니다. -RUN ./gradlew clean build -x test - ---- - -# 2단계: 실행 스테이지 -# 애플리케이션 실행에 필요한 Java 21 JRE만 포함된 경량 이미지를 사용합니다. -FROM openjdk:21-jre-slim - -# 컨테이너 내부의 작업 디렉토리를 설정합니다. -WORKDIR /app - -# 빌드 스테이지에서 생성된 JAR 파일을 복사합니다. -# `--from=builder` 옵션을 사용하여 첫 번째 단계에서 빌드된 JAR만 가져옵니다. -# 파일명은 `group`, `version`에 따라 `glt-korea-0.0.1-SNAPSHOT.jar`가 되므로, -# 이를 `app.jar`라는 간단한 이름으로 변경합니다. -COPY --from=builder /app/build/libs/glt-korea-0.0.1-SNAPSHOT.jar ./app.jar - -# 애플리케이션이 외부 요청을 받을 포트를 노출합니다. EXPOSE 8080 -# 컨테이너 시작 시 실행될 명령어를 정의합니다. -CMD ["java", "-jar", "app.jar"] \ No newline at end of file +CMD ["java", "-jar", "app.jar"] diff --git a/docker/production/docker-compose.yml b/docker/production/docker-compose.yml index e69de29b..3d417fe8 100644 --- a/docker/production/docker-compose.yml +++ b/docker/production/docker-compose.yml @@ -0,0 +1,17 @@ +version: "3.9" + +services: + user-service: + image: ghcr.io/kernel180-be12/final-4team-icebang/user-service:latest + container_name: user-service + restart: always + ports: + - "80:8080" + env_file: + - .env + networks: + - app-network + +networks: + app-network: + driver: bridge