diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 425d244..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index dc16896..47ec7cd 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,9 +2,7 @@ name: Deploy with Docker Hub on: push: - branches: [main, develop] - pull_request: - branches: [main] + branches: [ develop, main ] env: DOCKER_IMAGE: leeeunda/blockcloud-server @@ -12,9 +10,11 @@ env: jobs: test: runs-on: ubuntu-latest - continue-on-error: true # 급배포용(테스트 실패해도 다음 진행) + continue-on-error: true steps: - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Set up JDK 21 uses: actions/setup-java@v4 @@ -37,56 +37,51 @@ jobs: build-and-push: needs: test runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' steps: - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Login to Docker Hub uses: docker/login-action@v3 with: - username: ${{ secrets.DOCKER_USERNAME }} # <<< CHANGE(secrets): Docker Hub ID - password: ${{ secrets.DOCKER_PASSWORD }} # <<< CHANGE(secrets): Docker Hub PAT/비번 + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - # 만약 EC2가 Graviton(ARM64)이면 platform 지정 필요 - # with: platforms: linux/arm64 - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . push: true tags: | - ${{ env.DOCKER_IMAGE }}:latest - ${{ env.DOCKER_IMAGE }}:${{ github.sha }} - ${{ env.DOCKER_IMAGE }}:${{ github.ref_name }} + ${{ env.DOCKER_IMAGE }}:pr-${{ github.event.number }} + ${{ env.DOCKER_IMAGE }}:${{ github.event.pull_request.head.sha }} + ${{ env.DOCKER_IMAGE }}:${{ github.event.pull_request.head.ref }} cache-from: type=gha cache-to: type=gha,mode=max - # platforms: linux/amd64 # <<< CHANGE(옵션): EC2가 x86_64면 유지, ARM이면 linux/arm64 로 + # platforms: linux/amd64 # Graviton이면 linux/arm64 deploy-to-ec2: needs: build-and-push runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' steps: - name: Deploy to EC2 (pull & replace container) uses: appleboy/ssh-action@v1.2.0 with: - host: ${{ secrets.EC2_HOST }} # <<< CHANGE(secrets): EC2 퍼블릭 도메인/IP - username: ${{ secrets.EC2_USER }} # <<< CHANGE(secrets): 일반 ubuntu - key: ${{ secrets.EC2_SSH_KEY }} # <<< CHANGE(secrets): PEM 본문 + host: ${{ secrets.EC2_HOST }} + username: ${{ secrets.EC2_USER }} + key: ${{ secrets.EC2_SSH_KEY }} script: | set -e - IMAGE="${{ env.DOCKER_IMAGE }}:${{ github.sha }}" - echo "Pull $IMAGE" + IMAGE="${{ env.DOCKER_IMAGE }}:${{ github.event.pull_request.head.sha }}" docker pull "$IMAGE" - echo "Stop & remove old container" docker stop blockcloud-app || true docker rm blockcloud-app || true - echo "Run new container (bind only localhost)" docker run -d \ --name blockcloud-app \ --restart unless-stopped \ @@ -94,16 +89,12 @@ jobs: -p 127.0.0.1:8080:8080 \ "$IMAGE" - echo "Health check" - # <<< CHANGE(필요시): 액추에이터 경로가 다르면 아래 URL 수정 - for i in {1..20}; do + for i in {1..30}; do if curl -fsS http://127.0.0.1:8080/actuator/health >/dev/null 2>&1; then echo "UP" exit 0 fi sleep 3 done - - echo "App failed to start. Logs:" docker logs --tail=200 blockcloud-app || true exit 1 diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 4bc2748..0000000 --- a/Dockerfile +++ /dev/null @@ -1,44 +0,0 @@ -# 멀티스테이지 빌드 -FROM gradle:8.5-jdk21 AS build - -# 작업 디렉토리 설정 -WORKDIR /app - -# Gradle 파일들 복사 (캐시 최적화) -COPY gradlew . -COPY gradle gradle -COPY build.gradle . -COPY settings.gradle . - -# 의존성 다운로드 -RUN ./gradlew dependencies --no-daemon - -# 소스 코드 복사 -COPY src src - -# JAR 파일 빌드 -RUN ./gradlew build -x test --no-daemon - -# 실행 스테이지 -FROM openjdk:21-jdk-slim - -# 메타데이터 -LABEL maintainer="BlockCloud Team" -LABEL version="1.0" -LABEL description="BlockCloud Backend Application" - -# 작업 디렉토리 설정 -WORKDIR /app - -# JAR 파일 복사 -COPY --from=build /app/build/libs/*.jar app.jar - -# 포트 노출 -EXPOSE 8080 - -# 헬스체크 -HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \ - CMD curl -f http://localhost:8080/actuator/health || exit 1 - -# 애플리케이션 실행 -ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/build.gradle b/build.gradle index 7ecad06..f36ec6b 100644 --- a/build.gradle +++ b/build.gradle @@ -28,29 +28,34 @@ repositories { } dependencies { + // Spring Boot Starters implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' - // MySQL 의존성 + // Database runtimeOnly 'com.mysql:mysql-connector-j' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' + + // API Documentation + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0' + + // JWT + implementation 'io.jsonwebtoken:jjwt-api:0.12.3' + implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' + implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' + + // Lombok compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' + + // Test testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'com.h2database:h2' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - testImplementation("com.h2database:h2") - - //oauth2 - implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' - - //JWT 토큰 라이브러리 - implementation 'io.jsonwebtoken:jjwt-api:0.12.3' - implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' - implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' } tasks.named('test') { @@ -86,4 +91,5 @@ jacocoTestCoverageVerification { } } } + check.dependsOn jacocoTestCoverageVerification \ No newline at end of file diff --git a/scripts/deploy.sh b/scripts/deploy.sh deleted file mode 100755 index 3f3eec9..0000000 --- a/scripts/deploy.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/bin/bash - -# BlockCloud Docker Hub 배포 스크립트 -set -e - -# 색상 정의 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# 로그 함수 -log_info() { - echo -e "${GREEN}[INFO]${NC} $1" -} - -log_warn() { - echo -e "${YELLOW}[WARN]${NC} $1" -} - -log_error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -# 환경 변수 설정 -ENVIRONMENT=${1:-dev} -DOCKER_USERNAME=${DOCKER_USERNAME:-your-dockerhub-username} -DOCKER_IMAGE=${DOCKER_IMAGE:-$DOCKER_USERNAME/blockcloud-backend} -EC2_HOST=${EC2_HOST:-your-ec2-host} -EC2_USERNAME=${EC2_USERNAME:-ubuntu} - -log_info "🚀 BlockCloud Docker Hub 배포 시작 (환경: $ENVIRONMENT)" - -# 1. 테스트 실행 -log_info "🧪 테스트 실행 중..." -./gradlew test - -# 2. Docker 이미지 빌드 -log_info "🐳 Docker 이미지 빌드 중..." -docker build -t $DOCKER_IMAGE:latest . - -# 3. 이미지 태깅 -IMAGE_TAG=$(git rev-parse --short HEAD) -docker tag $DOCKER_IMAGE:latest $DOCKER_IMAGE:$IMAGE_TAG - -log_info "📦 이미지 태그: $IMAGE_TAG" - -# 4. Docker Hub 로그인 확인 -if [ -z "$DOCKER_PASSWORD" ]; then - log_error "DOCKER_PASSWORD 환경 변수가 설정되지 않았습니다." - log_info "다음 명령어로 설정하세요:" - log_info "export DOCKER_PASSWORD=your-dockerhub-password" - exit 1 -fi - -# 5. Docker Hub에 로그인 -log_info "🔐 Docker Hub 로그인 중..." -echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin - -# 6. 이미지 푸시 -log_info "📤 Docker Hub에 이미지 푸시 중..." -docker push $DOCKER_IMAGE:latest -docker push $DOCKER_IMAGE:$IMAGE_TAG - -log_info "✅ Docker Hub 푸시 완료!" - -# 7. EC2 배포 (프로덕션 환경인 경우) -if [ "$ENVIRONMENT" = "prod" ]; then - log_info "🖥️ EC2에 배포 중..." - - # EC2에 SSH로 접속하여 배포 - ssh -o StrictHostKeyChecking=no $EC2_USERNAME@$EC2_HOST << EOF - # Docker Hub에서 이미지 풀 - docker pull $DOCKER_IMAGE:$IMAGE_TAG - - # 기존 컨테이너 중지 및 제거 - docker stop blockcloud-app || true - docker rm blockcloud-app || true - - # 새 컨테이너 실행 - docker run -d \\ - --name blockcloud-app \\ - --restart unless-stopped \\ - -p 8080:8080 \\ - -e SPRING_PROFILES_ACTIVE=prod \\ - -e DB_HOST=\$DB_HOST \\ - -e DB_USERNAME=\$DB_USERNAME \\ - -e DB_PASSWORD=\$DB_PASSWORD \\ - -e JWT_SECRET=\$JWT_SECRET \\ - $DOCKER_IMAGE:$IMAGE_TAG - - # 헬스체크 - sleep 30 - if curl -f http://localhost:8080/actuator/health; then - echo "✅ 배포 성공!" - else - echo "❌ 배포 실패!" - docker logs blockcloud-app - exit 1 - fi -EOF -else - log_info "🔄 로컬 환경 배포 완료" -fi - -log_info "✅ 배포 완료!" -log_info "📊 이미지: $DOCKER_IMAGE:$IMAGE_TAG" -log_info "🔗 Docker Hub: https://hub.docker.com/r/$DOCKER_USERNAME/blockcloud-backend"