Continuous Deployment - 100-hours-a-week/3-team-ssammu-wiki GitHub Wiki

๐ŸŽจ CD ํŒŒ์ดํ”„๋ผ์ธ ํ๋ฆ„๋„

CareerBee_CD_แ„‘แ…กแ„‹แ…ตแ„‘แ…ณแ„…แ…กแ„‹แ…ตแ†ซ(MVP) drawio

์ „์ฒด ๋™์ž‘ ์š”์•ฝ

GitHub Push
    โ†“
GitHub Actions (CI)
    โ†“
๋ฐฑ์—”๋“œ JAR / ํ”„๋ก ํŠธ ์ •์  ํŒŒ์ผ / AI ์†Œ์Šค GCS ์—…๋กœ๋“œ
    โ†“
Self-Hosted Runner
    โ†“
deploy.sh ์‹คํ–‰
    โ†“
๋ฐฑ์—”๋“œ JAR ๊ต์ฒด ๋ฐ ์‹คํ–‰
ํ”„๋ก ํŠธ ์ •์  ํŒŒ์ผ ๋ณต์‚ฌ
AI ์„œ๋ฒ„ ์žฌ์‹œ์ž‘

๐Ÿ“„ CD ์„ค๊ณ„ ์„ค๋ช…์„œ

โ“ ์™œ CD(์ง€์†์  ๋ฐฐํฌ)๊ฐ€ ํ•„์š”ํ•œ๊ฐ€?

ํ•ญ๋ชฉ ์ˆ˜๋™ ๋ฐฐํฌ CD(์ง€์†์  ๋ฐฐํฌ)
ํšจ์œจ์„ฑ ๋ฐฐํฌํ•  ๋•Œ๋งˆ๋‹ค ์ˆ˜๋™ ๋ช…๋ น์–ด ์ž…๋ ฅ ํ•„์š”
โ†’ ๋ฐ˜๋ณต์ ์ด๊ณ  ์†Œ๋ชจ์ 
ํ‘ธ์‹œ ํ›„ ์ž๋™์œผ๋กœ ๋ฐฐํฌ๋˜์–ด ๋ฐ˜๋ณต ์ž‘์—… ์ œ๊ฑฐ
์†๋„ ๋ฐฐํฌ ์†๋„ ๋‹ด๋‹น์ž ์—ญ๋Ÿ‰์— ์˜์กด
โ†’ ๋ณ‘๋ชฉ ๋ฐœ์ƒ ๊ฐ€๋Šฅ
์ผ๊ด€๋œ ์†๋„๋กœ ์ž๋™ ๋ฐฐํฌ ๊ฐ€๋Šฅ โ†’ ๋ฆด๋ฆฌ์ฆˆ ์ฃผ๊ธฐ ๋‹จ์ถ•
์‹ ๋ขฐ์„ฑ ์ž‘์—…์ž ์‹ค์ˆ˜(ํŒŒ์ผ ๋ˆ„๋ฝ, ์ˆœ์„œ ์˜ค๋ฅ˜ ๋“ฑ) ๋ฐœ์ƒ ๊ฐ€๋Šฅ ์Šคํฌ๋ฆฝํŠธ ๊ธฐ๋ฐ˜ ์ž๋™ ์ฒ˜๋ฆฌ๋กœ ์‹ ๋ขฐ๋„ ์ƒ์Šน
ํ™•์žฅ์„ฑ ์„œ๋ฒ„/ํ™˜๊ฒฝ ์ˆ˜ ์ฆ๊ฐ€ ์‹œ ์ˆ˜์ž‘์—… ๊ด€๋ฆฌ ํ•œ๊ณ„ ๋ฐœ์ƒ ํ™˜๊ฒฝ ์ˆ˜์— ๊ด€๊ณ„์—†์ด ์ผ๊ด€๋œ ๋ฐฐํฌ ๊ฐ€๋Šฅ
๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐฐํฌ ์‹คํŒจ ์—ฌ๋ถ€ ํ™•์ธ ์–ด๋ ค์›€ ์‹คํŒจ ์‹œ ๋กค๋ฐฑ, ์•Œ๋ฆผ, ์ƒํƒœ ์ฒดํฌ ๊ฐ€๋Šฅ

