diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..49ceee9 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,82 @@ +name: CD + +on: + push: + branches: [ "main", "cicd" ] + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository (with submodules) + uses: actions/checkout@v4 + with: + token: ${{ secrets.GIT_ACTION_TOKEN }} + submodules: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker Hub Login + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Docker Build & Push (cache) + uses: docker/build-push-action@v6 + with: + context: . + file: ./docker/Dockerfile + push: true + tags: ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }}:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + deploy: + runs-on: ubuntu-latest + needs: build + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Copy docker-compose.yml to Server + uses: appleboy/scp-action@master + with: + host: ${{ secrets.SSH_HOST }} + port: ${{ secrets.SSH_PORT }} + username: ${{ secrets.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + source: "docker/docker-compose.yml" + target: "~/app" + + - name: Deploy on server (no down) + uses: appleboy/ssh-action@master + env: + ENV_FILE: ${{ secrets.ENV_FILE }} + with: + envs: ENV_FILE + host: ${{ secrets.SSH_HOST }} + port: ${{ secrets.SSH_PORT }} + username: ${{ secrets.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + script: | + set -e + cd ~/app/docker + + echo "⚪️ .env 생성" + echo "$ENV_FILE" > .env + + echo "⚪️ 최신 이미지 pull" + docker compose pull + + echo "⚪️ 변경분만 재기동 (down 하지 않음)" + docker compose up -d + + echo "⚪️ 사용하지 않는 이미지 정리(선택)" + docker image prune -f \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0b4e13e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,59 @@ +name: CI + +on: + pull_request: + types: [ opened, synchronize, reopened ] + +permissions: + contents: read + checks: write + pull-requests: write + +jobs: + spotless: + name: Code Style Check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "temurin" + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Check code style with Spotless + run: ./gradlew spotlessCheck + + build: + name: Build + needs: spotless + runs-on: ubuntu-22.04 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + token: ${{ secrets.GIT_ACTION_TOKEN }} + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "temurin" + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle + run: ./gradlew build -x test \ No newline at end of file diff --git a/docker/.dockerignore b/docker/.dockerignore new file mode 100644 index 0000000..59eb92b --- /dev/null +++ b/docker/.dockerignore @@ -0,0 +1,26 @@ +# Gradle 관련 +.gradle/ +build/ +!gradle/wrapper/gradle-wrapper.jar + +# IDE 관련 +.idea/ +.vscode/ +*.iws +*.iml +*.ipr +.classpath +.project +.settings/ + +# 로그 파일 +logs/ +*.log + +# 기타 +.git/ +.gitignore +README.md +docker-compose.yml +Dockerfile +.dockerignore \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..abf19aa --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,24 @@ +FROM eclipse-temurin:21-jdk AS build + +# 작업 위치 +WORKDIR /app + +# 소스 코드 복사 +COPY . . + +# 실행 권한 부여 +RUN chmod +x ./gradlew + +# 프로젝트 빌드 +RUN ./gradlew build -x test + +FROM eclipse-temurin:21-jre + +# 빌드 이미지에서 JAR 파일 복사 +COPY --from=build /app/build/libs/*.jar app.jar + +# 포트 노출 +EXPOSE 8080 + +# 애플리케이션 실행 +ENTRYPOINT ["java", "-jar", "app.jar"] \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..120fa64 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,69 @@ +services: + app: + image: ${DOCKER_USERNAME}/${DOCKER_REPO}:latest + container_name: insaroad + expose: + - "8080" + environment: + - SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE} + - SPRING_DATASOURCE_URL=${SPRING_DATASOURCE_URL} + - SPRING_DATASOURCE_USERNAME=${SPRING_DATASOURCE_USERNAME} + - SPRING_DATASOURCE_PASSWORD=${SPRING_DATASOURCE_PASSWORD} + depends_on: + mysql: + condition: service_healthy + networks: + - insaroad-network + restart: unless-stopped + + mysql: + image: mysql:8.0 + container_name: mysql + expose: + - "3306" + environment: + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + volumes: + - mysql-data:/var/lib/mysql + healthcheck: + test: [ "CMD", "mysqladmin", "ping" ] + interval: 10s + timeout: 5s + retries: 5 + networks: + - insaroad-network + restart: unless-stopped + + nginx: + image: nginx:latest + container_name: nginx + ports: + - "80:80" + - "443:443" + volumes: + - /home/ubuntu/nginx/conf.d:/etc/nginx/conf.d + - /etc/letsencrypt:/etc/letsencrypt:ro + - /home/ubuntu/nginx/.htpasswd:/etc/nginx/.htpasswd:ro + depends_on: + - app + - dozzle + networks: + - insaroad-network + restart: unless-stopped + + dozzle: + image: amir20/dozzle:latest + container_name: dozzle + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + networks: + - insaroad-network + restart: unless-stopped + +networks: + insaroad-network: + driver: bridge + +volumes: + mysql-data: \ No newline at end of file