Skip to content

Commit 89dc5b0

Browse files
authored
Merge: Staging서버 오픈 (#173)
Feat: 🎉 Staging서버 오픈 🎉
2 parents f8614b4 + cdea59e commit 89dc5b0

File tree

13 files changed

+533
-78
lines changed

13 files changed

+533
-78
lines changed

.github/workflows/ci-cd.yml

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ name: CI/CD — Backend (Build → Push → Deploy)
22

33
on:
44
push:
5-
branches: [ dev ]
5+
branches: [ dev, staging ]
66
pull_request:
7-
branches: [ dev ]
7+
branches: [ dev, staging ]
88
workflow_dispatch:
99
inputs:
1010
tag:
11-
description: "배포할 이미지 태그 (ex. release or <GIT_SHA>)"
11+
description: "배포할 이미지 태그 (ex. dev or dev-SHORT_SHA)"
1212
required: false
13-
default: "release"
13+
default: "dev"
1414

1515
concurrency:
1616
group: cicd-${{ github.ref_name }}
@@ -81,17 +81,32 @@ jobs:
8181
username: ${{ github.actor }}
8282
password: ${{ secrets.GITHUB_TOKEN }}
8383

84-
- name: Build & Push image
84+
- name: Decide tags by branch
85+
if: github.event_name == 'push'
86+
id: tags
87+
shell: bash
88+
run: |
89+
REF="${{ github.ref_name }}" # dev / staging
90+
SHORT_SHA="${GITHUB_SHA::7}"
91+
SAFE_REF=$(echo "$REF" | tr '[:upper:]' '[:lower:]' | sed -E 's#[^a-z0-9._-]+#-#g')
92+
echo "channel=$SAFE_REF" >> $GITHUB_OUTPUT # ex) dev, staging
93+
echo "version=${SAFE_REF}-${SHORT_SHA}" >> $GITHUB_OUTPUT # ex) dev-abc1234
94+
95+
- name: Build & Push (branch-tagged)
8596
if: github.event_name == 'push'
8697
run: |
87-
GIT_SHA=${{ github.sha }}
88-
docker build -f "${{ steps.df.outputs.path }}" -t $IMAGE:release -t $IMAGE:$GIT_SHA "${{ steps.df.outputs.ctx }}"
89-
docker push $IMAGE:release
90-
docker push $IMAGE:$GIT_SHA
98+
CHAN=${{ steps.tags.outputs.channel }} # dev | staging
99+
VER=${{ steps.tags.outputs.version }} # dev-<sha> | staging-<sha>
100+
docker build -f "${{ steps.df.outputs.path }}" \
101+
-t $IMAGE:$CHAN \
102+
-t $IMAGE:$VER \
103+
"${{ steps.df.outputs.ctx }}"
104+
docker push $IMAGE:$CHAN
105+
docker push $IMAGE:$VER
91106
92107
deploy:
93108
needs: build-and-push
94-
if: github.event_name == 'push' && (github.ref == 'refs/heads/dev') &&
109+
if: github.event_name == 'push' && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/staging') &&
95110
(needs.build-and-push.result == 'success')
96111
|| (github.event_name == 'workflow_dispatch')
97112
runs-on: ubuntu-latest
@@ -103,7 +118,7 @@ jobs:
103118
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.tag }}" ]; then
104119
echo "value=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
105120
else
106-
echo "value=release" >> $GITHUB_OUTPUT
121+
echo "value=${{ github.ref_name }}" >> $GITHUB_OUTPUT
107122
fi
108123
109124
- name: Deploy
@@ -114,5 +129,10 @@ jobs:
114129
key: ${{ secrets.CD_SSH_KEY }}
115130
port: ${{ secrets.CD_PORT }}
116131
script: |
117-
export DEPLOY_TAG='${{ steps.tag.outputs.value }}'
118-
bash -lc '/srv/docsa/infra/deploy.sh'
132+
if [ "${{ github.ref_name }}" = "staging" ]; then
133+
export DEPLOY_TAG='${{ steps.tag.outputs.value }}'
134+
bash -lc '/srv/docsa/infra/deploy.sh staging'
135+
else
136+
export DEPLOY_TAG='${{ steps.tag.outputs.value }}'
137+
bash -lc '/srv/docsa/infra/deploy.sh dev'
138+
fi

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ out/
3939

4040
### Secrets & Runtime
4141
infra/.env
42+
infra/*.env
4243
infra/**/*.env
4344
infra/certbot
4445
infra/mysql/exporter.cnf

infra/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ SPRING_MAIL_PASSWORD=
55
SPRING_DATASOURCE_URL=
66
SPRING_DATASOURCE_USERNAME=
77
SPRING_DATASOURCE_PASSWORD=
8+
DDL_AUTO=
89

910
# ------------ SESSION/COOKIE ------------
1011
SESSION_COOKIE_NAME=

infra/deploy.sh

Lines changed: 66 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,88 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4-
cd /srv/docsa/infra
4+
# 사용법:
5+
# /srv/docsa/infra/deploy.sh dev
6+
# /srv/docsa/infra/deploy.sh staging
7+
# 환경변수(선택):
8+
# DEPLOY_TAG : 덮어쓸 이미지 태그(dev, dev-<sha>, staging, staging-<sha> 등)
9+
# IMAGE_BASE : GHCR 이미지 경로 (기본: ghcr.io/prgrms-web-devcourse-final-project/docsa-backend)
10+
# SERVICE : 배포할 서비스명 (기본 app)
11+
# HEALTH_TIMEOUT : 헬스 대기시간 초 (기본 120)
512