๐Ÿ’ก ๊ธฐ๋Œ€ ํšจ๊ณผ

  • ์ˆ˜์ž‘์—… ๋Œ€๋น„ ๋ฐฐํฌ ์‹œ๊ฐ„ ๋Œ€ํญ ๊ฐ์†Œ (15๋ถ„ โ†’ 3~5๋ถ„)
  • GCS ํ™œ์šฉ์œผ๋กœ ๋นŒ๋“œ ์‚ฐ์ถœ๋ฌผ ๋ฒ„์ „ ๊ด€๋ฆฌ ๋ฐ ์™ธ๋ถ€ ๋…ธ์ถœ ์ตœ์†Œํ™”
  • ๋‹ค์šดํƒ€์ž„ ์ตœ์†Œํ™” (๊ฐ ํ”„๋กœ์„ธ์Šค ๊ต์ฒด ์‹œ 1~2๋ถ„ ์ด๋‚ด)
  • ๋กค๋ฐฑ ์ž๋™ํ™” ๊ธฐ๋ฐ˜ ํ™•๋ณด
  • CI-CD ๊ตฌ์กฐ ๋ถ„๋ฆฌ๋กœ ์—ญํ•  ๋ช…ํ™•ํ™” ๋ฐ ๋ณด์•ˆ/์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด์„ฑ ์ƒ์Šน

CD ์Šคํฌ๋ฆฝํŠธ

GitHub Actions

name: CD on Self-Hosted Runner

on: workflow_dispatch: # ๋˜๋Š” push, deploy tag ๋“ฑ

jobs: deploy: runs-on: self-hosted steps: - name: Run deploy.sh from local repo run: | chmod +x ./scripts/deploy.sh ./scripts/deploy.sh

GCS ๊ธฐ๋ฐ˜ ์ž๋™ ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ (Self-Hosted Runner์šฉ)

!/bin/bash

# ๐Ÿ“ ๊ฒฝ๋กœ ์„ค์ •
GCS_BUCKET_NAME=careerbee-deploy-artifacts
RELEASE_DIR=~/release
BACKEND_DIR=$RELEASE_DIR/backend
FRONTEND_DIR=$RELEASE_DIR/frontend
AI_DIR=$RELEASE_DIR/ai

LOG_DIR=~/logs
mkdir -p $BACKEND_DIR $FRONTEND_DIR $AI_DIR $LOG_DIR

echo GCS์—์„œ ์ตœ์‹  ๋นŒ๋“œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ

echo ๋ฐฑ์—”๋“œ JAR ๋‹ค์šด๋กœ๋“œ...
gsutil cp gs://$GCS_BUCKET_NAME/backend/app-latest.jar $BACKEND_DIR/app.jar

echo ํ”„๋ก ํŠธ์—”๋“œ ์ •์  ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ...
gsutil -m cp -r gs://$GCS_BUCKET_NAME/frontend/* $FRONTEND_DIR/

echo AI ์„œ๋ฒ„ ์••์ถ• ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ๋ฐ ํ•ด์ œ...
gsutil cp gs://$GCS_BUCKET_NAME/ai/ai-latest.zip $AI_DIR/
unzip -o $AI_DIR/ai-latest.zip -d $AI_DIR/

echo ๋ฐฑ์—”๋“œ ํ”„๋กœ์„ธ์Šค ๊ต์ฒด
pkill -f 'app.jar' || echo ๊ธฐ์กด ๋ฐฑ์—”๋“œ ํ”„๋กœ์„ธ์Šค ์—†์Œ
nohup java -jar $BACKEND_DIR/app.jar $LOG_DIR/backend.log

