Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
283 changes: 180 additions & 103 deletions .github/workflows/deploy-to-dev-ec2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,114 @@ jobs:
target: ~/nadab/
overwrite: true

- name: 🔐 Prepare deployment secrets
env:
INSIGHT_PROMPT_B64: ${{ secrets.INSIGHT_PROMPT_B64 }}
INSIGHT_WITH_IMAGE_PROMPT_B64: ${{ secrets.INSIGHT_WITH_IMAGE_PROMPT_B64 }}
WEEKLY_PROMPT_B64: ${{ secrets.WEEKLY_PROMPT_B64 }}
MONTHLY_V1_PROMPT_B64: ${{ secrets.MONTHLY_V1_PROMPT_B64 }}
MONTHLY_V2_BASELINE_PROMPT_B64: ${{ secrets.MONTHLY_V2_BASELINE_PROMPT_B64 }}
MONTHLY_V2_COMPARISON_PROMPT_B64: ${{ secrets.MONTHLY_V2_COMPARISON_PROMPT_B64 }}
EVIDENCE_CARD_PROMPT_B64: ${{ secrets.EVIDENCE_CARD_PROMPT_B64 }}
PATTERN_EXTRACT_PROMPT_B64: ${{ secrets.PATTERN_EXTRACT_PROMPT_B64 }}
TYPE_SELECT_PROMPT_B64: ${{ secrets.TYPE_SELECT_PROMPT_B64 }}
TYPE_PROMPT_B64: ${{ secrets.TYPE_PROMPT_B64 }}
REPAIR_TYPE_PROMPT_B64: ${{ secrets.REPAIR_TYPE_PROMPT_B64 }}
ASK_CHAT_ANSWER_SYSTEM_PROMPT_B64: ${{ secrets.ASK_CHAT_ANSWER_SYSTEM_PROMPT_B64 }}
ASK_CHAT_ANSWER_USER_PROMPT_B64: ${{ secrets.ASK_CHAT_ANSWER_USER_PROMPT_B64 }}
NOTIFICATION_MESSAGES_B64: ${{ secrets.NOTIFICATION_MESSAGES_B64 }}
DB_URL: ${{ secrets.DB_URL }}
DB_USERNAME: ${{ secrets.DB_USERNAME }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
FRONTEND_DEV_URL: ${{ secrets.FRONTEND_DEV_URL }}
FRONTEND_DEV_URL_2: ${{ secrets.FRONTEND_DEV_URL_2 }}
FRONTEND_DEV_URL_3: ${{ secrets.FRONTEND_DEV_URL_3 }}
SWAGGER_SERVER_URL: ${{ secrets.SWAGGER_SERVER_URL }}
SWAGGER_ORIGIN_PUBLIC_IP: ${{ secrets.SWAGGER_ORIGIN_PUBLIC_IP }}
SWAGGER_ORIGIN_DOMAIN: ${{ secrets.SWAGGER_ORIGIN_DOMAIN }}
NAVER_CLIENT_ID: ${{ secrets.NAVER_CLIENT_ID }}
NAVER_CLIENT_SECRET: ${{ secrets.NAVER_CLIENT_SECRET }}
NAVER_REDIRECT_URI: ${{ secrets.NAVER_REDIRECT_URI }}
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_ANDROID_CLIENT_ID: ${{ secrets.GOOGLE_ANDROID_CLIENT_ID }}
GOOGLE_IOS_CLIENT_ID: ${{ secrets.GOOGLE_IOS_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
GOOGLE_REDIRECT_URI: ${{ secrets.GOOGLE_REDIRECT_URI }}
KAKAO_CLIENT_ID: ${{ secrets.KAKAO_CLIENT_ID }}
KAKAO_CLIENT_SECRET: ${{ secrets.KAKAO_CLIENT_SECRET }}
KAKAO_REDIRECT_URI: ${{ secrets.KAKAO_REDIRECT_URI }}
KAKAO_APP_ID: ${{ secrets.KAKAO_APP_ID }}
APPLE_CLIENT_ID: ${{ secrets.APPLE_CLIENT_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_PRIVATE_KEY: ${{ secrets.APPLE_PRIVATE_KEY }}
IAM_ACCESS_KEY: ${{ secrets.IAM_ACCESS_KEY }}
IAM_SECRET_KEY: ${{ secrets.IAM_SECRET_KEY }}
BUCKET_NAME: ${{ secrets.BUCKET_NAME }}
PROFILE_IMAGE_BASE_URL: ${{ secrets.PROFILE_IMAGE_BASE_URL }}
CLOUDFRONT_KEY_PAIR_ID: ${{ secrets.CLOUDFRONT_KEY_PAIR_ID }}
CLOUDFRONT_PRIVATE_KEY: ${{ secrets.CLOUDFRONT_PRIVATE_KEY }}
KMS_KEY_ID: ${{ secrets.KMS_KEY_ID }}
MAIL_ADDRESS: ${{ secrets.MAIL_ADDRESS }}
MAIL_PASSWORD: ${{ secrets.MAIL_PASSWORD }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GOOGLE_GENAI_API_KEY: ${{ secrets.GOOGLE_GENAI_API_KEY }}
FIREBASE_ADMIN_KEY: ${{ secrets.FIREBASE_ADMIN_KEY }}
ADMIN_PAGE_PASSWORD: ${{ secrets.ADMIN_PAGE_PASSWORD }}
DEV_TEST_ACCOUNT_PASSWORD: ${{ secrets.DEV_TEST_ACCOUNT_PASSWORD }}
run: |
set -euo pipefail
umask 077
mkdir -p deploy-secrets

SECRET_NAMES=(
INSIGHT_PROMPT_B64 INSIGHT_WITH_IMAGE_PROMPT_B64 WEEKLY_PROMPT_B64
MONTHLY_V1_PROMPT_B64 MONTHLY_V2_BASELINE_PROMPT_B64 MONTHLY_V2_COMPARISON_PROMPT_B64
EVIDENCE_CARD_PROMPT_B64 PATTERN_EXTRACT_PROMPT_B64 TYPE_SELECT_PROMPT_B64
TYPE_PROMPT_B64 REPAIR_TYPE_PROMPT_B64 ASK_CHAT_ANSWER_SYSTEM_PROMPT_B64
ASK_CHAT_ANSWER_USER_PROMPT_B64 NOTIFICATION_MESSAGES_B64
DB_URL DB_USERNAME DB_PASSWORD JWT_SECRET
FRONTEND_DEV_URL FRONTEND_DEV_URL_2 FRONTEND_DEV_URL_3
SWAGGER_SERVER_URL SWAGGER_ORIGIN_PUBLIC_IP SWAGGER_ORIGIN_DOMAIN
NAVER_CLIENT_ID NAVER_CLIENT_SECRET NAVER_REDIRECT_URI
GOOGLE_CLIENT_ID GOOGLE_ANDROID_CLIENT_ID GOOGLE_IOS_CLIENT_ID
GOOGLE_CLIENT_SECRET GOOGLE_REDIRECT_URI
KAKAO_CLIENT_ID KAKAO_CLIENT_SECRET KAKAO_REDIRECT_URI KAKAO_APP_ID
APPLE_CLIENT_ID APPLE_TEAM_ID APPLE_KEY_ID APPLE_PRIVATE_KEY
IAM_ACCESS_KEY IAM_SECRET_KEY BUCKET_NAME PROFILE_IMAGE_BASE_URL
CLOUDFRONT_KEY_PAIR_ID CLOUDFRONT_PRIVATE_KEY KMS_KEY_ID
MAIL_ADDRESS MAIL_PASSWORD OPENAI_API_KEY ANTHROPIC_API_KEY
GOOGLE_GENAI_API_KEY FIREBASE_ADMIN_KEY ADMIN_PAGE_PASSWORD DEV_TEST_ACCOUNT_PASSWORD
)

for name in "${SECRET_NAMES[@]}"; do
printf '%s' "${!name}" | base64 -w 0 > "deploy-secrets/$name"
done

# scp-action Docker 컨테이너가 다른 UID로 파일을 읽을 수 있도록 전송 직전에만 권한 허용
chmod 755 deploy-secrets
chmod 644 deploy-secrets/*

- name: 📤 Upload deployment secrets to EC2
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.EC2_HOST }}
username: ec2-user
key: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
source: ./deploy-secrets
target: ~/nadab/
overwrite: true

- name: 🚀 Restart App on EC2
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.EC2_HOST }}
username: ec2-user
key: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
script: |
set -euxo pipefail
set -euo pipefail

cd ~/nadab
echo "🔎 현재 서버 디렉토리: $(pwd)"
Expand All @@ -59,112 +159,89 @@ jobs:
JAR_NAME=$(basename "$JAR_PATH")

echo "📌 배포할 JAR 선택됨: $JAR_PATH"

# 실행중인 프로세스 종료

SECRETS_DIR="deploy-secrets"
[ -d "$SECRETS_DIR" ] || { echo "❌ 배포 Secret 디렉토리가 존재하지 않습니다"; exit 1; }
chmod 700 "$SECRETS_DIR"
chmod 600 "$SECRETS_DIR"/*

cleanup_secrets() {
rm -f -- "$SECRETS_DIR"/*
rmdir -- "$SECRETS_DIR"
}
trap cleanup_secrets EXIT

load_secret() {
local name="$1"
local path="$SECRETS_DIR/$name"
[ -f "$path" ] || { echo "❌ 필수 Secret 파일 누락: $name"; exit 1; }

local value
value="$(base64 -d "$path")"
printf -v "$name" '%s' "$value"
export "$name"
}

load_prompt() {
local name="$1"
local path="$SECRETS_DIR/${name}_B64"
[ -f "$path" ] || { echo "❌ 필수 프롬프트 파일 누락: ${name}_B64"; exit 1; }

local value
value="$(base64 -d "$path" | base64 -d | tr -d '\r')"
printf -v "$name" '%s' "$value"
export "$name"
}

PROMPT_NAMES=(
INSIGHT_PROMPT INSIGHT_WITH_IMAGE_PROMPT WEEKLY_PROMPT
MONTHLY_V1_PROMPT MONTHLY_V2_BASELINE_PROMPT MONTHLY_V2_COMPARISON_PROMPT
EVIDENCE_CARD_PROMPT PATTERN_EXTRACT_PROMPT TYPE_SELECT_PROMPT TYPE_PROMPT
REPAIR_TYPE_PROMPT ASK_CHAT_ANSWER_SYSTEM_PROMPT ASK_CHAT_ANSWER_USER_PROMPT
NOTIFICATION_MESSAGES
)

SECRET_NAMES=(
DB_URL DB_USERNAME DB_PASSWORD JWT_SECRET
FRONTEND_DEV_URL FRONTEND_DEV_URL_2 FRONTEND_DEV_URL_3
SWAGGER_SERVER_URL SWAGGER_ORIGIN_PUBLIC_IP SWAGGER_ORIGIN_DOMAIN
NAVER_CLIENT_ID NAVER_CLIENT_SECRET NAVER_REDIRECT_URI
GOOGLE_CLIENT_ID GOOGLE_ANDROID_CLIENT_ID GOOGLE_IOS_CLIENT_ID
GOOGLE_CLIENT_SECRET GOOGLE_REDIRECT_URI
KAKAO_CLIENT_ID KAKAO_CLIENT_SECRET KAKAO_REDIRECT_URI KAKAO_APP_ID
APPLE_CLIENT_ID APPLE_TEAM_ID APPLE_KEY_ID APPLE_PRIVATE_KEY
IAM_ACCESS_KEY IAM_SECRET_KEY BUCKET_NAME PROFILE_IMAGE_BASE_URL
CLOUDFRONT_KEY_PAIR_ID CLOUDFRONT_PRIVATE_KEY KMS_KEY_ID
MAIL_ADDRESS MAIL_PASSWORD OPENAI_API_KEY ANTHROPIC_API_KEY
GOOGLE_GENAI_API_KEY FIREBASE_ADMIN_KEY ADMIN_PAGE_PASSWORD DEV_TEST_ACCOUNT_PASSWORD
)

for name in "${PROMPT_NAMES[@]}"; do
load_prompt "$name"
done

for name in "${SECRET_NAMES[@]}"; do
load_secret "$name"
done

cleanup_secrets
trap - EXIT

# Secret 복원이 완료된 후에만 기존 프로세스 종료
echo "🛑 기존 애플리케이션 종료 중..."
pkill -f "$JAR_NAME" || true

echo "🚀 새 버전 실행..."

# ✅ base64로 인코딩된 프롬프트를 환경 변수에 디코딩해서 넣기
INSIGHT_PROMPT_B64="${{ secrets.INSIGHT_PROMPT_B64 }}"
INSIGHT_PROMPT="$(printf '%s' "$INSIGHT_PROMPT_B64" | base64 -d | tr -d '\r')"
export INSIGHT_PROMPT

INSIGHT_WITH_IMAGE_PROMPT_B64="${{ secrets.INSIGHT_WITH_IMAGE_PROMPT_B64 }}"
INSIGHT_WITH_IMAGE_PROMPT="$(printf '%s' "$INSIGHT_WITH_IMAGE_PROMPT_B64" | base64 -d | tr -d '\r')"
export INSIGHT_WITH_IMAGE_PROMPT

WEEKLY_PROMPT_B64="${{ secrets.WEEKLY_PROMPT_B64 }}"
WEEKLY_PROMPT="$(printf '%s' "$WEEKLY_PROMPT_B64" | base64 -d | tr -d '\r')"
export WEEKLY_PROMPT

MONTHLY_V1_PROMPT_B64="${{ secrets.MONTHLY_V1_PROMPT_B64 }}"
MONTHLY_V1_PROMPT="$(printf '%s' "$MONTHLY_V1_PROMPT_B64" | base64 -d | tr -d '\r')"
export MONTHLY_V1_PROMPT

MONTHLY_V2_BASELINE_PROMPT_B64="${{ secrets.MONTHLY_V2_BASELINE_PROMPT_B64 }}"
MONTHLY_V2_BASELINE_PROMPT="$(printf '%s' "$MONTHLY_V2_BASELINE_PROMPT_B64" | base64 -d | tr -d '\r')"
export MONTHLY_V2_BASELINE_PROMPT

MONTHLY_V2_COMPARISON_PROMPT_B64="${{ secrets.MONTHLY_V2_COMPARISON_PROMPT_B64 }}"
MONTHLY_V2_COMPARISON_PROMPT="$(printf '%s' "$MONTHLY_V2_COMPARISON_PROMPT_B64" | base64 -d | tr -d '\r')"
export MONTHLY_V2_COMPARISON_PROMPT

EVIDENCE_CARD_PROMPT_B64="${{ secrets.EVIDENCE_CARD_PROMPT_B64 }}"
EVIDENCE_CARD_PROMPT="$(printf '%s' "$EVIDENCE_CARD_PROMPT_B64" | base64 -d | tr -d '\r')"
export EVIDENCE_CARD_PROMPT

PATTERN_EXTRACT_PROMPT_B64="${{ secrets.PATTERN_EXTRACT_PROMPT_B64 }}"
PATTERN_EXTRACT_PROMPT="$(printf '%s' "$PATTERN_EXTRACT_PROMPT_B64" | base64 -d | tr -d '\r')"
export PATTERN_EXTRACT_PROMPT

TYPE_SELECT_PROMPT_B64="${{ secrets.TYPE_SELECT_PROMPT_B64 }}"
TYPE_SELECT_PROMPT="$(printf '%s' "$TYPE_SELECT_PROMPT_B64" | base64 -d | tr -d '\r')"
export TYPE_SELECT_PROMPT

TYPE_PROMPT_B64="${{ secrets.TYPE_PROMPT_B64 }}"
TYPE_PROMPT="$(printf '%s' "$TYPE_PROMPT_B64" | base64 -d | tr -d '\r')"
export TYPE_PROMPT

REPAIR_TYPE_PROMPT_B64="${{ secrets.REPAIR_TYPE_PROMPT_B64 }}"
REPAIR_TYPE_PROMPT="$(printf '%s' "$REPAIR_TYPE_PROMPT_B64" | base64 -d | tr -d '\r')"
export REPAIR_TYPE_PROMPT

ASK_CHAT_ANSWER_SYSTEM_PROMPT_B64="${{ secrets.ASK_CHAT_ANSWER_SYSTEM_PROMPT_B64 }}"
ASK_CHAT_ANSWER_SYSTEM_PROMPT="$(printf '%s' "$ASK_CHAT_ANSWER_SYSTEM_PROMPT_B64" | base64 -d | tr -d '\r')"
export ASK_CHAT_ANSWER_SYSTEM_PROMPT

ASK_CHAT_ANSWER_USER_PROMPT_B64="${{ secrets.ASK_CHAT_ANSWER_USER_PROMPT_B64 }}"
ASK_CHAT_ANSWER_USER_PROMPT="$(printf '%s' "$ASK_CHAT_ANSWER_USER_PROMPT_B64" | base64 -d | tr -d '\r')"
export ASK_CHAT_ANSWER_USER_PROMPT

NOTIFICATION_MESSAGES_B64="${{ secrets.NOTIFICATION_MESSAGES_B64 }}"
NOTIFICATION_MESSAGES="$(printf '%s' "$NOTIFICATION_MESSAGES_B64" | base64 -d | tr -d '\r')"
export NOTIFICATION_MESSAGES

DB_URL="${{ secrets.DB_URL }}" \
DB_USERNAME="${{ secrets.DB_USERNAME }}" \
DB_PASSWORD="${{ secrets.DB_PASSWORD }}" \
JWT_SECRET="${{ secrets.JWT_SECRET }}" \
FRONTEND_DEV_URL="${{ secrets.FRONTEND_DEV_URL }}" \
FRONTEND_DEV_URL_2="${{ secrets.FRONTEND_DEV_URL_2 }}" \
FRONTEND_DEV_URL_3="${{ secrets.FRONTEND_DEV_URL_3 }}" \
SWAGGER_SERVER_URL="${{ secrets.SWAGGER_SERVER_URL }}" \
SWAGGER_ORIGIN_PUBLIC_IP="${{ secrets.SWAGGER_ORIGIN_PUBLIC_IP }}" \
SWAGGER_ORIGIN_DOMAIN="${{ secrets.SWAGGER_ORIGIN_DOMAIN }}" \
NAVER_CLIENT_ID="${{ secrets.NAVER_CLIENT_ID }}" \
NAVER_CLIENT_SECRET="${{ secrets.NAVER_CLIENT_SECRET }}" \
NAVER_REDIRECT_URI="${{ secrets.NAVER_REDIRECT_URI }}" \
GOOGLE_CLIENT_ID="${{ secrets.GOOGLE_CLIENT_ID }}" \
GOOGLE_ANDROID_CLIENT_ID="${{ secrets.GOOGLE_ANDROID_CLIENT_ID }}" \
GOOGLE_IOS_CLIENT_ID="${{ secrets.GOOGLE_IOS_CLIENT_ID }}" \
GOOGLE_CLIENT_SECRET="${{ secrets.GOOGLE_CLIENT_SECRET }}" \
GOOGLE_REDIRECT_URI="${{ secrets.GOOGLE_REDIRECT_URI }}" \
KAKAO_CLIENT_ID="${{ secrets.KAKAO_CLIENT_ID }}" \
KAKAO_CLIENT_SECRET="${{ secrets.KAKAO_CLIENT_SECRET }}" \
KAKAO_REDIRECT_URI="${{ secrets.KAKAO_REDIRECT_URI }}" \
KAKAO_APP_ID="${{ secrets.KAKAO_APP_ID }}" \
APPLE_CLIENT_ID="${{ secrets.APPLE_CLIENT_ID }}" \
APPLE_TEAM_ID="${{ secrets.APPLE_TEAM_ID }}" \
APPLE_KEY_ID="${{ secrets.APPLE_KEY_ID }}" \
APPLE_PRIVATE_KEY="${{ secrets.APPLE_PRIVATE_KEY }}" \
IAM_ACCESS_KEY="${{ secrets.IAM_ACCESS_KEY }}" \
IAM_SECRET_KEY="${{ secrets.IAM_SECRET_KEY }}" \
BUCKET_NAME="${{ secrets.BUCKET_NAME }}" \
PROFILE_IMAGE_BASE_URL="${{ secrets.PROFILE_IMAGE_BASE_URL }}" \
CLOUDFRONT_KEY_PAIR_ID="${{ secrets.CLOUDFRONT_KEY_PAIR_ID }}" \
CLOUDFRONT_PRIVATE_KEY="${{ secrets.CLOUDFRONT_PRIVATE_KEY }}" \
KMS_KEY_ID="${{ secrets.KMS_KEY_ID }}" \
MAIL_ADDRESS="${{ secrets.MAIL_ADDRESS }}" \
MAIL_PASSWORD="${{ secrets.MAIL_PASSWORD }}" \
OPENAI_API_KEY="${{ secrets.OPENAI_API_KEY }}" \
ANTHROPIC_API_KEY="${{ secrets.ANTHROPIC_API_KEY }}" \
GOOGLE_GENAI_API_KEY="${{ secrets.GOOGLE_GENAI_API_KEY }}" \
FIREBASE_ADMIN_KEY="${{ secrets.FIREBASE_ADMIN_KEY }}" \
ADMIN_PAGE_PASSWORD='${{ secrets.ADMIN_PAGE_PASSWORD }}' \
DEV_TEST_ACCOUNT_PASSWORD="${{ secrets.DEV_TEST_ACCOUNT_PASSWORD }}" \
echo "🚀 새 버전 실행..."
nohup java -jar "$JAR_PATH" \
--spring.profiles.active=dev > app.log 2>&1 &

echo "✅ 배포 완료!"

- name: 🧹 Cleanup deployment secrets
if: always()
run: |
set -euo pipefail
if [ -d deploy-secrets ]; then
rm -f -- deploy-secrets/*
rmdir -- deploy-secrets
fi
Loading