feat:gichub actions 테스트 #1
Workflow file for this run
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: Deploy to EC2 | |
| # ========================= | |
| # 전역 환경변수 | |
| # ========================= | |
| env: | |
| IMAGE_REPOSITORY: fivelogic # GHCR 이미지 리포지토리명 | |
| CONTAINER_NAME: spring-boot # 컨테이너 이름 | |
| EC2_INSTANCE_TAG_NAME: devcos-team10-main # 배포 대상 EC2 Name 태그 | |
| DOCKER_NETWORK: app-network # 도커 네트워크 | |
| BACKEND_DIR: back # Dockerfile 위치 (프로젝트 루트) | |
| on: | |
| push: | |
| paths: | |
| - ".github/workflows/**" | |
| - "src/**" | |
| - "build.gradle" | |
| - "settings.gradle" | |
| - "Dockerfile" | |
| branches: | |
| - main | |
| - chore/107 | |
| pull_request: | |
| branches: | |
| - main | |
| - develop | |
| # 권한 최소화/명시화 | |
| permissions: | |
| contents: write # 태그/릴리즈 | |
| packages: write # GHCR 푸시 | |
| # 기본 셸 | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| # --------------------------------------------------------- | |
| # 1) 테스트 | |
| # --------------------------------------------------------- | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 코드 체크아웃 | |
| uses: actions/checkout@v4 | |
| - name: Java 21 설정 | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '21' | |
| cache: 'gradle' | |
| - name: Gradle 권한 설정 | |
| run: chmod +x ./gradlew | |
| - name: 테스트 실행 | |
| run: ./gradlew test | |
| - name: 테스트 결과 업로드 | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results | |
| path: build/reports/tests/test/ | |
| # --------------------------------------------------------- | |
| # 2) 태그/릴리즈 생성 (main 브랜치만) | |
| # --------------------------------------------------------- | |
| makeTagAndRelease: | |
| needs: test | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tag_name: ${{ steps.create_tag.outputs.new_tag }} | |
| steps: | |
| - name: 코드 체크아웃 | |
| uses: actions/checkout@v4 | |
| # 버전 태그 자동 생성 (vX.Y.Z) | |
| - name: Create Tag | |
| id: create_tag | |
| uses: mathieudutour/[email protected] | |
| with: | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| # 릴리즈 생성 | |
| - name: Create Release | |
| uses: actions/create-release@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: ${{ steps.create_tag.outputs.new_tag }} | |
| release_name: Release ${{ steps.create_tag.outputs.new_tag }} | |
| body: ${{ steps.create_tag.outputs.changelog }} | |
| draft: false | |
| prerelease: false | |
| # --------------------------------------------------------- | |
| # 3) 도커 이미지 빌드/푸시 | |
| # --------------------------------------------------------- | |
| buildImageAndPush: | |
| name: 도커 이미지 빌드와 푸시 | |
| needs: makeTagAndRelease | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 코드 체크아웃 | |
| uses: actions/checkout@v4 | |
| - name: .env 파일 생성 | |
| env: | |
| DOT_ENV: ${{ secrets.DOT_ENV }} | |
| run: | | |
| mkdir -p "${{ env.BACKEND_DIR }}" | |
| printf "%s" "${DOT_ENV}" > "${{ env.BACKEND_DIR }}/.env" | |
| - name: Docker Buildx 설치 | |
| uses: docker/setup-buildx-action@v3 | |
| # GHCR 로그인 | |
| - name: 레지스트리 로그인 | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # 저장소 소유자명을 소문자로 (GHCR 경로 표준화) | |
| - name: set lower case owner name | |
| run: | | |
| echo "OWNER_LC=${OWNER,,}" >> "${GITHUB_ENV}" | |
| env: | |
| OWNER: "${{ github.repository_owner }}" | |
| # 캐시를 최대한 활용하여 빌드 → 버전태그 및 latest 동시 푸시 | |
| - name: 빌드 앤 푸시 | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ${{ env.BACKEND_DIR }} | |
| push: true | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| tags: | | |
| ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_REPOSITORY }}:${{ needs.makeTagAndRelease.outputs.tag_name }} | |
| ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_REPOSITORY }}:latest | |
| # --------------------------------------------------------- | |
| # 4) 배포 | |
| # --------------------------------------------------------- | |
| deploy: | |
| name: 배포 | |
| needs: [makeTagAndRelease, buildImageAndPush] | |
| runs-on: ubuntu-latest | |
| steps: | |
| # AWS 자격 구성 | |
| - name: AWS 자격 구성 | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| aws-region: ${{ secrets.AWS_REGION }} | |
| aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| # Name 태그로 EC2 인스턴스 조회 | |
| - name: 인스턴스 ID 가져오기 | |
| id: get_instance_id | |
| run: | | |
| INSTANCE_ID=$(aws ec2 describe-instances \ | |
| --filters "Name=tag:Name,Values=${{ env.EC2_INSTANCE_TAG_NAME }}" "Name=instance-state-name,Values=running" \ | |
| --query "Reservations[].Instances[].InstanceId" --output text) | |
| if [[ -z "${INSTANCE_ID}" || "${INSTANCE_ID}" == "None" ]]; then | |
| echo "❌ 실행 중인 EC2 인스턴스를 찾을 수 없습니다." | |
| exit 1 | |
| fi | |
| echo "✅ EC2 인스턴스 발견: ${INSTANCE_ID}" | |
| echo "INSTANCE_ID=${INSTANCE_ID}" >> "${GITHUB_ENV}" | |
| # SSM으로 배포 수행 | |
| - name: AWS SSM Send-Command로 배포 | |
| uses: peterkimzz/aws-ssm-send-command@master | |
| with: | |
| aws-region: ${{ secrets.AWS_REGION }} | |
| aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| instance-ids: ${{ env.INSTANCE_ID }} | |
| working-directory: /home/ssm-user | |
| comment: Deploy Spring Boot Application | |
| command: | | |
| set -Eeuo pipefail | |
| # 로그 파일 설정 | |
| LOG="/tmp/deploy-$(date +%Y%m%d_%H%M%S).log" | |
| exec > >(awk '{ fflush(); print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }' | tee -a "$LOG") | |
| exec 2> >(awk '{ fflush(); print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }' | tee -a "$LOG" >&2) | |
| echo "🚀 배포 시작..." | |
| # 환경변수 로드 | |
| source /etc/environment || true | |
| # 이미지 정보 설정 | |
| OWNER_LC="${{ github.repository_owner }}" | |
| OWNER_LC="${OWNER_LC,,}" | |
| IMAGE_TAG='${{ needs.makeTagAndRelease.outputs.tag_name }}' | |
| IMAGE_REPOSITORY='${{ env.IMAGE_REPOSITORY }}' | |
| IMAGE="ghcr.io/${OWNER_LC}/${IMAGE_REPOSITORY}:${IMAGE_TAG}" | |
| CONTAINER_NAME="${{ env.CONTAINER_NAME }}" | |
| NET="${{ env.DOCKER_NETWORK }}" | |
| echo "📦 이미지: ${IMAGE}" | |
| echo "📦 컨테이너: ${CONTAINER_NAME}" | |
| # 프로젝트 디렉토리로 이동 | |
| cd ~/WEB6_8_FiveLogic_BE || exit 1 | |
| # 최신 이미지 pull | |
| echo "📥 Docker 이미지 다운로드 중..." | |
| docker pull $IMAGE | |
| # 기존 컨테이너 중지 및 삭제 | |
| echo "🛑 기존 컨테이너 중지 중..." | |
| docker-compose stop $CONTAINER_NAME || true | |
| docker-compose rm -f $CONTAINER_NAME || true | |
| # docker-compose.yml 이미지 업데이트 | |
| sed -i "s|image:.*${IMAGE_REPOSITORY}.*|image: ${IMAGE}|g" docker-compose.yml | |
| # 새 컨테이너 시작 | |
| echo "🚀 새 컨테이너 시작 중..." | |
| docker-compose up -d $CONTAINER_NAME | |
| # 헬스체크 | |
| echo "🏥 헬스체크 중..." | |
| for i in {1..30}; do | |
| if docker exec $CONTAINER_NAME curl -f http://localhost:8080/health > /dev/null 2>&1; then | |
| echo "✅ 서버 정상 구동!" | |
| break | |
| fi | |
| echo "대기 중... ($i/30)" | |
| sleep 2 | |
| done | |
| # 컨테이너 상태 확인 | |
| echo "📊 컨테이너 상태:" | |
| docker-compose ps $CONTAINER_NAME | |
| # 최근 로그 출력 | |
| echo "📋 최근 로그:" | |
| docker-compose logs --tail=50 $CONTAINER_NAME | |
| # 오래된 이미지 정리 | |
| echo "🧹 오래된 이미지 정리 중..." | |
| { | |
| docker images --format '{{.Repository}}:{{.Tag}}' \ | |
| | grep -F "ghcr.io/${OWNER_LC}/${IMAGE_REPOSITORY}:" \ | |
| | grep -v -F ":${IMAGE_TAG}" \ | |
| | grep -v -F ":latest" \ | |
| | xargs -r docker rmi | |
| } || true | |
| echo "✅ 배포 완료!" |