-
Notifications
You must be signed in to change notification settings - Fork 2
214 lines (193 loc) · 8.76 KB
/
deploy.yml
File metadata and controls
214 lines (193 loc) · 8.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
name: Build & Deploy (backend + frontend)
on:
workflow_dispatch: {}
push:
branches: ["main"]
paths:
- "backend/**"
- "frontend/**" # 프론트 변경에도 트리거
- "docker-compose.yml"
- ".github/workflows/deploy.yml"
concurrency:
group: deploy-main
cancel-in-progress: true
env:
REGISTRY: ghcr.io
IMAGE_BACK: ghcr.io/sisc-it/sisc-web-back
IMAGE_FRONT: ghcr.io/sisc-it/sisc-web-front # 프론트 이미지 추가
jobs:
# 1. 변경 감지 (변동 없음)
changes:
runs-on: ubuntu-latest
outputs:
back: ${{ steps.filter.outputs.back }}
front: ${{ steps.filter.outputs.front }}
steps:
- name: Checkout (full history)
uses: actions/checkout@v4
#with: # Git 히스토리를 처음부터 끝까지 가져오기.
# fetch-depth: 0 # 개발 배포는 최신 코드만 있으면 됨 (기본값 1)
- name: Detect path changes
id: filter
uses: dorny/paths-filter@v3
with:
filters: |
back:
- 'backend/**'
- 'docker-compose.yml' # ⬅ 추가
- '.github/workflows/deploy.yml' # ⬅ 추가
front:
- 'frontend/**'
- 'docker-compose.yml' # ⬅ 추가
- '.github/workflows/deploy.yml' # ⬅ 추가
# 2. 백엔드 빌드
build-back:
needs: [changes] # deploy는 job 들이 병렬 처리가 되므로, 리스트 항목이 모두 끝나야 시작된다는 조건 추가
#if: ${{ needs.changes.outputs.back == 'true' || github.event_name == 'workflow_dispatch' }}
environment: development
runs-on: ubuntu-latest
permissions: { contents: read, packages: write }
#defaults:
# run:
# working-directory: backend # context: ./backend 로 지정했기 때문에 필요X
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} # 실행 중인 유저 이름 자동 할당
password: ${{ secrets.GITHUB_TOKEN }} # 별도 설정 없이 바로 사용 가능
- uses: docker/setup-buildx-action@v3
# 이미지 태그를 예쁘게 만들지만, 개발서버는 latest만 있으면 됨. (예: sha-a1b2c3d, v1.0.0, pr-123)
#- name: Meta (tags/labels) - backend
# id: meta-back
# uses: docker/metadata-action@v5
# with:
# images: ${{ env.IMAGE_BACK }}
# tags: |
# type=raw,value=latest
# type=sha,prefix=sha-,format=short
- name: Build & Push (backend)
uses: docker/build-push-action@v6
with:
context: ./backend
push: true
tags: ${{ env.IMAGE_BACK }}:latest
#tags: ${{ steps.meta-back.outputs.tags }}
#labels: ${{ steps.meta-back.outputs.labels }}
#cache-from: type=gha
#cache-to: type=gha,mode=max
build-front:
needs: [changes] # deploy는 job 들이 병렬 처리가 되므로, 리스트 항목이 모두 끝나야 시작된다는 조건 추가
#if: ${{ needs.changes.outputs.front == 'true' || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest
environment: development # development 이라는 environment에 있는 secrets 들을 쓰기 위함 (secrets.FRONTEND_URL)
permissions: { contents: read, packages: write }
#defaults: # context: ./frontend
# run:
# working-directory: frontend
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} # 실행 중인 유저 이름 자동 할당
password: ${{ secrets.GITHUB_TOKEN }} # 별도 설정 없이 바로 사용 가능
#- name: Meta (tags/labels) - frontend
# id: meta-front
# uses: docker/metadata-action@v5
# with:
# images: ${{ env.IMAGE_FRONT }}
# tags: |
# type=raw,value=latest
# type=sha,prefix=sha-,format=short
- uses: docker/setup-buildx-action@v3
- name: Build & Push (frontend)
uses: docker/build-push-action@v6
with:
context: ./frontend # ⬅ 프론트 도커 컨텍스트 위치
push: true
platforms: linux/amd64
tags: ${{ env.IMAGE_FRONT }}:latest
#tags: ${{ steps.meta-front.outputs.tags }}
#labels: ${{ steps.meta-front.outputs.labels }}
build-args: |
VITE_API_URL=${{ secrets.SPRING_API_URL }}
#cache-from: type=gha
#cache-to: type=gha,mode=max
deploy:
#if: ${{ always() && (needs.build-back.result == 'success' || needs.build-front.result == 'success') }}
needs: [changes, build-back, build-front] # deploy는 job 들이 병렬 처리가 되므로, 리스트 항목이 모두 끝나야 시작된다는 조건 추가
# - manual 실행(workflow_dispatch)이면 무조건 실행
# - push일 때는 둘 중 하나라도 성공한 경우에만 실행 (둘 다 failure가 아닌 이상 OK)
runs-on: ubuntu-latest
environment: development # development 환경의 repository secrets 사용
steps:
- uses: actions/checkout@v4
- name: Make .env file
run: |
# 1. 기본 설정, 첫 줄은 > (덮어쓰기, >>:이어쓰기)
echo "SPRING_PROFILES_ACTIVE=prod" > .env
# 2. DB (GitHub Secrets)
echo "DB_URL=${{ secrets.DB_URL }}" >> .env
echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> .env
echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env
# 3. 기타 Secrets
echo "SPRING_API_URL=${{ secrets.SPRING_API_URL }}" >> .env
echo "FRONTEND_URL=${{ secrets.FRONTEND_URL }}" >> .env
echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env
echo "MAIL_USERNAME=${{ secrets.MAIL_USERNAME }}" >> .env
echo "MAIL_PASSWORD=${{ secrets.MAIL_PASSWORD }}" >> .env
echo "SBA_ADMIN_NAME=${{ secrets.SBA_ADMIN_NAME }}" >> .env
echo "SBA_ADMIN_PASSWORD=${{ secrets.SBA_ADMIN_PASSWORD }}" >> .env
# 필요하다면 풀 사이즈 변수도 추가
# echo "DB_POOL_MAX=30" >> .env
# echo "STOCK_POOL_MAX=10" >> .env
- name: 파일 전송 (docker-compose, .env to EC2)
uses: appleboy/scp-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.SSH_PORT }}
source: "docker-compose.yml, .env"
target: "/home/${{ secrets.SSH_USER }}/app/sisc-web/"
- name: SSH deploy
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.SSH_PORT }}
script_stop: true
script: |
set -euo pipefail
# 필수 폴더 생성 및 권한 설정 (최초 1회 혹은 누락 대비)
# sudo mkdir -p /mnt/storage/pg_ai_data /mnt/storage/logs /mnt/storage/uploads ./data/postgres
# sudo chown -R 70:70 /mnt/storage/pg_ai_data ./data/postgres # DB 전용
# sudo chmod -R 777 /mnt/storage/logs /mnt/storage/uploads # 앱 공용
cd ~/app/sisc-web
# GHCR 로그인 (백/프론트 둘 다 같은 레지스트리 사용)
echo "${{ secrets.GHCR_READ_TOKEN }}" | docker login ghcr.io -u ${{ secrets.GHCR_READ_USER }} --password-stdin
# 실행
docker compose pull api web redis npm # 최신 이미지 받기 (backend, frontend만)
docker compose up -d --remove-orphans api web redis npm db # 컨테이너 재기동 (backend, frontend만)
docker image prune -a -f
# 백엔드 헬스체크 (서비스 이름이 api일 때)
if docker ps --format '{{.Names}}' | grep -q "^api$"; then
echo "Waiting for api to be healthy..."
for i in {1..30}; do
status=$(docker inspect --format='{{json .State.Health.Status}}' api 2>/dev/null || echo '"none"')
if echo "$status" | grep -q healthy; then
echo "=== 서버 정상 작동 확인 ==="; break
fi
sleep 2
done
fi
# 도커 용량 최적화
- name: Cleanup Docker
run: |
# 빌드 과정에서 생긴 모든 캐시 삭제 (-a 옵션이 핵심)
docker builder prune -a -f
# 태그가 없어진 이미지 삭제
docker image prune -a -f