Skip to content

Commit 29fbca8

Browse files
kkiseugdompoo
authored andcommitted
인프라 이사를 위한 CD 스크립트 수정 (#571)
* chore: dev 서버 스크립트 변경 * chore: 테스트를 위해 바꾼 조건 재변경 * chore: prod cd 스크립트 수정 * fix: cd 스크립트 픽스 * refactor: 배포 스크립트 girhub actions script로 통일 * refactor: 배포 과정에서 CI 과정 ci 스크립트로 수행하도록 변경 * refactor: env 파일 생성 과정 추가 * chore: prod 테스트를 위한 조건 원복 * chore: 개발 서버 배포 테스트를 위한 조건 변경 * refactor: ci/cd 과정 분리 * fix: build 문제 해결 * refactor: ci 과정과 네이밍 통합 * refactor: 테스트를 위해 설정한 조건 복원 * refactor: 운영서버 스크립트 수정 * refactor: 운영서버 브랜치 수정 * test: 운영 서버 테스트 * refactor: 테스트를 위한 조건 복원
1 parent 8316877 commit 29fbca8

File tree

4 files changed

+108
-211
lines changed

4 files changed

+108
-211
lines changed

.github/workflows/backend-ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: Backend CI
22

33
on:
4+
workflow_call:
45
pull_request:
56
branches: [ backend ]
67
workflow_dispatch:

.github/workflows/backend-dev-cd.yml

Lines changed: 51 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@ on:
66
workflow_dispatch:
77

88
jobs:
9+
ci:
10+
name: CI 실행
11+
uses: ./.github/workflows/backend-ci.yml
12+
secrets: inherit
13+
914
build:
1015
name: 도커 이미지 빌드 & 푸시
16+
needs: ci
1117
runs-on: ubuntu-latest
1218
defaults:
1319
run:
@@ -24,16 +30,11 @@ jobs:
2430
distribution: 'corretto'
2531
cache: 'gradle'
2632

27-
- name: 프로젝트 gradlew 빌드
28-
run: ./gradlew build
33+
- name: gradlew 실행 권한 부여
34+
run: chmod +x gradlew
2935

30-
- name: 테스트 결과 보고서 작성
31-
uses: dorny/test-reporter@v1
32-
if: success() || failure()
33-
with:
34-
name: 테스트 결과
35-
path: backend/build/test-results/test/*.xml
36-
reporter: java-junit
36+
- name: 프로젝트 gradlew 빌드
37+
run: ./gradlew clean build -x test
3738

3839
- name: Docker 로그인
3940
uses: docker/login-action@v3
@@ -52,49 +53,47 @@ jobs:
5253
deploy:
5354
name: 개발서버 배포
5455
needs: build
55-
runs-on: [ self-hosted, dev-app ]
56-
defaults:
57-
run:
58-
working-directory: /home/ssm-user/coursepick
56+
runs-on: ubuntu-latest
5957

6058
steps:
61-
- name: Docker 로그인
62-
uses: docker/login-action@v3
59+
- name: SSH로 배포 스크립트 실행
60+
uses: appleboy/ssh-action@v1.0.0
6361
with:
64-
username: ${{ secrets.DOCKER_USERNAME }}
65-
password: ${{ secrets.DOCKER_PASSWORD }}
66-
67-
- name: .env 파일 생성
68-
run: |
69-
cat > .env <<'EOF'
70-
${{ secrets.DEV_ENV_FILE }}
71-
EOF
72-
chmod 600 .env
73-
74-
- name: 새로운 서버 시작
75-
run: |
76-
sudo docker compose --env-file .env up -d --pull always backend
77-
78-
- name: 사용하지 않는 도커 이미지 정리
79-
run: |
80-
sudo docker image prune -a -f
81-
82-
- name: 시작된 서버 헬스체크
83-
run: |
84-
for i in $(seq 1 10)
85-
do
86-
SERVER_STATUS=$(curl -o /dev/null -w "%{http_code}" http://localhost:80/actuator/health || true)
87-
88-
if [ "$SERVER_STATUS" -eq 200 ]; then
89-
echo "서버 정상적으로 실행됨 status=$SERVER_STATUS"
90-
break
91-
else
92-
echo "헬스체크에 실패함. 5초 후 다시 시도"
93-
sleep 5
94-
fi
95-
96-
if [ $i -eq 10 ]; then
97-
echo "서버가 정상적으로 실행되지 않아 종료함"
98-
exit 1
99-
fi
100-
done
62+
host: ${{ secrets.DEV_SERVER_HOST }}
63+
username: ubuntu
64+
key: ${{ secrets.SSH_PRIVATE_KEY }}
65+
script: |
66+
cd /home/ubuntu/coursepick
67+
68+
echo "🚀 개발 서버 배포 시작..."
69+
70+
echo "📦 최신 이미지 Pull..."
71+
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/coursepick-backend:dev
72+
73+
echo "🌳 .env 파일 생성..."
74+
cat > .env <<'EOF'
75+
${{ secrets.DEV_ENV_FILE }}
76+
EOF
77+
chmod 600 .env
78+
79+
echo "▶️ 새 서버 시작..."
80+
sudo docker compose --env-file .env up -d --pull always backend
81+
82+
echo "🧹 사용하지 않는 이미지 정리..."
83+
sudo docker image prune -a -f
84+
85+
echo "⛑️ 헬스 체크..."
86+
for i in $(seq 1 10); do
87+
SERVER_STATUS=$(curl -o /dev/null -w "%{http_code}" http://localhost:80/actuator/health || echo "000")
88+
if [ "$SERVER_STATUS" -eq 200 ]; then
89+
echo "✅ 배포 성공! 서버 동작 중..."
90+
exit 0
91+
else
92+
echo "Attempt $i/10: 헬스 체크 실패 (status=$SERVER_STATUS). 5초 후 재시도..."
93+
sleep 5
94+
fi
95+
done
96+
97+
echo "❌ 배포 실패! 서버가 동작하지 않습니다."
98+
sudo docker logs coursepick-backend --tail 50
99+
exit 1

.github/workflows/backend-prod-app-cd.yml

Lines changed: 0 additions & 86 deletions
This file was deleted.

.github/workflows/backend-prod-cd.yml

Lines changed: 56 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ on:
99
workflow_dispatch:
1010

1111
jobs:
12+
ci:
13+
name: CI 실행
14+
uses: ./.github/workflows/backend-ci.yml
15+
secrets: inherit
16+
1217
build:
13-
name: 프로젝트 빌드
18+
name: 도커 이미지 빌드 & 푸시
19+
needs: ci
1420
runs-on: ubuntu-latest
1521
defaults:
1622
run:
@@ -27,16 +33,11 @@ jobs:
2733
distribution: 'corretto'
2834
cache: 'gradle'
2935

30-
- name: 프로젝트 gradlew 빌드
31-
run: ./gradlew build
36+
- name: gradlew 실행 권한 부여
37+
run: chmod +x gradlew
3238

33-
- name: 테스트 결과 보고서 작성
34-
uses: dorny/test-reporter@v1
35-
if: success() || failure()
36-
with:
37-
name: 테스트 결과
38-
path: backend/build/test-results/test/*.xml
39-
reporter: java-junit
39+
- name: 프로젝트 gradlew 빌드
40+
run: ./gradlew clean build -x test
4041

4142
- name: Docker 로그인
4243
uses: docker/login-action@v3
@@ -52,68 +53,50 @@ jobs:
5253
--push \
5354
.
5455
55-
# 1) 유휴 서버 탐지
56-
detect-idle:
57-
name: 쉬고있는 EC2 서버 탐지
56+
deploy:
57+
name: 운영서버 배포
5858
needs: build
59-
runs-on: [ self-hosted, prod-lb ]
60-
outputs:
61-
idle-server: ${{ steps.find.outputs.idle }}
62-
steps:
63-
- name: 탐침 스크립트 실행
64-
id: find
65-
run: |
66-
declare -A servers=(
67-
[prod-app-1]="${{ secrets.PROD_APP_1_HEALTH_URL }}"
68-
[prod-app-2]="${{ secrets.PROD_APP_2_HEALTH_URL }}"
69-
)
70-
71-
idle_servers=()
72-
73-
for name in "${!servers[@]}"; do
74-
url="${servers[$name]}"
75-
code=$(curl -s -o /dev/null -w "%{http_code}" "$url" || echo "")
76-
if [[ "$code" -eq 200 ]]; then
77-
echo "$name 응답 성공"
78-
else
79-
echo "$name 응답 실패"
80-
idle_servers+=("$name")
81-
fi
82-
done
83-
84-
if [[ ${#idle_servers[@]} -eq 0 ]]; then
85-
echo "Both servers are healthy – cannot find idle server"
86-
elif [[ ${#idle_servers[@]} -eq 1 ]]; then
87-
idle="${idle_servers[0]}"
88-
echo "One server is idle, idle=$idle"
89-
echo "idle=$idle" >> $GITHUB_OUTPUT
90-
else
91-
idle="prod-app-1"
92-
echo "None servers are idle – as default, deploy to server1, idle=$idle"
93-
echo "idle=$idle" >> $GITHUB_OUTPUT
94-
fi
95-
96-
echo "idle=$idle" >> $GITHUB_OUTPUT
97-
98-
# 2) 유휴 서버에 배포 (server1 / server2 중 하나만 실행)
99-
deploy-prod-app-1:
100-
name: prod-app-1 서버에 배포
101-
needs: detect-idle
102-
if: needs.detect-idle.outputs.idle-server == 'prod-app-1'
103-
uses: ./.github/workflows/backend-prod-app-cd.yml
104-
with:
105-
run_id: ${{ github.run_id }}
106-
main_runner: prod-app-1
107-
sub_runner: prod-app-2
108-
secrets: inherit
59+
runs-on: ubuntu-latest
10960

110-
deploy-prod-app-2:
111-
name: prod-app-2 서버에 배포
112-
needs: detect-idle
113-
if: needs.detect-idle.outputs.idle-server == 'prod-app-2'
114-
uses: ./.github/workflows/backend-prod-app-cd.yml
115-
with:
116-
run_id: ${{ github.run_id }}
117-
main_runner: prod-app-2
118-
sub_runner: prod-app-1
119-
secrets: inherit
61+
steps:
62+
- name: SSH로 배포 스크립트 실행
63+
uses: appleboy/ssh-action@v1.0.0
64+
with:
65+
host: ${{ secrets.PROD_SERVER_HOST }}
66+
username: ubuntu
67+
key: ${{ secrets.SSH_PRIVATE_KEY }}
68+
script: |
69+
cd /home/ubuntu/coursepick
70+
71+
echo "🚀 운영 서버 배포 시작..."
72+
73+
echo "📦 최신 이미지 Pull..."
74+
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/coursepick-backend:prod
75+
76+
echo "🌳 .env 파일 생성..."
77+
cat > .env <<'EOF'
78+
${{ secrets.PROD_ENV_FILE }}
79+
EOF
80+
chmod 600 .env
81+
82+
echo "▶️ 새 서버 시작..."
83+
sudo docker compose --env-file .env up -d --pull always backend
84+
85+
echo "🧹 사용하지 않는 이미지 정리..."
86+
sudo docker image prune -a -f
87+
88+
echo "⛑️ 헬스 체크..."
89+
for i in $(seq 1 10); do
90+
SERVER_STATUS=$(curl -o /dev/null -w "%{http_code}" http://localhost:80/actuator/health || echo "000")
91+
if [ "$SERVER_STATUS" -eq 200 ]; then
92+
echo "✅ 배포 성공! 서버 동작 중..."
93+
exit 0
94+
else
95+
echo "Attempt $i/10: 헬스 체크 실패 (status=$SERVER_STATUS). 5초 후 재시도..."
96+
sleep 5
97+
fi
98+
done
99+
100+
echo "❌ 배포 실패! 서버가 동작하지 않습니다."
101+
sudo docker logs coursepick-backend --tail 50
102+
exit 1

0 commit comments

Comments
 (0)