Merge pull request #158 from TimeBank-Sparta/20152842-patch-61 #107
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 (Blue-Green) | |
| on: | |
| push: | |
| branches: | |
| - develop | |
| - main | |
| workflow_dispatch: | |
| jobs: | |
| deploy: | |
| runs-on: ubuntu-latest | |
| env: | |
| SLACK_DEV_WEBHOOK_URL: ${{ secrets.SLACK_DEV_WEBHOOK_URL }} | |
| SLACK_PROD_WEBHOOK_URL: ${{ secrets.SLACK_PROD_WEBHOOK_URL }} | |
| SERVICES: "gateway-service help-service notification-service review-service point-service user-service config-server eureka-server" | |
| EC2_HOST: ${{ secrets.EC2_HOST }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to DockerHub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Define TAG | |
| id: define_tag | |
| run: echo "TAG=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV | |
| - name: Detect Changed Services | |
| id: detect_services | |
| run: | | |
| CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }}) | |
| if echo "$CHANGED_FILES" | grep -Eq '(^build.gradle|^settings.gradle|^gradlew|^gradlew\.bat|^build\.gradle\.kts|^common/)'; then | |
| echo "CHANGED=ALL" >> $GITHUB_ENV | |
| else | |
| CHANGED=$(echo "$CHANGED_FILES" \ | |
| | grep -E '^(gateway-service|help-service|notification-service|review-service|point-service|user-service|config-server|eureka-server)/' \ | |
| | awk -F/ '{print $1}' | sort -u | xargs) | |
| echo "CHANGED=$CHANGED" >> $GITHUB_ENV | |
| fi | |
| - name: Count existing services on EC2 | |
| id: remote_count | |
| uses: appleboy/ssh-action@v0.1.8 | |
| with: | |
| host: ${{ secrets.EC2_HOST }} | |
| username: ${{ secrets.EC2_USER }} | |
| key: ${{ secrets.EC2_SSH_KEY }} | |
| port: 22 | |
| sync: true | |
| script: | | |
| docker ps \ | |
| --filter name=gateway-blue \ | |
| --filter name=gateway-green \ | |
| --filter name=help-service \ | |
| --filter name=notification-service \ | |
| --filter name=review-service \ | |
| --filter name=point-service \ | |
| --filter name=user-service \ | |
| --filter name=config-server \ | |
| --filter name=eureka-server \ | |
| --format '{{.Names}}' | wc -l | |
| - name: Export EXISTING_COUNT | |
| run: | | |
| RAW="${{ steps.remote_count.outputs.stdout || '0' }}" | |
| NUM=$(echo "$RAW" | tr -cd '0-9') | |
| echo "EXISTING_COUNT=$NUM" >> $GITHUB_ENV | |
| - name: Decide whether to skip deploy | |
| run: | | |
| echo "Existing containers: $EXISTING_COUNT" | |
| if [ -z "$CHANGED" ] && [ "$EXISTING_COUNT" -gt 13 ]; then | |
| echo "No changes & already deployed → skipping" | |
| exit 0 | |
| fi | |
| - name: Build & Push images | |
| id: build_push | |
| run: | | |
| if [ "$CHANGED" = "ALL" ] || { [ -z "$CHANGED" ] && [ "$EXISTING_COUNT" -le 13 ]; }; then | |
| TARGETS=($SERVICES) | |
| else | |
| TARGETS=($CHANGED) | |
| fi | |
| echo "Deploy targets: ${TARGETS[*]}" | |
| for svc in "${TARGETS[@]}"; do | |
| docker build -t namgyu967/$svc:${TAG} -f $svc/Dockerfile . | |
| docker push namgyu967/$svc:${TAG} | |
| docker tag namgyu967/$svc:${TAG} namgyu967/$svc:latest | |
| docker push namgyu967/$svc:latest | |
| done | |
| echo "TARGETS=${TARGETS[*]}" >> $GITHUB_ENV | |
| - name: EC2에 Blue-Green 및 서비스 배포 | |
| uses: appleboy/ssh-action@master | |
| with: | |
| host: ${{ secrets.EC2_HOST }} | |
| username: ${{ secrets.EC2_USER }} | |
| key: ${{ secrets.EC2_SSH_KEY }} | |
| port: 22 | |
| protocol: tcp | |
| sync: true | |
| debug: true | |
| capture_stdout: true | |
| curl_insecure: false | |
| envs: | | |
| TAG=${{ env.TAG }} | |
| SERVICES=${{ env.SERVICES }} | |
| CHANGED=${{ env.CHANGED }} | |
| script: | | |
| set -e | |
| cd ~/timebank | |
| source .env-tag | |
| docker-compose up -d nginx | |
| if docker-compose ps | grep -q gateway-blue; then | |
| NEW=green; OLD=blue | |
| else | |
| NEW=blue; OLD=green | |
| fi | |
| docker-compose pull gateway-$NEW | |
| docker-compose up -d gateway-$NEW | |
| sed -i "s/server gateway-$OLD:8080;/server gateway-$NEW:8080;/" nginx-conf/gw.conf | |
| docker exec nginx nginx -s reload | |
| if [ "${CHANGED}" = "ALL" ] || [ -z "${CHANGED}" ]; then | |
| IFS=' ' read -r -a targets <<< "${SERVICES}" | |
| else | |
| IFS=' ' read -r -a targets <<< "${CHANGED}" | |
| fi | |
| echo "=== DEBUG:Final deploy targets ===" | |
| for svc in "${targets[@]}"; do | |
| echo " - $svc" | |
| done | |
| for svc in "${targets[*]}"; do | |
| [ "$svc" = "gateway-service" ] && continue | |
| echo "Deploying $svc..." | |
| docker-compose pull $svc | |
| docker-compose up -d $svc | |
| done | |
| - name: 헬스체크 및 결과 수집 | |
| id: health | |
| shell: bash | |
| run: | | |
| set +e | |
| SUCCESS=""; FAILED="" | |
| BASE="http://${{ env.EC2_HOST }}" | |
| # 헬스체크 대상도 동일하게 계산 | |
| if [ "${CHANGED}" = "ALL" ] || [ -z "${CHANGED}" ]; then | |
| IFS=' ' read -r -a targets <<< "${SERVICES}" | |
| else | |
| IFS=' ' read -r -a targets <<< "${CHANGED}" | |
| fi | |
| for svc in "${targets[@]}"; do | |
| if [ "$svc" = "gateway-service" ]; then | |
| END="$BASE/actuator/health" | |
| else | |
| END="$BASE/$svc/actuator/health" | |
| fi | |
| for i in {1..10}; do | |
| sleep 5 | |
| CODE=$(curl -s -o /dev/null -w "%{http_code}" "$END" || echo "000") | |
| if [ "$CODE" = "200" ]; then | |
| SUCCESS="$SUCCESS $svc" | |
| break | |
| fi | |
| [ "$i" -eq 10 ] && FAILED="$FAILED $svc" | |
| done | |
| done | |
| echo "SUCCESS=${SUCCESS:-none}" >> $GITHUB_ENV | |
| echo "FAILED=${FAILED:-none}" >> $GITHUB_ENV | |
| - name: Slack Notification (Success) | |
| if: success() | |
| uses: slackapi/slack-github-action@v1.24.0 | |
| with: | |
| payload: | | |
| { | |
| "text": "${{ github.ref == 'refs/heads/main' && ':white_check_mark: *[PROD]* 배포 성공!*' || ':white_check_mark: *[DEV]* 배포 성공!*' }}\n> 대상: ${{ env.TARGETS || 'all' }}\n> 정상: ${{ env.SUCCESS }}\n> 실패: ${{ env.FAILED }}\n> 태그: ${{ env.TAG }}\n> Eureka Server: http://${{ env.EC2_HOST }}:8761" | |
| } | |
| env: | |
| SLACK_WEBHOOK_URL: ${{ github.ref == 'refs/heads/main' && secrets.SLACK_PROD_WEBHOOK_URL || secrets.SLACK_DEV_WEBHOOK_URL }} | |
| - name: Slack Notification (Failure) | |
| if: failure() | |
| uses: slackapi/slack-github-action@v1.24.0 | |
| with: | |
| payload: | | |
| { | |
| "text": "${{ github.ref == 'refs/heads/main' && ':x: *[PROD]* 배포 실패!*' || ':x: *[DEV]* 배포 실패!*' }}\n> 에러 확인해주세요." | |
| } | |
| env: | |
| SLACK_WEBHOOK_URL: ${{ github.ref == 'refs/heads/main' && secrets.SLACK_PROD_WEBHOOK_URL || secrets.SLACK_DEV_WEBHOOK_URL }} |