echo ํ”„๋ก ํŠธ์—”๋“œ ์ •์  ํŒŒ์ผ ๋ฎ์–ด์“ฐ๊ธฐ
sudo cp -r $FRONTEND_DIR/* /var/www/html/

echo AI ์„œ๋ฒ„ ์žฌ์‹œ์ž‘
cd $AI_DIR
source venv/bin/activate || python3 -m venv venv source venv/bin/activate
pip install -r requirements.txt
pkill -f 'uvicorn' || echo ๊ธฐ์กด AI ํ”„๋กœ์„ธ์Šค ์—†์Œ
nohup uvicorn main:app --host 0.0.0.0 --port 8000 $LOG_DIR/ai.log

echo โœ… ๋ฐฐํฌ ์™„๋ฃŒ

โš ๏ธ ๋กค๋ฐฑ ์ „๋žต ๋ฐ ์Šคํฌ๋ฆฝํŠธ

โœ… ์™œ ๋กค๋ฐฑ ํŒŒ์ดํ”„๋ผ์ธ์ด ํ•„์š”ํ•œ๊ฐ€?

  • GitHub Actions ์ƒ์—์„œ ๋นŒ๋“œ์™€ ๋ฐฐํฌ๋Š” ์„ฑ๊ณตํ–ˆ๋”๋ผ๋„, ์‹ค์ œ ๋ฐฐํฌ๋œ ์„œ๋น„์Šค์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ
    • ex) ๋กœ๊ทธ์ธ ์‹คํŒจ, AI ์‘๋‹ต ์˜ค๋ฅ˜, ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋ˆ„๋ฝ ๋“ฑ
  • GCS์— Git ์ปค๋ฐ‹ ํ•ด์‹œ ๊ธฐ์ค€์œผ๋กœ ๋ฒ„์ „๋œ ์‚ฐ์ถœ๋ฌผ์„ ์—…๋กœ๋“œํ•จ์œผ๋กœ์จ, ๐Ÿ‘‰ ์„œ๋น„์Šค ์žฅ์•  ๋ฐœ์ƒ ์‹œ ํŠน์ • ๋ฒ„์ „์œผ๋กœ ๋น ๋ฅด๊ฒŒ ๋ณต์› ๊ฐ€๋Šฅ

์ฆ‰, GitHub Actions์—๋Š” ์„ฑ๊ณต์ด๋ผ ํ‘œ๊ธฐ๋˜์ง€๋งŒ ์‚ฌ์šฉ์ž๋Š” ์žฅ์• ๋ฅผ ๊ฒช๋Š” ๊ฒฝ์šฐ์—๋„ ๋น ๋ฅด๊ฒŒ ๋Œ€์‘ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•˜๋Š” ์‚ฌํ›„ ๋ณต๊ตฌ ์ „๋žต

GCS ๋ฒ„์ „ ๊ด€๋ฆฌ ์ „๋žต

ํ•ญ๋ชฉ ์ €์žฅ ๊ฒฝ๋กœ ์˜ˆ์‹œ ์„ค๋ช…
Backend gs://careerbee-deploy-artifacts/backend/app-.jar ์ปค๋ฐ‹ ๊ธฐ์ค€์œผ๋กœ JAR ๋ฒ„์ „ ๋ณด๊ด€
Frontend gs://careerbee-deploy-artifacts/frontend// ์ •์  ๋ฆฌ์†Œ์Šค ์ „์ฒด ๋””๋ ‰ํ† ๋ฆฌ ๋ณด๊ด€
AI Server gs://careerbee-deploy-artifacts/ai/ai-.zip ์••์ถ•๋œ ์†Œ์Šค ์ฝ”๋“œ ๋ฐ venv ํฌํ•จ

๋กค๋ฐฑ ํŒŒ์ดํ”„๋ผ์ธ ํ๋ฆ„๋„

CareerBee_RollBack drawio (1)

  • ์„œ๋น„์Šค ๋ฐฐํฌ ์ดํ›„ ์žฅ์•  ๋ฐœ์ƒ ์‹œ, ๊ฐœ๋ฐœ์ž๋Š” GCS์— ์ €์žฅ๋œ ์ด์ „ ์ปค๋ฐ‹ ๊ธฐ๋ฐ˜์˜ ๋นŒ๋“œ ์‚ฐ์ถœ๋ฌผ์„ ๊ธฐ์ค€์œผ๋กœ ๋น ๋ฅด๊ฒŒ ๋กค๋ฐฑ์„ ์ง„ํ–‰ํ•œ๋‹ค
  1. Cloud Storage์—์„œ๋Š” ๊ฐ€์žฅ ์ตœ๊ทผ ์„ฑ๊ณตํ•œ ์ปค๋ฐ‹ ํ•ด์‹œ ๊ธฐ์ค€์œผ๋กœ ๋ฒ„์ „์„ ํ™•์ธ

  2. Compute Engine์— SSH ์ ‘์†ํ•˜์—ฌ ./rollback.sh <์ปค๋ฐ‹ํ•ด์‹œ>๋ฅผ ์‹คํ–‰

Self-Hosted Runner ํ™˜๊ฒฝ ๋‚ด ์ž๋™ํ™”๋œ GitHub Actions ๊ธฐ๋ฐ˜ ๋ฐฐํฌ ์‹œ์Šคํ…œ๊ณผ ์—ฐ๊ณ„๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋กค๋ฐฑ ์ดํ›„์—๋„ ๋™์ผํ•œ ๋ฐฐํฌ ํ”Œ๋กœ์šฐ๋ฅผ ๋”ฐ๋ผ ์ž๋™ํ™”๋œ ์žฌ๋ฐฐํฌ๊ฐ€ ๊ฐ€๋Šฅ

rollback.sh

# ๐Ÿ” ๋กค๋ฐฑ ๋Œ€์ƒ ์ปค๋ฐ‹ ํ•ด์‹œ ์ˆ˜๋™ ์ง€์ •
COMMIT_HASH=$1

if [ -z "$COMMIT_HASH" ]; then
  echo "๋กค๋ฐฑํ•  ์ปค๋ฐ‹ ํ•ด์‹œ๋ฅผ ์ธ์ž๋กœ ์ž…๋ ฅํ•˜์„ธ์š”"
  echo "์˜ˆ: ./rollback.sh 1a2b3c4d"
  exit 1
fi

GCS_BUCKET_NAME=careerbee-deploy-artifacts
RELEASE_DIR=~/release
BACKEND_DIR=$RELEASE_DIR/backend
FRONTEND_DIR=$RELEASE_DIR/frontend
AI_DIR=$RELEASE_DIR/ai
LOG_DIR=~/logs

mkdir -p $BACKEND_DIR $FRONTEND_DIR $AI_DIR $LOG_DIR

echo "๐Ÿ”„ GCS์—์„œ ์ปค๋ฐ‹ $COMMIT_HASH ๊ธฐ์ค€์œผ๋กœ ๋นŒ๋“œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ"

echo "๐Ÿ” ๋ฐฑ์—”๋“œ JAR ๋‹ค์šด๋กœ๋“œ..."
gsutil cp gs://$GCS_BUCKET_NAME/backend/app-${COMMIT_HASH}.jar $BACKEND_DIR/app.jar

echo "๐Ÿ” ํ”„๋ก ํŠธ์—”๋“œ ์ •์  ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ..."
gsutil -m cp -r gs://$GCS_BUCKET_NAME/frontend/${COMMIT_HASH}/* $FRONTEND_DIR/

echo "๐Ÿ” AI ์„œ๋ฒ„ ์••์ถ• ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ๋ฐ ํ•ด์ œ..."
gsutil cp gs://$GCS_BUCKET_NAME/ai/ai-${COMMIT_HASH}.zip $AI_DIR/
unzip -o $AI_DIR/ai-${COMMIT_HASH}.zip -d $AI_DIR/

echo "๐Ÿ” ๋ฐฑ์—”๋“œ ์žฌ์‹œ์ž‘"
pkill -f 'app.jar' || echo "๊ธฐ์กด ๋ฐฑ์—”๋“œ ์—†์Œ"
nohup java -jar $BACKEND_DIR/app.jar > $LOG_DIR/backend_rollback.log 2>&1 &

echo "๐Ÿ” ํ”„๋ก ํŠธ์—”๋“œ ์žฌ๋ฐฐํฌ"
sudo cp -r $FRONTEND_DIR/* /var/www/html/

echo "๐Ÿ” AI ์„œ๋ฒ„ ์žฌ์‹œ์ž‘"
cd $AI_DIR
source venv/bin/activate || python3 -m venv venv &amp;&amp; source venv/bin/activate
pip install -r requirements.txt
pkill -f 'uvicorn' || echo "๊ธฐ์กด AI ์—†์Œ"
nohup uvicorn main:app --host 0.0.0.0 --port 8000 > $LOG_DIR/ai_rollback.log 2>&1 &

echo "โœ… ๋กค๋ฐฑ ์™„๋ฃŒ - ์ปค๋ฐ‹ $COMMIT_HASH"

๐Ÿ“Œ ๋กค๋ฐฑ ์‹œ๋‚˜๋ฆฌ์˜ค ์š”์•ฝ

์ƒํ™ฉ ๋Œ€์‘ ์ „๋žต
๋ฐฐํฌ ์ดํ›„ ๋กœ๊ทธ์ธ ์˜ค๋ฅ˜ ๋“ฑ ๊ธฐ๋Šฅ ์žฅ์•  ๋ฐœ์ƒ ./rollback.sh <๋ฌธ์ œ ์—†๋Š” ์ปค๋ฐ‹ ํ•ด์‹œ> ์‹คํ–‰
๋ฐฐํฌ ์งํ›„ ์‚ฌ์ดํŠธ ์ ‘์† ์•ˆ๋จ GCS์—์„œ ์ด์ „ ๋ฒ„์ „ ๋‹ค์šด๋กœ๋“œ โ†’ ์„œ๋น„์Šค ๊ต์ฒด
FastAPI ์˜ค๋ฅ˜ AI ์„œ๋ฒ„๋งŒ ๋กค๋ฐฑ ๊ฐ€๋Šฅ (๋‹ค๋ฅธ ์„œ๋น„์Šค๋Š” ์œ ์ง€)

๐Ÿ“Œ ๋ณธ ํŽ˜์ด์ง€๋Š” 2025๋…„ 4์›” 22์ผ์— ๋งˆ์ง€๋ง‰์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