6-
# 특정 태그로 배포시 DEPLOY_TAG=...
7-
IMAGE_BASE="ghcr.io/prgrms-web-devcourse-final-project/docsa-backend"
8-
TAG="${DEPLOY_TAG:-}" # 비어있으면 compose에 적힌 태그 사용
13+
TARGET="${1:-}" # ← dev 또는 staging 인자 필수
14+
if [[ "$TARGET" != "dev" && "$TARGET" != "staging" ]]; then
15+
echo "Usage: $0 <dev|staging>"
16+
exit 2
17+
fi
18+
19+
IMAGE_BASE="${IMAGE_BASE:-ghcr.io/prgrms-web-devcourse-final-project/docsa-backend}"
20+
SERVICE="${SERVICE:-app}"
21+
HEALTH_TIMEOUT="${HEALTH_TIMEOUT:-120}"
22+
23+
cd "$(dirname "$0")"
24+
ROOT="$(pwd)"
25+
26+
# 타깃에 따라 compose/env 자동 선택
27+
if [[ "$TARGET" == "dev" ]]; then
28+
COMPOSE_FILE="$ROOT/docker-compose.yml"
29+
ENV_FILE="$ROOT/.env"
30+
else
31+
COMPOSE_FILE="$ROOT/docker-compose.stg.yml"
32+
ENV_FILE="$ROOT/.stg.env"
33+
fi
34+
35+
TAG="${DEPLOY_TAG:-$TARGET}" # ← 기본은 채널 태그(dev|staging), 입력 있으면 우선
36+
37+
# 임시 override 파일로 이미지 태그만 덮어쓰기
938
OVR=""
1039
if [[ -n "$TAG" ]]; then
11-
OVR="docker-compose.override.deploy.yml"
40+
OVR="$ROOT/docker-compose.override.deploy.yml"
1241
cat > "$OVR" <<EOF
1342
services:
14-
app:
43+
${SERVICE}:
1544
image: ${IMAGE_BASE}:${TAG}
1645
EOF
1746
fi
1847

19-
FILES=(-f docker-compose.yml)
20-
[[ -n "$OVR" ]] && FILES+=(-f "$OVR")
48+
# docker compose 인자 구성 (-p로 프로젝트 격리, --env-file로 env 명시)
49+
ARGS=(-f "$COMPOSE_FILE")
50+
[[ -n "$OVR" ]] && ARGS+=(-f "$OVR")
51+
ARGS+=(--env-file "$ENV_FILE")
52+
53+
echo "[deploy] target=$TARGET tag=$TAG"
54+
echo "[deploy] compose=$COMPOSE_FILE env=$ENV_FILE service=$SERVICE"
55+
56+
# 1) 유효성 검사(문법/치환 확인)
57+
docker compose "${ARGS[@]}" config >/dev/null
2158

22-
# 최신 이미지 받고 교체
23-
docker compose "${FILES[@]}" pull app
24-
docker compose "${FILES[@]}" up -d app
59+
# 2) 이미지 풀 + 대상 서비스만 업데이트
60+
docker compose "${ARGS[@]}" pull "$SERVICE" || true
61+
docker compose "${ARGS[@]}" up -d "$SERVICE"
2562

26-
# 헬스체크 대기 (최대 120s)
27-
echo -n "Waiting for app (docsa-app) to be healthy"
63+
# 3) 컨테이너 ID를 compose로 조회(이름 하드코딩 회피)
64+
CID="$(docker compose "${ARGS[@]}" ps -q "$SERVICE" | tail -n1 || true)"
65+
if [[ -z "$CID" ]]; then
66+
echo "No container found for service '$SERVICE' (project $PROJECT)"; exit 1
67+
fi
68+
69+
# 4) 헬스체크 대기
70+
echo -n "Waiting for $SERVICE to be healthy"
2871
ok=0
29-
for i in {1..60}; do
30-
status="$(docker inspect -f '{{.State.Health.Status}}' docsa-app 2>/dev/null || echo none)"
31-
if [[ "$status" == "healthy" ]]; then ok=1; echo -e "\nApp healthy"; break; fi
72+
ITER=$(( HEALTH_TIMEOUT / 2 ))
73+
for _ in $(seq 1 "$ITER"); do
74+
status="$(docker inspect -f '{{.State.Health.Status}}' "$CID" 2>/dev/null || echo none)"
75+
if [[ "$status" == "healthy" ]]; then ok=1; echo -e "\n$SERVICE healthy"; break; fi
3276
sleep 2; echo -n "."
3377
done
3478

35-
# 임시 override 제거 & 청소
36-
[[ -n "$OVR" ]] && rm -f "$OVR"
79+
# 5) 임시 override 청소 + 이미지 정리
80+
[[ -n "$OVR" ]] && rm -f "$OVR" || true
3781
docker image prune -f >/dev/null 2>&1 || true
3882

39-
# 실패 처리
83+
# 6) 실패 시 로그 출력 후 종료
4084
if [[ $ok -eq 0 ]]; then
41-
echo -e "\nApp failed to become healthy (status=$status)"
42-
docker logs --tail=200 docsa-app || true
85+
echo -e "\n$SERVICE failed to become healthy (status=${status:-unknown})"
86+
docker logs --tail=200 "$CID" || true
4387
exit 1
44-
fi
88+
fi

0 commit comments

Comments
 (0)