diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index dd8f823f..c2b48d28 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -1,4 +1,4 @@ -name: Dev CI/CD - Build and Deploy +name: Dev CI/CD - Build, Push and Deploy on: push: @@ -12,13 +12,13 @@ concurrency: env: REGISTRY: docker.io IMAGE_NAME: ninecraft0523/ninecraft-server + MODULE: apis jobs: - build-and-push: + build-push-and-deploy: runs-on: ubuntu-24.04 timeout-minutes: 20 - outputs: - tags: ${{ steps.meta.outputs.tags }} + environment: development steps: - name: Checkout code @@ -28,27 +28,17 @@ jobs: run: | mkdir ./secret echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties - echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties chmod 600 ./secret/* - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - cache: gradle + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + - name: Log in to Docker Hub + uses: docker/login-action@v3 with: - gradle-home-cache-cleanup: true - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Run full Gradle build - run: ./gradlew build --parallel --build-cache + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Extract metadata for Docker id: meta @@ -58,32 +48,20 @@ jobs: tags: | type=raw,value=development-latest - - 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.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push Docker image + id: build-and-push uses: docker/build-push-action@v6 with: context: . + file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} cache-from: type=gha cache-to: type=gha,mode=max + build-args: | + MODULE=${{ env.MODULE }} - deploy-dev: - needs: build-and-push - runs-on: ubuntu-24.04 - timeout-minutes: 10 - environment: development - - steps: - name: Deploy to Development Server uses: appleboy/ssh-action@v1.2.2 with: @@ -92,11 +70,9 @@ jobs: key: ${{ secrets.DEV_SSH_KEY }} port: ${{ secrets.DEV_PORT }} script: | - cd /opt/app export DOCKERHUB_USERNAME="${{ secrets.DOCKERHUB_USERNAME }}" export DOCKERHUB_TOKEN="${{ secrets.DOCKERHUB_TOKEN }}" - export IMAGE_TAG="${{ needs.build-and-push.outputs.tags }}" + export IMAGE_TAG="$(echo "${{ steps.meta.outputs.tags }}" | head -n1)" cd ~/deploy chmod +x ./deploy.sh ./deploy.sh - diff --git a/.github/workflows/prod-ci-cd.yml b/.github/workflows/prod-ci-cd.yml index 7127109a..efa1e09e 100644 --- a/.github/workflows/prod-ci-cd.yml +++ b/.github/workflows/prod-ci-cd.yml @@ -1,9 +1,9 @@ -name: Prod CI/CD - Build and Deploy +name: Prod CI/CD - Build, Push and Deploy on: release: types: - - published # Release가 published 될 때만 실행 + - published # GitHub Release가 'published' 상태일 때만 워크플로우를 실행합니다. concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -12,15 +12,13 @@ concurrency: env: REGISTRY: docker.io IMAGE_NAME: ninecraft0523/ninecraft-server + MODULE: apis jobs: - build-and-push: + build-push-and-deploy: runs-on: ubuntu-24.04 timeout-minutes: 25 - outputs: - image-digest: ${{ steps.build.outputs.digest }} - version: ${{ steps.meta.outputs.version }} - tags: ${{ steps.meta.outputs.tags }} + environment: production steps: - name: Checkout code @@ -29,28 +27,18 @@ jobs: - name: Inject application-secret.properties from Secrets run: | mkdir ./secret - echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties chmod 600 ./secret/* - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - cache: gradle + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + - name: Log in to Docker Hub + uses: docker/login-action@v3 with: - gradle-home-cache-cleanup: true - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Run full Gradle build with strict validation - run: ./gradlew build --parallel --build-cache --warning-mode all + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Extract metadata for Docker id: meta @@ -61,33 +49,20 @@ jobs: type=semver,pattern={{version}} type=raw,value=production-latest - - 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.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push Docker image - id: build + id: build-and-push uses: docker/build-push-action@v6 with: context: . + file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} cache-from: type=gha cache-to: type=gha,mode=max + build-args: | + MODULE=${{ env.MODULE }} - deploy-prod: - needs: build-and-push - runs-on: ubuntu-24.04 - timeout-minutes: 20 - environment: production - - steps: - name: Deploy to Production Server uses: appleboy/ssh-action@v1.2.2 with: @@ -96,11 +71,10 @@ jobs: key: ${{ secrets.PROD_SSH_KEY }} port: ${{ secrets.PROD_PORT }} script: | - cd /opt/app export DOCKERHUB_USERNAME="${{ secrets.DOCKERHUB_USERNAME }}" export DOCKERHUB_TOKEN="${{ secrets.DOCKERHUB_TOKEN }}" - export IMAGE_TAG="$(echo "${{ needs.build-and-push.outputs.tags }}" | head -n1)" - export VERSION_TAG="${{ needs.build-and-push.outputs.version }}" + export IMAGE_TAG="$(echo "${{ steps.meta.outputs.tags }}" | head -n1)" + export VERSION_TAG="${{ steps.meta.outputs.version }}" export RELEASE_VERSION="${{ github.event.release.tag_name }}" cd ~/deploy chmod +x ./deploy.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..5dce274b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +# Build stage +FROM gradle:8.7-jdk21 AS build +ARG MODULE=apis +WORKDIR /app + +# 의존성 캐싱 최적화를 위한 단계별 복사 +# 1. 의존성 관련 파일만 먼저 복사 +COPY build.gradle settings.gradle ./ +COPY ${MODULE}/build.gradle ./${MODULE}/ + +# 2. 소스코드 없이 의존성만 다운로드 +RUN ./gradlew :${MODULE}:dependencies --no-daemon + +# 3. 소스코드 전체 복사 +COPY . . + +# 4. 실제 애플리케이션 빌드 +RUN ./gradlew :${MODULE}:bootJar --parallel --no-daemon + +# Run stage +FROM openjdk:21-slim +ARG MODULE=apis +WORKDIR /app + +# 멀티스테이지 빌드로 최종 이미지 크기 최소화 +COPY --from=build /app/${MODULE}/build/libs/${MODULE}-*.jar app.jar + +# 런타임에 필요한 secret 폴더 복사 +COPY --from=build /app/secret ./secret/ + +# JVM 실행 설정 +# - Xms512m: 초기 힙 메모리 512MB +# - Xmx1g: 최대 힙 메모리 1GB +ENTRYPOINT ["java", "-Xms512m", "-Xmx1g", "-jar", "app.jar"] diff --git a/Dockerfile-dev b/Dockerfile-dev new file mode 100644 index 00000000..862165bc --- /dev/null +++ b/Dockerfile-dev @@ -0,0 +1,34 @@ +# Build stage +FROM gradle:8.7-jdk21 AS build +ARG MODULE=apis +WORKDIR /app + +# 의존성 캐싱 최적화를 위한 단계별 복사 +# 1. 의존성 관련 파일만 먼저 복사 +COPY build.gradle settings.gradle ./ +COPY ${MODULE}/build.gradle ./${MODULE}/ + +# 2. 소스코드 없이 의존성만 다운로드 +RUN ./gradlew :${MODULE}:dependencies --no-daemon + +# 3. 소스코드 전체 복사 +COPY . . + +# 4. 실제 애플리케이션 빌드 +RUN ./gradlew :${MODULE}:bootJar --parallel --no-daemon + +# Run stage +FROM openjdk:21-slim +ARG MODULE=apis +WORKDIR /app + +# 멀티스테이지 빌드로 최종 이미지 크기 최소화 +COPY --from=build /app/${MODULE}/build/libs/${MODULE}-*.jar app.jar + +# 런타임에 필요한 secret 폴더 복사 +COPY --from=build /app/secret ./secret/ + +# JVM 실행 설정 +# Xms512m: 초기 힙 메모리 512MB +# Xmx1g: 최대 힙 메모리 1GB +ENTRYPOINT ["java", "-Xms512m", "-Xmx1g", "-jar", "app.jar"]