Skip to content

Fix notification recipient for friend addition: notify the friend bei… #178

Fix notification recipient for friend addition: notify the friend bei…

Fix notification recipient for friend addition: notify the friend bei… #178

Workflow file for this run

name: Deploy to Server
on:
push:
branches:
- main # 프로덕션 배포
- release # 프로덕션 배포
- develop # 개발 환경 배포
workflow_dispatch: # 수동 실행 (환경 선택 가능)
inputs:
environment:
description: '배포 환경 선택'
required: true
default: 'prod'
type: choice
options:
- dev
- prod
jobs:
deploy:
name: Deploy to ${{ (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main') && 'Production' || github.event.inputs.environment == 'prod' && 'Production' || 'Development' }} Server
runs-on: ubuntu-latest
env:
DEPLOY_ENV: ${{ (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main') && 'prod' || github.ref == 'refs/heads/develop' && 'dev' || github.event.inputs.environment == 'prod' && 'prod' || github.event.inputs.environment == 'dev' && 'dev' || 'dev' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add server to known hosts
run: |
ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Create Firebase service account key file
run: |
mkdir -p src/main/resources
cat > src/main/resources/firebase-service-account.json << 'EOF'
${{ secrets.FCM_SERVICE_ACCOUNT_KEY_JSON }}
EOF
- name: Copy files to server
run: |
DEPLOY_ENV_VALUE="${{ (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main') && 'prod' || github.ref == 'refs/heads/develop' && 'dev' || github.event.inputs.environment == 'prod' && 'prod' || github.event.inputs.environment == 'dev' && 'dev' || 'dev' }}"
# 환경별 디렉토리 설정 (각 환경이 완전히 독립적으로 동작)
if [ "$DEPLOY_ENV_VALUE" = "prod" ]; then
REMOTE_DIR="~/taba_backend_prod"
echo "=== Copying files to production directory: $REMOTE_DIR ==="
else
REMOTE_DIR="~/taba_backend_dev"
echo "=== Copying files to development directory: $REMOTE_DIR ==="
fi
# 원격 디렉토리 생성
ssh -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "mkdir -p $REMOTE_DIR"
# 환경별로 필요한 파일만 복사 (다른 환경 파일은 복사하지 않음)
if [ "$DEPLOY_ENV_VALUE" = "prod" ]; then
echo "=== Copying production files only ==="
scp -o StrictHostKeyChecking=no docker-compose.prod.yml Dockerfile ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:$REMOTE_DIR/
else
echo "=== Copying development files only ==="
scp -o StrictHostKeyChecking=no docker-compose.dev.yml Dockerfile ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:$REMOTE_DIR/
fi
# 공통 파일 복사 (각 환경의 독립 디렉토리에)
scp -o StrictHostKeyChecking=no build.gradle settings.gradle gradle.properties ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:$REMOTE_DIR/
scp -r -o StrictHostKeyChecking=no gradle ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:$REMOTE_DIR/
scp -r -o StrictHostKeyChecking=no src ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:$REMOTE_DIR/
- name: Deploy Application
run: |
DEPLOY_ENV_VALUE="${{ (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main') && 'prod' || github.ref == 'refs/heads/develop' && 'dev' || github.event.inputs.environment == 'prod' && 'prod' || github.event.inputs.environment == 'dev' && 'dev' || 'dev' }}"
ssh -o StrictHostKeyChecking=no "${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}" DEPLOY_ENV="$DEPLOY_ENV_VALUE" bash << 'REMOTE_SCRIPT'
# 환경별 디렉토리 설정 (각 환경이 완전히 독립적으로 동작)
if [ "$DEPLOY_ENV" = "prod" ]; then
DEPLOY_DIR="$HOME/taba_backend_prod"
else
DEPLOY_DIR="$HOME/taba_backend_dev"
fi
cd "$DEPLOY_DIR"
echo "=== Working directory: $DEPLOY_DIR ==="
echo "=== Current directory: $(pwd) ==="
# 공통 이메일 설정 (프로덕션/개발 동일)
export MAIL_HOST="${{ secrets.MAIL_HOST }}"
export MAIL_PORT="${{ secrets.MAIL_PORT }}"
export MAIL_USERNAME="${{ secrets.MAIL_USERNAME }}"
export MAIL_PASSWORD="${{ secrets.MAIL_PASSWORD }}"
# 이메일 기본값 설정 (Gmail)
[ -z "$MAIL_HOST" ] && export MAIL_HOST=smtp.gmail.com
[ -z "$MAIL_PORT" ] && export MAIL_PORT=587
# 환경별 설정 (각 환경은 독립적으로 동작)
if [ "$DEPLOY_ENV" = "prod" ]; then
echo "=== Production environment configuration ==="
export DB_NAME="${{ secrets.DB_NAME_PROD }}"
export DB_USERNAME="${{ secrets.DB_USERNAME_PROD }}"
export DB_PASSWORD="${{ secrets.DB_PASSWORD_PROD }}"
export REDIS_PASSWORD="${{ secrets.REDIS_PASSWORD_PROD }}"
export JWT_SECRET="${{ secrets.JWT_SECRET_PROD }}"
export SERVER_URL="${{ secrets.SERVER_URL_PROD }}"
export EXTERNAL_PORT="${{ secrets.EXTERNAL_PORT_PROD }}"
export DB_EXTERNAL_PORT="${{ secrets.DB_EXTERNAL_PORT_PROD }}"
export REDIS_EXTERNAL_PORT="${{ secrets.REDIS_EXTERNAL_PORT_PROD }}"
export FRONTEND_URL="${{ secrets.FRONTEND_URL_PROD }}"
# 포트 기본값 설정 (프로덕션: Backend(8080), MySQL(3306), Redis(6379))
[ -z "$EXTERNAL_PORT" ] && export EXTERNAL_PORT=8080
[ -z "$DB_EXTERNAL_PORT" ] && export DB_EXTERNAL_PORT=3306
[ -z "$REDIS_EXTERNAL_PORT" ] && export REDIS_EXTERNAL_PORT=6379
export SPRING_PROFILES_ACTIVE=prod
COMPOSE_FILE="docker-compose.prod.yml"
BACKEND_CONTAINER="taba-backend-prod"
MYSQL_CONTAINER="taba-mysql-prod"
REDIS_CONTAINER="taba-redis-prod"
echo "✅ Using production compose file: $COMPOSE_FILE"
echo "✅ Production containers: $BACKEND_CONTAINER, $MYSQL_CONTAINER, $REDIS_CONTAINER"
else
echo "=== Development environment configuration ==="
export DB_NAME="${{ secrets.DB_NAME_DEV }}"
export DB_USERNAME="${{ secrets.DB_USERNAME_DEV }}"
export DB_PASSWORD="${{ secrets.DB_PASSWORD_DEV }}"
export REDIS_PASSWORD="${{ secrets.REDIS_PASSWORD_DEV }}"
export JWT_SECRET="${{ secrets.JWT_SECRET_DEV }}"
export SERVER_URL="${{ secrets.SERVER_URL_DEV }}"
export EXTERNAL_PORT="${{ secrets.EXTERNAL_PORT_DEV }}"
export DB_EXTERNAL_PORT="${{ secrets.DB_EXTERNAL_PORT_DEV }}"
export REDIS_EXTERNAL_PORT="${{ secrets.REDIS_EXTERNAL_PORT_DEV }}"
export FRONTEND_URL="${{ secrets.FRONTEND_URL_DEV }}"
# 포트 기본값 설정 (개발: Backend(8081), MySQL(3307), Redis(6380) - 동시 실행 가능)
[ -z "$EXTERNAL_PORT" ] && export EXTERNAL_PORT=8081
[ -z "$DB_EXTERNAL_PORT" ] && export DB_EXTERNAL_PORT=3307
[ -z "$REDIS_EXTERNAL_PORT" ] && export REDIS_EXTERNAL_PORT=6380
export SPRING_PROFILES_ACTIVE=dev
COMPOSE_FILE="docker-compose.dev.yml"
BACKEND_CONTAINER="taba-backend-dev"
MYSQL_CONTAINER="taba-mysql-dev"
REDIS_CONTAINER="taba-redis-dev"
echo "✅ Using development compose file: $COMPOSE_FILE"
echo "✅ Development containers: $BACKEND_CONTAINER, $MYSQL_CONTAINER, $REDIS_CONTAINER"
fi
# 다른 환경의 컨테이너는 건드리지 않음을 확인
echo "=== Ensuring other environment containers are not affected ==="
if [ "$DEPLOY_ENV" = "prod" ]; then
DEV_BACKEND=$(docker ps --format '{{.Names}}' | grep "^taba-backend-dev$" || echo "")
DEV_MYSQL=$(docker ps --format '{{.Names}}' | grep "^taba-mysql-dev$" || echo "")
DEV_REDIS=$(docker ps --format '{{.Names}}' | grep "^taba-redis-dev$" || echo "")
if [ -n "$DEV_BACKEND" ] || [ -n "$DEV_MYSQL" ] || [ -n "$DEV_REDIS" ]; then
echo "✅ Development environment containers are running (will not be affected):"
[ -n "$DEV_BACKEND" ] && echo " - $DEV_BACKEND"
[ -n "$DEV_MYSQL" ] && echo " - $DEV_MYSQL"
[ -n "$DEV_REDIS" ] && echo " - $DEV_REDIS"
fi
else
PROD_BACKEND=$(docker ps --format '{{.Names}}' | grep "^taba-backend-prod$" || echo "")
PROD_MYSQL=$(docker ps --format '{{.Names}}' | grep "^taba-mysql-prod$" || echo "")
PROD_REDIS=$(docker ps --format '{{.Names}}' | grep "^taba-redis-prod$" || echo "")
if [ -n "$PROD_BACKEND" ] || [ -n "$PROD_MYSQL" ] || [ -n "$PROD_REDIS" ]; then
echo "✅ Production environment containers are running (will not be affected):"
[ -n "$PROD_BACKEND" ] && echo " - $PROD_BACKEND"
[ -n "$PROD_MYSQL" ] && echo " - $PROD_MYSQL"
[ -n "$PROD_REDIS" ] && echo " - $PROD_REDIS"
fi
fi
# 필수 환경 변수 확인
if [ -z "$DB_NAME" ] || [ -z "$DB_USERNAME" ] || [ -z "$DB_PASSWORD" ] || [ -z "$JWT_SECRET" ] || [ -z "$SERVER_URL" ]; then
echo "❌ 필수 환경 변수가 설정되지 않았습니다."
echo "DB_NAME: ${DB_NAME:+설정됨}${DB_NAME:-미설정}"
echo "DB_USERNAME: ${DB_USERNAME:+설정됨}${DB_USERNAME:-미설정}"
echo "DB_PASSWORD: ${DB_PASSWORD:+설정됨}${DB_PASSWORD:-미설정}"
echo "JWT_SECRET: ${JWT_SECRET:+설정됨}${JWT_SECRET:-미설정}"
echo "SERVER_URL: ${SERVER_URL:+설정됨}${SERVER_URL:-미설정}"
exit 1
fi
export DB_HOST=mysql DB_PORT=3306 REDIS_HOST=redis REDIS_PORT=6379 SERVER_PORT=8080 FILE_UPLOAD_DIR=/app/uploads
export JWT_EXPIRATION=${JWT_EXPIRATION:-604800000}
[ -z "$REDIS_PASSWORD" ] && export REDIS_PASSWORD=
COMPOSE_CMD="docker-compose -f $COMPOSE_FILE"
# MySQL 사용자 생성 함수
ensure_mysql_user() {
local mysql_container="$MYSQL_CONTAINER"
local db_name="$DB_NAME"
local db_username="$DB_USERNAME"
local db_password="$DB_PASSWORD"
local root_pass=$(docker exec "$mysql_container" printenv MYSQL_ROOT_PASSWORD 2>/dev/null || echo "$db_password")
local root_test=$(docker exec "$mysql_container" mysql -u root -p"$root_pass" -e "SELECT 1" 2>&1) || true
if echo "$root_test" | grep -qiE "(ERROR|Access denied|denied)"; then
root_pass="$db_password"
root_test=$(docker exec "$mysql_container" mysql -u root -p"$root_pass" -e "SELECT 1" 2>&1) || true
fi
if ! echo "$root_test" | grep -qiE "(ERROR|Access denied|denied)"; then
docker exec "$mysql_container" mysql -u root -p"$root_pass" -e "CREATE DATABASE IF NOT EXISTS \`$db_name\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 2>&1 | grep -v "Warning" >/dev/null || true
docker exec "$mysql_container" mysql -u root -p"$root_pass" -e "DROP USER IF EXISTS '$db_username'@'%';" 2>&1 | grep -v "Warning" >/dev/null || true
docker exec "$mysql_container" mysql -u root -p"$root_pass" -e "CREATE USER '$db_username'@'%' IDENTIFIED BY '$db_password';" 2>&1 | grep -v "Warning" >/dev/null || true
docker exec "$mysql_container" mysql -u root -p"$root_pass" -e "GRANT ALL PRIVILEGES ON \`$db_name\`.* TO '$db_username'@'%'; FLUSH PRIVILEGES;" 2>&1 | grep -v "Warning" >/dev/null || true
fi
}
# 공유 네트워크 생성 (prod/dev 모두 사용, 이미 존재하면 무시)
docker network create taba-network 2>/dev/null || true
# 현재 환경의 백엔드 컨테이너만 중지 및 제거 (다른 환경은 건드리지 않음)
echo "=== Stopping current environment backend container ==="
docker stop "$BACKEND_CONTAINER" 2>/dev/null || true
docker rm -f "$BACKEND_CONTAINER" 2>/dev/null || true
# 손상된 이미지 제거 (ContainerConfig 에러 방지)
echo "=== Removing old backend image to prevent ContainerConfig errors ==="
# docker-compose가 사용하는 이미지 이름 찾기 (프로젝트명-서비스명 형식)
COMPOSE_PROJECT_NAME=$(basename "$(pwd)" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]//g')
OLD_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "${COMPOSE_PROJECT_NAME}.*backend|.*backend.*${COMPOSE_PROJECT_NAME}" | head -1 || echo "")
if [ -z "$OLD_IMAGE" ]; then
# 대체 방법: <none> 태그가 있는 이미지 찾기
OLD_IMAGE=$(docker images --format "{{.ID}}" --filter "dangling=true" | head -1 || echo "")
if [ -n "$OLD_IMAGE" ]; then
echo "Removing dangling image: $OLD_IMAGE"
docker rmi -f "$OLD_IMAGE" 2>/dev/null || true
fi
else
echo "Removing old backend image: $OLD_IMAGE"
docker rmi -f "$OLD_IMAGE" 2>/dev/null || true
fi
# 손상된 컨테이너 이미지 참조 정리
docker container prune -f 2>/dev/null || true
# 백엔드 이미지 빌드
echo "=== Building backend image ==="
$COMPOSE_CMD build --no-cache --progress=plain backend || exit 1
# 현재 환경의 MySQL/Redis 컨테이너만 완전히 제거 (다른 환경은 건드리지 않음)
echo "=== Stopping and removing current environment MySQL/Redis containers ==="
# 여러 번 시도하여 완전히 제거
for attempt in {1..3}; do
docker stop "$MYSQL_CONTAINER" "$REDIS_CONTAINER" 2>/dev/null || true
docker rm -f "$MYSQL_CONTAINER" "$REDIS_CONTAINER" 2>/dev/null || true
sleep 1
# 컨테이너가 완전히 제거되었는지 확인
if ! docker ps -a --format '{{.Names}}' | grep -q "^${MYSQL_CONTAINER}$" && \
! docker ps -a --format '{{.Names}}' | grep -q "^${REDIS_CONTAINER}$"; then
echo "✅ Containers removed successfully"
break
fi
if [ $attempt -eq 3 ]; then
echo "⚠️ Some containers may still exist, but continuing..."
fi
done
# MySQL, Redis 시작 (다른 환경의 컨테이너는 그대로 유지)
echo "=== Starting MySQL and Redis for current environment ==="
# --force-recreate 옵션으로 ContainerConfig 에러 방지
$COMPOSE_CMD up -d --force-recreate mysql redis
# 컨테이너가 실제로 시작될 때까지 대기 (재시작 포함)
echo "=== Waiting for containers to start ==="
for i in {1..60}; do
MYSQL_RUNNING=$(docker ps --format '{{.Names}}' | grep -q "^${MYSQL_CONTAINER}$" && echo "yes" || echo "no")
REDIS_RUNNING=$(docker ps --format '{{.Names}}' | grep -q "^${REDIS_CONTAINER}$" && echo "yes" || echo "no")
if [ "$MYSQL_RUNNING" = "yes" ] && [ "$REDIS_RUNNING" = "yes" ]; then
echo "✅ Containers are running"
break
fi
# 종료된 컨테이너가 있으면 재시작 시도
if [ "$MYSQL_RUNNING" = "no" ]; then
MYSQL_STATUS=$(docker ps -a --format '{{.Names}} {{.Status}}' | grep "^${MYSQL_CONTAINER} " || echo "")
if [ -n "$MYSQL_STATUS" ]; then
echo "⚠️ MySQL container not running: $MYSQL_STATUS, attempting restart..."
docker start "$MYSQL_CONTAINER" 2>/dev/null || $COMPOSE_CMD up -d --no-deps mysql
fi
fi
if [ "$REDIS_RUNNING" = "no" ]; then
REDIS_STATUS=$(docker ps -a --format '{{.Names}} {{.Status}}' | grep "^${REDIS_CONTAINER} " || echo "")
if [ -n "$REDIS_STATUS" ]; then
echo "⚠️ Redis container not running: $REDIS_STATUS, attempting restart..."
docker logs --tail=20 "$REDIS_CONTAINER" 2>&1 || true
docker start "$REDIS_CONTAINER" 2>/dev/null || $COMPOSE_CMD up -d --no-deps redis
fi
fi
if [ $i -eq 60 ]; then
echo "❌ Containers failed to start after 60 seconds"
echo "=== Container status ==="
docker ps -a | grep -E "${MYSQL_CONTAINER}|${REDIS_CONTAINER}" || true
echo "=== MySQL logs ==="
docker logs --tail=30 "$MYSQL_CONTAINER" 2>&1 || true
echo "=== Redis logs ==="
docker logs --tail=30 "$REDIS_CONTAINER" 2>&1 || true
exit 1
fi
sleep 2
done
# MySQL health check 대기
echo "=== Waiting for MySQL to be healthy ==="
for i in {1..60}; do
HEALTH_STATUS=$(docker inspect --format='{{.State.Health.Status}}' "$MYSQL_CONTAINER" 2>/dev/null || echo "unknown")
echo "MySQL health check attempt $i/60: $HEALTH_STATUS"
if [ "$HEALTH_STATUS" = "healthy" ]; then
echo "✅ MySQL is healthy"
break
fi
if [ $i -eq 60 ]; then
echo "❌ MySQL failed to become healthy after 60 attempts"
docker logs --tail=50 "$MYSQL_CONTAINER" 2>&1 || true
exit 1
fi
sleep 2
done
ensure_mysql_user
# 사용자 연결 테스트
for retry in {1..3}; do
USER_TEST=$(docker exec "$MYSQL_CONTAINER" mysql -u "$DB_USERNAME" -p"$DB_PASSWORD" -e "USE \`$DB_NAME\`; SELECT 1;" 2>&1) || true
if ! echo "$USER_TEST" | grep -qiE "(ERROR|Access denied|denied)"; then
echo "✅ MySQL connection successful"
break
fi
if [ $retry -lt 3 ]; then
ensure_mysql_user
sleep 3
else
echo "❌ MySQL connection failed"
docker logs --tail=30 "$MYSQL_CONTAINER" 2>&1
exit 1
fi
done
# 백엔드 시작 (MySQL/Redis는 이미 실행 중이므로 --no-deps 사용)
echo "=== Starting backend ==="
# MySQL/Redis가 실행 중인지 확인
if ! docker ps --format '{{.Names}}' | grep -q "^${MYSQL_CONTAINER}$" || \
! docker ps --format '{{.Names}}' | grep -q "^${REDIS_CONTAINER}$"; then
echo "❌ MySQL or Redis container is not running"
docker ps --format '{{.Names}}' | grep -E "${MYSQL_CONTAINER}|${REDIS_CONTAINER}" || true
exit 1
fi
echo "✅ MySQL and Redis are running, starting backend..."
# ContainerConfig 에러 방지를 위해 기존 백엔드 컨테이너 완전히 제거
echo "=== Removing existing backend container to prevent ContainerConfig errors ==="
docker stop "$BACKEND_CONTAINER" 2>/dev/null || true
docker rm -f "$BACKEND_CONTAINER" 2>/dev/null || true
# docker-compose를 사용하여 컨테이너 제거 (메타데이터 정리)
$COMPOSE_CMD rm -f backend 2>/dev/null || true
sleep 2
# 백엔드 컨테이너 시작
$COMPOSE_CMD up -d --no-deps --force-recreate --remove-orphans backend || exit 1
sleep 5
echo "=== Backend logs ==="
docker logs --tail=30 "$BACKEND_CONTAINER" 2>&1
REMOTE_SCRIPT
env:
DEPLOY_ENV: ${{ (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main') && 'prod' || github.ref == 'refs/heads/develop' && 'dev' || github.event.inputs.environment == 'prod' && 'prod' || github.event.inputs.environment == 'dev' && 'dev' || 'dev' }}
- name: Check container status
run: |
DEPLOY_ENV_VALUE="${{ (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main') && 'prod' || github.ref == 'refs/heads/develop' && 'dev' || github.event.inputs.environment == 'prod' && 'prod' || github.event.inputs.environment == 'dev' && 'dev' || 'dev' }}"
ssh -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} DEPLOY_ENV="$DEPLOY_ENV_VALUE" bash << 'REMOTE_SCRIPT'
# 환경별 디렉토리 설정
if [ "$DEPLOY_ENV" = "prod" ]; then
DEPLOY_DIR="$HOME/taba_backend_prod"
else
DEPLOY_DIR="$HOME/taba_backend_dev"
fi
cd "$DEPLOY_DIR"
BACKEND_CONTAINER=$([ "$DEPLOY_ENV" = "prod" ] && echo "taba-backend-prod" || echo "taba-backend-dev")
echo "=== Container Status ==="
docker ps -a --filter "name=taba" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" || true
echo ""
echo "=== Backend Logs ==="
docker logs --tail=50 "$BACKEND_CONTAINER" 2>&1 || echo "No logs"
REMOTE_SCRIPT
env:
DEPLOY_ENV: ${{ (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main') && 'prod' || github.ref == 'refs/heads/develop' && 'dev' || github.event.inputs.environment == 'prod' && 'prod' || github.event.inputs.environment == 'dev' && 'dev' || 'dev' }}
- name: Health Check (Internal)
continue-on-error: true
run: |
ssh -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} bash << 'REMOTE_SCRIPT'
BACKEND_CONTAINER=$([ "$DEPLOY_ENV" = "prod" ] && echo "taba-backend-prod" || echo "taba-backend-dev")
sleep 60
for i in {1..10}; do
docker ps | grep -q "$BACKEND_CONTAINER" && docker exec "$BACKEND_CONTAINER" curl -f http://localhost:8080/api/v1/actuator/health 2>&1 && exit 0
sleep 10
done
docker logs --tail=50 "$BACKEND_CONTAINER" 2>&1
exit 1
REMOTE_SCRIPT
env:
DEPLOY_ENV: ${{ (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main') && 'prod' || github.ref == 'refs/heads/develop' && 'dev' || github.event.inputs.environment == 'prod' && 'prod' || github.event.inputs.environment == 'dev' && 'dev' || 'dev' }}
- name: Health Check (External) - Optional
continue-on-error: true
run: |
DEPLOY_ENV="${{ (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main') && 'prod' || github.ref == 'refs/heads/develop' && 'dev' || github.event.inputs.environment == 'prod' && 'prod' || github.event.inputs.environment == 'dev' && 'dev' || 'dev' }}"
if [ "$DEPLOY_ENV" = "prod" ]; then
SERVER_URL='${{ secrets.SERVER_URL_PROD }}'
else
SERVER_URL='${{ secrets.SERVER_URL_DEV }}'
fi
echo "Checking external health endpoint..."
echo "DEPLOY_ENV: $DEPLOY_ENV"
echo "SERVER_URL: ${SERVER_URL:0:20}..." # 처음 20자만 표시
# SERVER_URL이 비어있거나 잘못된 형식인지 확인
if [ -z "$SERVER_URL" ] || [ "$SERVER_URL" = "null" ] || [[ "$SERVER_URL" == *"***"* ]]; then
echo "SERVER_URL not properly set, skipping external health check"
exit 0
fi
# SERVER_URL에서 도메인 추출 (https://api.example.com/api/v1 -> https://api.example.com)
SERVER_DOMAIN=$(echo "$SERVER_URL" | sed 's|https\?://||' | sed 's|/.*||')
if [ -n "$SERVER_DOMAIN" ] && [ "$SERVER_DOMAIN" != "null" ]; then
curl -f https://${SERVER_DOMAIN}/api/v1/actuator/health || echo "External health check failed"
else
echo "SERVER_URL not set, skipping external health check"
fi
- name: Deployment Summary
run: |
DEPLOY_ENV="${{ (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main') && 'prod' || github.ref == 'refs/heads/develop' && 'dev' || github.event.inputs.environment == 'prod' && 'prod' || github.event.inputs.environment == 'dev' && 'dev' || 'dev' }}"
if [ "$DEPLOY_ENV" = "prod" ]; then
SERVER_URL='${{ secrets.SERVER_URL_PROD }}'
ENV_NAME="프로덕션"
else
SERVER_URL='${{ secrets.SERVER_URL_DEV }}'
ENV_NAME="개발"
fi
SERVER_DOMAIN=$(echo "$SERVER_URL" | sed 's|https\?://||' | sed 's|/.*||' 2>/dev/null || echo "")
echo "## 🚀 $ENV_NAME 배포 완료!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **환경**: $ENV_NAME" >> $GITHUB_STEP_SUMMARY
if [ -n "$SERVER_DOMAIN" ] && [ "$SERVER_DOMAIN" != "null" ] && [[ ! "$SERVER_DOMAIN" == *"***"* ]]; then
echo "- **서버**: $SERVER_DOMAIN" >> $GITHUB_STEP_SUMMARY
echo "- **API URL**: $SERVER_URL" >> $GITHUB_STEP_SUMMARY
echo "- **Health Check**: $SERVER_URL/actuator/health" >> $GITHUB_STEP_SUMMARY
echo "- **Swagger UI**: $SERVER_URL/swagger-ui/index.html" >> $GITHUB_STEP_SUMMARY
else
DEPLOY_ENV_UPPER=$(echo "$DEPLOY_ENV" | tr '[:lower:]' '[:upper:]')
echo "- **서버**: GitHub Secrets에서 SERVER_URL_${DEPLOY_ENV_UPPER} 설정 필요" >> $GITHUB_STEP_SUMMARY
echo "- **API URL**: 설정되지 않음" >> $GITHUB_STEP_SUMMARY
fi