From d62d1aba4341938797e1e8d8175afba379844e4d Mon Sep 17 00:00:00 2001 From: heygeeji Date: Tue, 6 Jan 2026 01:45:38 +0900 Subject: [PATCH 1/2] =?UTF-8?q?cd:=20blue/green=20=EB=B0=B0=ED=8F=AC=20?= =?UTF-8?q?=EA=B8=B0=EB=B0=98=20CD=20=ED=8C=8C=EC=9D=B4=ED=94=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20=EA=B5=AC=EC=B6=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd.yml | 73 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 .github/workflows/cd.yml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 00000000..4c89397f --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,73 @@ +name: CD - Blue Green Deploy + +on: + push: + branches: [ release ] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + # 1. 소스 체크아웃 + - name: Checkout + uses: actions/checkout@v4 + + # 2. Docker Hub 로그인 + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # 3. Docker 이미지 빌드 & 푸시 + - name: Build & Push Docker Image + run: | + docker build -t heygeeji/ncb-backend:latest . + docker push heygeeji/ncb-backend:latest + + # 4. EC2 배포 (Blue/Green + Rollback) + - name: Deploy to EC2 + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.EC2_HOST }} + username: ec2-user + key: ${{ secrets.EC2_SSH_KEY }} + script: | + set -e + cd ~/deploy + + echo "🔍 Detecting active container..." + + if docker ps --filter "name=concert-spring-blue" --format "{{.Status}}" | grep -q healthy; then + ACTIVE=blue + TARGET=green + PORT=8082 + else + ACTIVE=green + TARGET=blue + PORT=8081 + fi + + echo "🟦 Active: $ACTIVE" + echo "🟩 Deploy target: $TARGET" + + echo "📥 Pull latest image" + docker compose -f docker-compose-prod.yml pull spring-$TARGET + + echo "🚀 Start spring-$TARGET" + docker compose -f docker-compose-prod.yml up -d spring-$TARGET + + echo "⏳ Waiting for health check on $PORT..." + for i in {1..20}; do + if curl -sf http://localhost:$PORT/actuator/health > /dev/null; then + echo "✅ spring-$TARGET is healthy" + exit 0 + fi + echo "⏳ still waiting..." + sleep 5 + done + + echo "❌ Health check failed for spring-$TARGET - rolling back" + docker compose -f docker-compose-prod.yml stop spring-$TARGET + exit 1 From 53f63ccca1096c9ca1f4d030654b29ce09535d6d Mon Sep 17 00:00:00 2001 From: heygeeji Date: Tue, 6 Jan 2026 02:21:33 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20CD=20=ED=97=AC=EC=8A=A4=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=20=EB=A3=A8=ED=94=84=20=EC=A2=85=EB=A3=8C=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 4c89397f..f2054a2d 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -59,14 +59,20 @@ jobs: docker compose -f docker-compose-prod.yml up -d spring-$TARGET echo "⏳ Waiting for health check on $PORT..." + HEALTHY=false for i in {1..20}; do if curl -sf http://localhost:$PORT/actuator/health > /dev/null; then - echo "✅ spring-$TARGET is healthy" - exit 0 + HEALTHY=true + break fi echo "⏳ still waiting..." sleep 5 done + + if [ "$HEALTHY" = "true" ]; then + echo "✅ spring-$TARGET is healthy" + exit 0 + fi echo "❌ Health check failed for spring-$TARGET - rolling back" docker compose -f docker-compose-prod.yml stop spring-$TARGET