Skip to content

FIX: deploy and client app route #193

FIX: deploy and client app route

FIX: deploy and client app route #193

Workflow file for this run

name: Deploy ToGather Microservices to AWS EKS
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:
env:
AWS_REGION: ap-northeast-2
ECR_REGISTRY: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com
EKS_CLUSTER_NAME: togather-cluster
EKS_NAMESPACE: togather
CDN_URL: https://d36ue99r8i68ow.cloudfront.net
S3_BUCKET_NAME: togather-static-assets
CLOUDFRONT_DISTRIBUTION_ID: E15ZDIW40YBVEN
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# --- ๊ณตํ†ต ์ค€๋น„ ๋‹จ๊ณ„ ---!!!
- name: Checkout Server Repository
uses: actions/checkout@v4
- name: Set gradlew permissions
run: chmod +x gradlew
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Checkout Client Repository
uses: actions/checkout@v4
with:
repository: ToGather-Final/ToGather-Client
token: ${{ secrets.GH_PAT }}
path: togather-client
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
- name: Cache pnpm dependencies
uses: actions/cache@v3
with:
path: |
~/.pnpm-store
togather-client/node_modules
key: ${{ runner.os }}-pnpm-${{ hashFiles('togather-client/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Setup JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
# --- Next.js ํด๋ผ์ด์–ธํŠธ ๋จผ์ € ๋นŒ๋“œ (๋น ๋ฅธ ํ”ผ๋“œ๋ฐฑ) ---
- name: Build Next.js Client (Priority)
run: |
cd togather-client
export CDN_URL_CLEAN=$(echo "${{ env.CDN_URL }}" | sed 's:/*$::')
echo "๐Ÿ›ฐ Using CDN_URL=$CDN_URL_CLEAN"
pnpm install --frozen-lockfile
# โœ… Next.js ๋‹จ์ผ ๋นŒ๋“œ (Node runtime)
SERVER_API_BASE_URL=http://api-gateway.togather.svc.cluster.local:8000/api \
NEXT_PUBLIC_API_BASE_URL=https://xn--o79aq2k062a.store/api \
NEXT_PUBLIC_WS_URL=wss://xn--o79aq2k062a.store/ws \
CDN_URL=$CDN_URL_CLEAN pnpm run build
# โœ… ๋นŒ๋“œ ๊ฒฐ๊ณผ ๊ฒ€์ฆ (server.js ๋˜๋Š” next-server.js ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ์„ฑ๊ณต)
if [ ! -f ".next/standalone/server.js" ] && [ ! -f ".next/standalone/server.mjs" ] && [ ! -f ".next/standalone/next-server.js" ]; then
echo "โŒ Next.js standalone server entry not found!"
echo "๐Ÿ” Available files in .next/standalone:"
ls -la .next/standalone/ || echo "No standalone directory found"
echo "๐Ÿ” Available files in .next:"
ls -la .next/ || echo "No .next directory found"
exit 1
else
echo "โœ… Next.js standalone build successful"
if [ -f ".next/standalone/server.js" ]; then
echo "โœ… Found server.js"
fi
if [ -f ".next/standalone/next-server.js" ]; then
echo "โœ… Found next-server.js"
fi
fi
# โœ… .next/server ์ œ์™ธํ•˜๊ณ  ์•„ํ‹ฐํŒฉํŠธ ์ƒ์„ฑ
cd ..
tar -czf next-artifacts.tgz -C togather-client .next/standalone .next/static public src/app src/components src/contexts src/hooks src/lib src/utils src/constants src/types src/services src/containers
echo "โœ… next-artifacts.tgz ์ƒ์„ฑ ์™„๋ฃŒ"
# --- Next.js ๋นŒ๋“œ ์•„ํ‹ฐํŒฉํŠธ ์—…๋กœ๋“œ (1ํšŒ๋งŒ) ---
- name: Upload Next build artifacts (Priority)
uses: actions/upload-artifact@v4
with:
name: next-artifacts
path: next-artifacts.tgz
# --- Docker ๋นŒ๋“œ ---
- name: Download and Extract Next.js Build Artifacts (Priority)
uses: actions/download-artifact@v4
with:
name: next-artifacts
path: ./togather-client
- name: Extract Next.js Artifacts (Priority)
run: |
tar -xzf ./togather-client/next-artifacts.tgz -C ./togather-client
echo "โœ… next-artifacts.tgz ์••์ถ• ํ•ด์ œ ์™„๋ฃŒ"
- name: Build and Push Next.js Runtime Image (Priority)
continue-on-error: true
run: |
echo "๐Ÿš€ Building Next.js runtime image..."
cd togather-client
if docker build \
--build-arg SERVER_API_BASE_URL=http://api-gateway.togather.svc.cluster.local:8000/api \
--build-arg NEXT_PUBLIC_API_BASE_URL=https://xn--o79aq2k062a.store/api \
--build-arg NEXT_PUBLIC_WS_URL=wss://xn--o79aq2k062a.store/ws \
--build-arg CDN_URL=${{ env.CDN_URL }} \
-t $ECR_REGISTRY/togather/client:${{ github.sha }} \
-t $ECR_REGISTRY/togather/client:latest \
-f Dockerfile .; then
echo "โœ… Next.js build successful"
if docker push $ECR_REGISTRY/togather/client:${{ github.sha }} && docker push $ECR_REGISTRY/togather/client:latest; then
echo "โœ… Next.js Docker image successfully built and pushed!"
else
echo "โŒ Next.js push failed"
exit 1
fi
else
echo "โŒ Next.js build failed"
exit 1
fi
# --- S3 ์ •์  ์ž์‚ฐ ์—…๋กœ๋“œ (๋™์ผํ•œ ๋นŒ๋“œ ๊ฒฐ๊ณผ ์‚ฌ์šฉ) ---
- name: Upload Static Assets to S3 (Priority)
run: |
echo "๐Ÿš€ Uploading static assets to S3..."
cd togather-client
# โœ… ๋™์ผํ•œ ๋นŒ๋“œ ๊ฒฐ๊ณผ๋ฅผ S3์— ์—…๋กœ๋“œ
pnpm run upload-assets
echo "โœ… Static assets uploaded to S3 successfully!"
env:
CDN_URL: ${{ env.CDN_URL }}
S3_BUCKET_NAME: ${{ env.S3_BUCKET_NAME }}
CLOUDFRONT_DISTRIBUTION_ID: ${{ env.CLOUDFRONT_DISTRIBUTION_ID }}
# --- S3 ๋ฒ„ํ‚ท ์ •์ฑ… ์„ค์ • ---
- name: Configure S3 Bucket Policy for CloudFront
run: |
echo "๐Ÿ”ง Configuring S3 bucket policy for CloudFront access..."
aws s3api put-bucket-policy \
--bucket ${{ env.S3_BUCKET_NAME }} \
--policy file://scripts/s3-bucket-policy.json
echo "โœ… S3 bucket policy configured successfully!"
# --- kubectl ์„ค์น˜ (Next.js ๋ฐฐํฌ๋ฅผ ์œ„ํ•ด) ---
- name: Install kubectl (Priority)
uses: azure/setup-kubectl@v3
with:
version: 'v1.28.0'
# --- Next.js ํด๋ผ์ด์–ธํŠธ EKS ๋ฐฐํฌ (๋น ๋ฅธ ํ”ผ๋“œ๋ฐฑ) ---
- name: Deploy Next.js Client to EKS (Priority)
if: github.ref == 'refs/heads/main'
run: |
echo "๐Ÿš€ Deploying Next.js Client first for quick feedback..."
# kubectl ์„ค์ •
aws eks update-kubeconfig --region ${{ env.AWS_REGION }} --name ${{ env.EKS_CLUSTER_NAME }}
export ECR_REGISTRY=${{ env.ECR_REGISTRY }}
# ๊ธฐ์กด Next.js ํด๋ผ์ด์–ธํŠธ Pod ์ •๋ฆฌ (๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” Pod๋“ค ์ œ๊ฑฐ)
echo "๐Ÿงน Cleaning up existing Next.js Client pods..."
kubectl delete pods -l app=nextjs-client -n ${{ env.EKS_NAMESPACE }} --ignore-not-found=true || true
# Next.js ํด๋ผ์ด์–ธํŠธ๋งŒ ๋จผ์ € ๋ฐฐํฌ
echo "๐Ÿ“ฆ Deploying Next.js Client..."
if envsubst < k8s/nextjs-client.yaml | kubectl apply -f - -n ${{ env.EKS_NAMESPACE }}; then
echo "โœ… Next.js Client deployed successfully"
# ์ด๋ฏธ์ง€ ์—…๋ฐ์ดํŠธ
if kubectl set image deployment/nextjs-client nextjs-client=$ECR_REGISTRY/togather/client:${{ github.sha }} -n ${{ env.EKS_NAMESPACE }} --record=true; then
echo "โœ… Next.js Client image updated successfully"
# Pod ์žฌ์‹œ์ž‘ ๋Œ€๊ธฐ
echo "โณ Waiting for Next.js Client pods to be ready..."
kubectl rollout status deployment/nextjs-client -n ${{ env.EKS_NAMESPACE }} --timeout=300s || echo "โš ๏ธ Rollout timeout, but continuing..."
else
echo "โŒ Next.js Client image update failed"
fi
else
echo "โŒ Next.js Client deployment failed"
fi
- name: Build with Gradle (Backend)
run: |
chmod +x gradlew
./gradlew build -x test
# --- Spring Services Docker Build (with error handling) ----
- name: Build and Push API Gateway image
continue-on-error: true
run: |
echo "๐Ÿš€ Building API Gateway image..."
if docker build -f api-gateway/Dockerfile -t $ECR_REGISTRY/togather/api-gateway:${{ github.sha }} .; then
echo "โœ… API Gateway build successful"
docker tag $ECR_REGISTRY/togather/api-gateway:${{ github.sha }} $ECR_REGISTRY/togather/api-gateway:latest
if docker push $ECR_REGISTRY/togather/api-gateway:${{ github.sha }} && docker push $ECR_REGISTRY/togather/api-gateway:latest; then
echo "โœ… API Gateway pushed successfully"
else
echo "โŒ API Gateway push failed"
exit 1
fi
else
echo "โŒ API Gateway build failed"
exit 1
fi
- name: Build and Push User Service image
continue-on-error: true
run: |
echo "๐Ÿš€ Building User Service image..."
if docker build -f user-service/Dockerfile -t $ECR_REGISTRY/togather/user-service:${{ github.sha }} .; then
echo "โœ… User Service build successful"
docker tag $ECR_REGISTRY/togather/user-service:${{ github.sha }} $ECR_REGISTRY/togather/user-service:latest
if docker push $ECR_REGISTRY/togather/user-service:${{ github.sha }} && docker push $ECR_REGISTRY/togather/user-service:latest; then
echo "โœ… User Service pushed successfully"
else
echo "โŒ User Service push failed"
exit 1
fi
else
echo "โŒ User Service build failed"
exit 1
fi
- name: Build and Push Trading Service image
continue-on-error: true
run: |
echo "๐Ÿš€ Building Trading Service image..."
if docker build -f trading-service/Dockerfile -t $ECR_REGISTRY/togather/trading-service:${{ github.sha }} .; then
echo "โœ… Trading Service build successful"
docker tag $ECR_REGISTRY/togather/trading-service:${{ github.sha }} $ECR_REGISTRY/togather/trading-service:latest
if docker push $ECR_REGISTRY/togather/trading-service:${{ github.sha }} && docker push $ECR_REGISTRY/togather/trading-service:latest; then
echo "โœ… Trading Service pushed successfully"
else
echo "โŒ Trading Service push failed"
exit 1
fi
else
echo "โŒ Trading Service build failed"
exit 1
fi
- name: Build and Push Pay Service image
continue-on-error: true
run: |
echo "๐Ÿš€ Building Pay Service image..."
if docker build -f pay-service/Dockerfile -t $ECR_REGISTRY/togather/pay-service:${{ github.sha }} .; then
echo "โœ… Pay Service build successful"
docker tag $ECR_REGISTRY/togather/pay-service:${{ github.sha }} $ECR_REGISTRY/togather/pay-service:latest
if docker push $ECR_REGISTRY/togather/pay-service:${{ github.sha }} && docker push $ECR_REGISTRY/togather/pay-service:latest; then
echo "โœ… Pay Service pushed successfully"
else
echo "โŒ Pay Service push failed"
exit 1
fi
else
echo "โŒ Pay Service build failed"
exit 1
fi
- name: Build and Push Vote Service image
continue-on-error: true
run: |
echo "๐Ÿš€ Building Vote Service image..."
if docker build -f vote-service/Dockerfile -t $ECR_REGISTRY/togather/vote-service:${{ github.sha }} .; then
echo "โœ… Vote Service build successful"
docker tag $ECR_REGISTRY/togather/vote-service:${{ github.sha }} $ECR_REGISTRY/togather/vote-service:latest
if docker push $ECR_REGISTRY/togather/vote-service:${{ github.sha }} && docker push $ECR_REGISTRY/togather/vote-service:latest; then
echo "โœ… Vote Service pushed successfully"
else
echo "โŒ Vote Service push failed"
exit 1
fi
else
echo "โŒ Vote Service build failed"
exit 1
fi
# --- Spring Services Build Summary ---
- name: Spring Services Build Summary
run: |
echo "๐Ÿ“Š Spring Services Build Summary:"
echo "=================================="
echo "โœ… API Gateway: ${{ steps.build-api-gateway.outcome }}"
echo "โœ… User Service: ${{ steps.build-user-service.outcome }}"
echo "โœ… Trading Service: ${{ steps.build-trading-service.outcome }}"
echo "โœ… Pay Service: ${{ steps.build-pay-service.outcome }}"
echo "โœ… Vote Service: ${{ steps.build-vote-service.outcome }}"
# --- EKS ๋ฐฐํฌ ---
- name: Configure kubectl for EKS
run: |
aws eks update-kubeconfig --region ${{ env.AWS_REGION }} --name ${{ env.EKS_CLUSTER_NAME }}
- name: Deploy to EKS
if: github.ref == 'refs/heads/main'
run: |
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/api-gateway-rbac.yaml -n ${{ env.EKS_NAMESPACE }}
export ECR_REGISTRY=${{ env.ECR_REGISTRY }}
export CERTIFICATE_ARN=${{ secrets.CERTIFICATE_ARN }}
# Secrets ์ƒ์„ฑ
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: togather-secrets
namespace: ${{ env.EKS_NAMESPACE }}
type: Opaque
stringData:
SPRING_DATASOURCE_USERNAME: "${{ secrets.DB_USERNAME }}"
SPRING_DATASOURCE_PASSWORD: "${{ secrets.DB_PASSWORD }}"
DB_USERNAME: "${{ secrets.DB_USERNAME }}"
DB_PASSWORD: "${{ secrets.DB_PASSWORD }}"
JWT_SECRET_KEY: "${{ secrets.JWT_SECRET_KEY }}"
JWT_SECRET: "${{ secrets.JWT_SECRET_KEY }}"
SPRING_RABBITMQ_USERNAME: "admin"
SPRING_RABBITMQ_PASSWORD: "${{ secrets.RABBITMQ_PASSWORD }}"
REDIS_PASSWORD: "${{ secrets.REDIS_PASSWORD }}"
SPRING_DATA_REDIS_PASSWORD: "${{ secrets.REDIS_PASSWORD }}"
EOF
# ๋ฆฌ์†Œ์Šค ๋ฐฐํฌ (with error handling)
echo "๐Ÿš€ Deploying Kubernetes resources..."
FAILED_DEPLOYMENTS=""
SUCCESS_DEPLOYMENTS=""
for file in api-gateway user-service trading-service pay-service vote-service ingress; do
echo "๐Ÿ“ฆ Deploying $file..."
if envsubst < k8s/$file.yaml | kubectl apply -f - -n ${{ env.EKS_NAMESPACE }}; then
echo "โœ… $file deployed successfully"
SUCCESS_DEPLOYMENTS="$SUCCESS_DEPLOYMENTS $file"
else
echo "โŒ $file deployment failed"
FAILED_DEPLOYMENTS="$FAILED_DEPLOYMENTS $file"
fi
done
# Additional resources
echo "๐Ÿ“ฆ Deploying additional resources..."
for resource in configmap redis rabbitmq hpa; do
echo "๐Ÿ“ฆ Deploying $resource..."
if kubectl apply -f k8s/$resource.yaml -n ${{ env.EKS_NAMESPACE }}; then
echo "โœ… $resource deployed successfully"
SUCCESS_DEPLOYMENTS="$SUCCESS_DEPLOYMENTS $resource"
else
echo "โŒ $resource deployment failed"
FAILED_DEPLOYMENTS="$FAILED_DEPLOYMENTS $resource"
fi
done
# ์ตœ์‹  ์ด๋ฏธ์ง€ ๋ฐ˜์˜ (with error handling)
echo "๐Ÿ”„ Updating service images..."
for svc in api-gateway user-service trading-service pay-service vote-service; do
echo "๐Ÿ”„ Updating $svc image..."
if kubectl set image deployment/$svc $svc=$ECR_REGISTRY/togather/$svc:${{ github.sha }} -n ${{ env.EKS_NAMESPACE }} --record=true; then
echo "โœ… $svc image updated successfully"
else
echo "โŒ $svc image update failed"
FAILED_DEPLOYMENTS="$FAILED_DEPLOYMENTS $svc-image"
fi
done
# ๋ฐฐํฌ ๊ฒฐ๊ณผ ์š”์•ฝ
echo ""
echo "๐Ÿ“Š Deployment Summary:"
echo "====================="
if [ -n "$SUCCESS_DEPLOYMENTS" ]; then
echo "โœ… Successful: $SUCCESS_DEPLOYMENTS"
fi
if [ -n "$FAILED_DEPLOYMENTS" ]; then
echo "โŒ Failed: $FAILED_DEPLOYMENTS"
echo "โš ๏ธ Some deployments failed, but continuing..."
fi
# Next.js ํด๋ผ์ด์–ธํŠธ ์ตœ์ข… ์ƒํƒœ ํ™•์ธ
echo ""
echo "๐Ÿ” Next.js Client Final Status:"
echo "==============================="
kubectl get pods -l app=nextjs-client -n ${{ env.EKS_NAMESPACE }} -o wide || echo "โŒ Failed to get Next.js Client pods"
# Next.js ํด๋ผ์ด์–ธํŠธ Health Check
echo ""
echo "๐Ÿฅ Next.js Client Health Check:"
NEXTJS_POD=$(kubectl get pods -l app=nextjs-client -n ${{ env.EKS_NAMESPACE }} -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
if [ -n "$NEXTJS_POD" ]; then
echo "๐Ÿ“‹ Pod: $NEXTJS_POD"
kubectl logs $NEXTJS_POD -n ${{ env.EKS_NAMESPACE }} --tail=20 || echo "โŒ Failed to get logs"
else
echo "โŒ No Next.js Client pod found"
fi
# --- ๋ฐฐํฌ ์™„๋ฃŒ ํ›„ Prewarm ---
- name: Prewarm Next.js Client
if: github.ref == 'refs/heads/main'
run: |
echo "๐Ÿ”ฅ Prewarming Next.js..."
SITE_URL="https://xn--o79aq2k062a.store"
for i in {1..5}; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$SITE_URL" || echo "000")
echo "Request $i => HTTP $STATUS"
sleep 3
done
echo "โœ… Prewarm completed!"
# --- ์ƒ์„ธํ•œ Pod ์ƒํƒœ ์ ๊ฒ€ ๋ฐ ๋กœ๊ทธ ์ถœ๋ ฅ ---
- name: Detailed Pod Status Check
if: always()
run: |
echo "๐Ÿ” Detailed Pod Status Check"
echo "============================"
# ๋ชจ๋“  Pod ์ƒํƒœ ํ™•์ธ
echo "๐Ÿ“Š All Pods Status:"
kubectl get pods -n ${{ env.EKS_NAMESPACE }} -o wide || echo "โŒ Failed to get pods"
# Next.js Client Pod ์ƒํƒœ ์ƒ์„ธ ํ™•์ธ
echo ""
echo "๐Ÿš€ Next.js Client Pod Status:"
NEXTJS_PODS=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=nextjs-client -o jsonpath='{.items[*].metadata.name}' 2>/dev/null || echo "")
if [ -n "$NEXTJS_PODS" ]; then
for pod in $NEXTJS_PODS; do
echo "๐Ÿ“‹ Pod: $pod"
kubectl get pod $pod -n ${{ env.EKS_NAMESPACE }} -o jsonpath='{.status.phase}' 2>/dev/null && echo ""
kubectl get pod $pod -n ${{ env.EKS_NAMESPACE }} -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null && echo " (Ready)"
kubectl get pod $pod -n ${{ env.EKS_NAMESPACE }} -o jsonpath='{.status.containerStatuses[0].ready}' 2>/dev/null && echo " (Container Ready)"
done
else
echo "โŒ No Next.js Client pods found"
fi
# API Gateway Pod ์ƒํƒœ ํ™•์ธ
echo ""
echo "๐ŸŒ API Gateway Pod Status:"
API_PODS=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=api-gateway -o jsonpath='{.items[*].metadata.name}' 2>/dev/null || echo "")
if [ -n "$API_PODS" ]; then
for pod in $API_PODS; do
echo "๐Ÿ“‹ Pod: $pod"
kubectl get pod $pod -n ${{ env.EKS_NAMESPACE }} -o jsonpath='{.status.phase}' 2>/dev/null && echo ""
kubectl get pod $pod -n ${{ env.EKS_NAMESPACE }} -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null && echo " (Ready)"
done
else
echo "โŒ No API Gateway pods found"
fi
# --- ๋น„์ •์ƒ Pod ๋กœ๊ทธ ์ถœ๋ ฅ ---
- name: Unhealthy Pod Logs
if: always()
run: |
echo "๐Ÿšจ Unhealthy Pod Logs Check"
echo "=========================="
# Next.js Client ๋น„์ •์ƒ Pod ๋กœ๊ทธ
echo "๐Ÿ” Next.js Client Pod Logs:"
NEXTJS_PODS=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=nextjs-client -o jsonpath='{.items[*].metadata.name}' 2>/dev/null || echo "")
if [ -n "$NEXTJS_PODS" ]; then
for pod in $NEXTJS_PODS; do
echo "๐Ÿ“‹ Pod: $pod"
READY_STATUS=$(kubectl get pod $pod -n ${{ env.EKS_NAMESPACE }} -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null || echo "Unknown")
if [ "$READY_STATUS" != "True" ]; then
echo "โš ๏ธ Pod $pod is not ready (Status: $READY_STATUS)"
echo "๐Ÿ“ Recent logs from $pod:"
kubectl logs $pod -n ${{ env.EKS_NAMESPACE }} --tail=50 || echo "โŒ Failed to get logs from $pod"
echo ""
echo "๐Ÿ“ Pod description for $pod:"
kubectl describe pod $pod -n ${{ env.EKS_NAMESPACE }} || echo "โŒ Failed to describe pod $pod"
echo ""
else
echo "โœ… Pod $pod is ready"
fi
done
fi
# API Gateway ๋น„์ •์ƒ Pod ๋กœ๊ทธ
echo "๐Ÿ” API Gateway Pod Logs:"
API_PODS=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=api-gateway -o jsonpath='{.items[*].metadata.name}' 2>/dev/null || echo "")
if [ -n "$API_PODS" ]; then
for pod in $API_PODS; do
echo "๐Ÿ“‹ Pod: $pod"
READY_STATUS=$(kubectl get pod $pod -n ${{ env.EKS_NAMESPACE }} -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null || echo "Unknown")
if [ "$READY_STATUS" != "True" ]; then
echo "โš ๏ธ Pod $pod is not ready (Status: $READY_STATUS)"
echo "๐Ÿ“ Recent logs from $pod:"
kubectl logs $pod -n ${{ env.EKS_NAMESPACE }} --tail=50 || echo "โŒ Failed to get logs from $pod"
echo ""
echo "๐Ÿ“ Pod description for $pod:"
kubectl describe pod $pod -n ${{ env.EKS_NAMESPACE }} || echo "โŒ Failed to describe pod $pod"
echo ""
else
echo "โœ… Pod $pod is ready"
fi
done
fi
# --- Health Check ์ƒํƒœ ํ™•์ธ ---
- name: Health Check Status
if: always()
run: |
echo "๐Ÿฅ Health Check Status"
echo "====================="
# Next.js Client health check
echo "๐Ÿ” Next.js Client Health Check:"
NEXTJS_PODS=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=nextjs-client -o jsonpath='{.items[*].metadata.name}' 2>/dev/null || echo "")
if [ -n "$NEXTJS_PODS" ]; then
for pod in $NEXTJS_PODS; do
echo "๐Ÿ“‹ Testing /api/healthz on pod: $pod"
POD_IP=$(kubectl get pod $pod -n ${{ env.EKS_NAMESPACE }} -o jsonpath='{.status.podIP}' 2>/dev/null || echo "")
if [ -n "$POD_IP" ]; then
echo "๐ŸŒ Pod IP: $POD_IP"
# Pod ๋‚ด๋ถ€์—์„œ health check ํ…Œ์ŠคํŠธ
kubectl exec $pod -n ${{ env.EKS_NAMESPACE }} -- curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/api/healthz 2>/dev/null || echo "โŒ Health check failed"
else
echo "โŒ Could not get pod IP"
fi
done
fi
# --- ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์ƒ์„ธ ์ง„๋‹จ ---
- name: Detailed Error Diagnostics
if: failure()
run: |
echo "๐Ÿšจ DEPLOYMENT FAILED - Detailed diagnostics..."
echo "============================================="
# ๋ชจ๋“  Pod ์ƒํƒœ
echo "๐Ÿ“Š All Pods Status:"
kubectl get pods -n ${{ env.EKS_NAMESPACE }} -o wide || echo "โŒ Failed to get pods"
# ์ด๋ฒคํŠธ ํ™•์ธ
echo ""
echo "๐Ÿ“ Recent Events:"
kubectl get events -n ${{ env.EKS_NAMESPACE }} --sort-by='.lastTimestamp' | tail -20 || echo "โŒ Failed to get events"
# ์„œ๋น„์Šค ์ƒํƒœ
echo ""
echo "๐ŸŒ Services Status:"
kubectl get svc -n ${{ env.EKS_NAMESPACE }} || echo "โŒ Failed to get services"
# Ingress ์ƒํƒœ
echo ""
echo "๐Ÿ”— Ingress Status:"
kubectl get ingress -n ${{ env.EKS_NAMESPACE }} || echo "โŒ Failed to get ingress"
#name: Deploy ToGather Microservices to AWS EKS
#
#on:
# push:
# branches: [ main ]
# pull_request:
# branches: [ main ]
# workflow_dispatch:
#
#env:
# AWS_REGION: ap-northeast-2
# ECR_REGISTRY: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com
# EKS_CLUSTER_NAME: togather-cluster
# EKS_NAMESPACE: togather
# # CDN ์„ค์ •!
# CDN_URL: https://d36ue99r8i68ow.cloudfront.net
# S3_BUCKET_NAME: togather-static-assets
# CLOUDFRONT_DISTRIBUTION_ID: E15ZDIW40YBVEN
#
#jobs:
# build-and-deploy:
# runs-on: ubuntu-latest
#
# steps:
# - name: Checkout code
# uses: actions/checkout@v4
#
# - name: Set gradlew permissions
# run: chmod +x gradlew
#
# - name: Configure AWS credentials
# uses: aws-actions/configure-aws-credentials@v4
# with:
# aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
# aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# aws-region: ${{ env.AWS_REGION }}
#
# - name: Login to Amazon ECR
# id: login-ecr
# uses: aws-actions/amazon-ecr-login@v2
#
# - name: Checkout Client Repo # ToGather-Client ์ ‘๊ทผ!
# uses: actions/checkout@v4
# with:
# repository: ToGather-Final/ToGather-Client
# token: ${{ secrets.GH_PAT }}
# path: togather-client
#
# - name: Setup pnpm
# uses: pnpm/action-setup@v4
# with:
# version: latest
#
# - name: Cache pnpm dependencies
# uses: actions/cache@v3
# with:
# path: |
# ~/.pnpm-store
# togather-client/node_modules
# key: ${{ runner.os }}-pnpm-${{ hashFiles('togather-client/pnpm-lock.yaml') }}
# restore-keys: |
# ${{ runner.os }}-pnpm-
#
# - name: Set up JDK 17
# uses: actions/setup-java@v4
# with:
# java-version: '17'
# distribution: 'temurin'
#
# - name: Cache Gradle packages
# uses: actions/cache@v3
# with:
# path: |
# ~/.gradle/caches
# ~/.gradle/wrapper
# key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
# restore-keys: |
# ${{ runner.os }}-gradle-
#
# - name: Build with Gradle
# run: |
# chmod +x gradlew
# ./gradlew build -x test
#
# # - name: Build and push Next.js Client image
# # run: |
# # docker build -t $ECR_REGISTRY/togather/client:${{ github.sha }} -f ./togather-client/Dockerfile ./togather-client
# # docker build -t $ECR_REGISTRY/togather/client:latest -f ./togather-client/Dockerfile ./togather-client
# # docker push $ECR_REGISTRY/togather/client:${{ github.sha }}
# # docker push $ECR_REGISTRY/togather/client:latest
#
# - name: Build Next.js Client and upload static assets
# run: |
# cd togather-client
# export CDN_URL_CLEAN=$(echo "${{ env.CDN_URL }}" | sed 's:/*$::')
# echo "๐Ÿ›ฐ Using CDN_URL=$CDN_URL_CLEAN"
#
# pnpm install --frozen-lockfile
#
# # โœ… Next.js ๋นŒ๋“œ (๋‹จ 1ํšŒ)
# SERVER_API_BASE_URL=http://api-gateway.togather.svc.cluster.local:8000/api \
# NEXT_PUBLIC_API_BASE_URL=https://xn--o79aq2k062a.store/api \
# CDN_URL=$CDN_URL_CLEAN pnpm run build
#
# # โœ… ๋นŒ๋“œ ์‚ฐ์ถœ๋ฌผ ์•„ํ‹ฐํŒฉํŠธ๋กœ ๋ณด๊ด€ (Docker์™€ S3์—์„œ ๋™์ผ ๋นŒ๋“œ ์‚ฌ์šฉ)
# cd ..
# tar -czf next-artifacts.tgz -C togather-client .next/standalone .next/static .next/server public
# echo "โœ… next-artifacts.tgz ์ƒ์„ฑ ์™„๋ฃŒ"
#
# # โœ… ์ •์  ์ž์‚ฐ ์—…๋กœ๋“œ ๋ฐ CDN ๋ฌดํšจํ™”
# cd togather-client
# pnpm run upload-assets
# env:
# CDN_URL: ${{ env.CDN_URL }}
# S3_BUCKET_NAME: ${{ env.S3_BUCKET_NAME }}
# CLOUDFRONT_DISTRIBUTION_ID: ${{ env.CLOUDFRONT_DISTRIBUTION_ID }}
# NEXT_PUBLIC_API_BASE_URL: https://xn--o79aq2k062a.store
#
# # โœ… next-artifacts.tgz ํŒŒ์ผ์„ ์—…๋กœ๋“œ (๋นŒ๋“œ ๊ฒฐ๊ณผ ๋ฐฑ์—…)
# - name: Upload Next build artifacts
# uses: actions/upload-artifact@v4
# with:
# name: next-artifacts
# path: next-artifacts.tgz
#
# # โœ… ๋นŒ๋“œ ๊ฒฐ๊ณผ๋ฅผ Docker ์ด๋ฏธ์ง€ ์ƒ์„ฑ์— ์žฌ์‚ฌ์šฉ
# - name: Download Next.js build artifacts
# uses: actions/download-artifact@v4
# with:
# name: next-artifacts
# path: ./togather-client
#
# echo "โœ… Next.js build completed. Checking output structure..."
# ls -R .next | head -n 40
#
# # โœ… server entry ๊ฒ€์ฆ
# if [ ! -f ".next/standalone/server.js" ] && [ ! -f ".next/standalone/server.mjs" ]; then
# echo "โŒ .next/standalone/server.js(.mjs) not found!"
# echo "๋นŒ๋“œ ์‚ฐ์ถœ๋ฌผ ๋ˆ„๋ฝ. ๋นŒ๋“œ ์‹คํŒจ๋กœ ๊ฐ„์ฃผํ•ฉ๋‹ˆ๋‹ค."
# ls -R .next/standalone | head -n 50 || true
# exit 1
# fi
#
#
# # โœ… ๋นŒ๋“œ ์‚ฐ์ถœ๋ฌผ ์•„ํ‹ฐํŒฉํŠธ๋กœ ๋ณด๊ด€ (Docker์™€ S3์—์„œ ๋™์ผ ๋นŒ๋“œ ์‚ฌ์šฉ)!!!
# cd ..
# tar -czf next-artifacts.tgz -C togather-client .next/standalone .next/static public
# echo "โœ… next-artifacts.tgz ์ƒ์„ฑ ์™„๋ฃŒ"
#
# - name: Build and push Next.js runtime image
# run: |
# echo "๐Ÿš€ Building Next.js runtime image..."
# docker build \
# --build-arg SERVER_API_BASE_URL=http://api-gateway.togather.svc.cluster.local:8000/api \
# --build-arg NEXT_PUBLIC_API_BASE_URL=https://xn--o79aq2k062a.store/api \
# --build-arg CDN_URL=${{ env.CDN_URL }} \
# -t $ECR_REGISTRY/togather/client:${{ github.sha }} \
# -f ./togather-client/Dockerfile ./togather-client
#
# # โœ… ํƒœ๊ทธ ๋ฐ ํ‘ธ์‹œ
# docker tag $ECR_REGISTRY/togather/client:${{ github.sha }} $ECR_REGISTRY/togather/client:latest
# docker push $ECR_REGISTRY/togather/client:${{ github.sha }}
# docker push $ECR_REGISTRY/togather/client:latest
#
# # โœ… ๋นŒ๋“œ ๊ฒ€์ฆ ๋กœ๊ทธ
# echo "โœ… Docker image for Next.js successfully built and pushed!"
#
#
# - name: Upload Next build artifacts
# uses: actions/upload-artifact@v4
# with:
# name: next-artifacts
# path: next-artifacts.tgz
#
# - name: Download Next.js build artifacts
# uses: actions/download-artifact@v4
# with:
# name: next-artifacts
# path: ./togather-client
#
# - name: Extract Next.js artifacts
# run: |
# tar -xzf ./togather-client/next-artifacts.tgz -C ./togather-client
# echo "โœ… next-artifacts.tgz ์••์ถ• ํ•ด์ œ ์™„๋ฃŒ"
# ls -R ./togather-client/.next/standalone | head -n 20
#
# # โœ… kr ๋„์ž…์„ ์œ„ํ•ด ์ถ”๊ฐ€ --build-arg CDN_URL=${{ env.CDN_URL }} \
# - name: Build and push Next.js runtime image
# run: |
# echo "๐Ÿš€ Building Next.js runtime image..."
# cd togather-client
#
# # ๋นŒ๋“œ ์‚ฐ์ถœ๋ฌผ ๊ฒ€์ฆ
# if [ ! -f ".next/standalone/server.js" ]; then
# echo "โŒ server.js not found in .next/standalone โ€” build failed!"
# ls -R .next | head -n 40
# exit 1
# fi
#
# docker build \
# --build-arg SERVER_API_BASE_URL=http://api-gateway.togather.svc.cluster.local:8000/api \
# --build-arg NEXT_PUBLIC_API_BASE_URL=https://xn--o79aq2k062a.store/api \
# --build-arg CDN_URL=${{ env.CDN_URL }} \
# -t $ECR_REGISTRY/togather/client:${{ github.sha }} \
# -t $ECR_REGISTRY/togather/client:latest \
# -f Dockerfile .
#
# docker push $ECR_REGISTRY/togather/client:${{ github.sha }}
# docker push $ECR_REGISTRY/togather/client:latest
#
# - name: Build and push Vote Service image
# run: |
# docker build -f vote-service/Dockerfile -t $ECR_REGISTRY/togather/vote-service:${{ github.sha }} .
# docker build -f vote-service/Dockerfile -t $ECR_REGISTRY/togather/vote-service:latest .
# docker push $ECR_REGISTRY/togather/vote-service:${{ github.sha }}
# docker push $ECR_REGISTRY/togather/vote-service:latest
#
# - name: Install kubectl
# uses: azure/setup-kubectl@v3
# with:
# version: 'v1.28.0'
#
# - name: Configure kubectl for EKS
# run: |
# aws eks update-kubeconfig --region ${{ env.AWS_REGION }} --name ${{ env.EKS_CLUSTER_NAME }}
#
# - name: Deploy to EKS
# if: github.ref == 'refs/heads/main'
# run: |
# # 1. ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ƒ์„ฑ (์—†์œผ๋ฉด ์ƒ์„ฑ, ์žˆ์œผ๋ฉด ๋„˜์–ด๊ฐ)
# kubectl apply -f k8s/namespace.yaml
#
# # 2. Secret ์ƒ์„ฑ (๋ชจ๋“  ๋ฏผ๊ฐ ์ •๋ณด๋ฅผ GitHub Secrets์—์„œ ๊ฐ€์ ธ์™€ ํ†ตํ•ฉ)
# kubectl apply -f - <<EOF
# apiVersion: v1
# kind: Secret
# metadata:
# name: togather-secrets
# namespace: ${{ env.EKS_NAMESPACE }}
# type: Opaque
# stringData:
# SPRING_DATASOURCE_USERNAME: "${{ secrets.DB_USERNAME }}"
# SPRING_DATASOURCE_PASSWORD: "${{ secrets.DB_PASSWORD }}"
# DB_USERNAME: "${{ secrets.DB_USERNAME }}"
# DB_PASSWORD: "${{ secrets.DB_PASSWORD }}"
# JWT_SECRET_KEY: "${{ secrets.JWT_SECRET_KEY }}"
# JWT_SECRET: "${{ secrets.JWT_SECRET_KEY }}"
# SPRING_RABBITMQ_USERNAME: "admin"
# SPRING_RABBITMQ_PASSWORD: "${{ secrets.RABBITMQ_PASSWORD }}"
# RABBITMQ_USERNAME: "admin"
# RABBITMQ_PASSWORD: "${{ secrets.RABBITMQ_PASSWORD }}"
# REDIS_PASSWORD: "${{ secrets.REDIS_PASSWORD }}"
# SPRING_DATA_REDIS_PASSWORD: "${{ secrets.REDIS_PASSWORD }}"
# # KIS ์ฆ๊ถŒ API ํ™˜๊ฒฝ๋ณ€์ˆ˜
# KIS_BASE_URL: "${{ secrets.KIS_BASE_URL }}"
# KIS_APPKEY: "${{ secrets.KIS_APPKEY }}"
# KIS_APPSECRET: "${{ secrets.KIS_APPSECRET }}"
# EOF
#
# # 3. RBAC ๋จผ์ € ์ ์šฉ (ServiceAccount/Role/RoleBinding)
# kubectl apply -f k8s/api-gateway-rbac.yaml -n ${{ env.EKS_NAMESPACE }}
#
# # 4. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์น˜ํ™˜ ํ›„ ๋‚˜๋จธ์ง€ ๋ชจ๋“  ๋ฆฌ์†Œ์Šค ๋ฐฐํฌ
# # ECR_REGISTRY์™€ CERTIFICATE_ARN ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ k8s ํŒŒ์ผ๋“ค์— ์น˜ํ™˜
# export ECR_REGISTRY=${{ env.ECR_REGISTRY }}
# export CERTIFICATE_ARN=${{ secrets.CERTIFICATE_ARN }}
#
# # ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์น˜ํ™˜์ด ํ•„์š”ํ•œ ํŒŒ์ผ๋“ค ๋ฐฐํฌ
# envsubst < k8s/api-gateway.yaml | kubectl apply -f - -n ${{ env.EKS_NAMESPACE }}
# envsubst < k8s/user-service.yaml | kubectl apply -f - -n ${{ env.EKS_NAMESPACE }}
# envsubst < k8s/trading-service.yaml | kubectl apply -f - -n ${{ env.EKS_NAMESPACE }}
# envsubst < k8s/pay-service.yaml | kubectl apply -f - -n ${{ env.EKS_NAMESPACE }}
# envsubst < k8s/vote-service.yaml | kubectl apply -f - -n ${{ env.EKS_NAMESPACE }}
# envsubst < k8s/nextjs-client.yaml | kubectl apply -f - -n ${{ env.EKS_NAMESPACE }}
# envsubst < k8s/ingress.yaml | kubectl apply -f - -n ${{ env.EKS_NAMESPACE }}
#
# # ๋‚˜๋จธ์ง€ ๋ฆฌ์†Œ์Šค๋“ค (ConfigMap, Service, HPA ๋“ฑ) ๋ฐฐํฌ
# kubectl apply -f k8s/configmap.yaml -n ${{ env.EKS_NAMESPACE }}
# kubectl apply -f k8s/configmap-env.yaml -n ${{ env.EKS_NAMESPACE }}
# kubectl apply -f k8s/redis.yaml -n ${{ env.EKS_NAMESPACE }}
# kubectl apply -f k8s/rabbitmq.yaml -n ${{ env.EKS_NAMESPACE }}
# # ingress.yaml๊ณผ nextjs-client.yaml์€ ์œ„์—์„œ envsubst๋กœ ์ด๋ฏธ ๋ฐฐํฌ๋จ
# kubectl apply -f k8s/hpa.yaml -n ${{ env.EKS_NAMESPACE }} # ๐Ÿš€ HPA ์žฌํ™œ์„ฑํ™”
#
# # 5. ๊ฐ ๋””ํ”Œ๋กœ์ด๋จผํŠธ์— ์ปค๋ฐ‹ SHA ์ด๋ฏธ์ง€ ์„ค์ • (๋กค์•„์›ƒ ํŠธ๋ฆฌ๊ฑฐ)
# kubectl set image deployment/api-gateway api-gateway=${{ env.ECR_REGISTRY }}/togather/api-gateway:${{ github.sha }} -n ${{ env.EKS_NAMESPACE }} --record=true
# kubectl set image deployment/user-service user-service=${{ env.ECR_REGISTRY }}/togather/user-service:${{ github.sha }} -n ${{ env.EKS_NAMESPACE }} --record=true
# kubectl set image deployment/trading-service trading-service=${{ env.ECR_REGISTRY }}/togather/trading-service:${{ github.sha }} -n ${{ env.EKS_NAMESPACE }} --record=true
# kubectl set image deployment/pay-service pay-service=${{ env.ECR_REGISTRY }}/togather/pay-service:${{ github.sha }} -n ${{ env.EKS_NAMESPACE }} --record=true
# kubectl set image deployment/vote-service vote-service=${{ env.ECR_REGISTRY }}/togather/vote-service:${{ github.sha }} -n ${{ env.EKS_NAMESPACE }} --record=true
# kubectl set image deployment/nextjs-client nextjs-client=${{ env.ECR_REGISTRY }}/togather/client:${{ github.sha }} -n ${{ env.EKS_NAMESPACE }} --record=true
#
# - name: Invalidate CloudFront Cache
# if: github.ref == 'refs/heads/main'
# uses: chetan/invalidate-cloudfront-action@v2
# env:
# DISTRIBUTION: ${{ env.CLOUDFRONT_DISTRIBUTION_ID }}
# PATHS: "/*" # ๐Ÿ’ก ๋ชจ๋“  ํŒŒ์ผ(*)์„ ๋ฌดํšจํ™”ํ•˜์—ฌ ์ฆ‰์‹œ ๋ณ€๊ฒฝ์‚ฌํ•ญ ๋ฐ˜์˜d
# AWS_REGION: "us-east-1" # ์ธ์ฆ์„œ๋Š” us-east-1์— ์žˆ์–ด์•ผ ํ•˜๋ฏ€๋กœ ๋ช…์‹œ
# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
#
# - name: Wait for deployment to complete
# if: github.ref == 'refs/heads/main'
# run: |
# # ๋ฐฐํฌ ๊ฒฐ๊ณผ ์ถ”์ ์„ ์œ„ํ•œ ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™”
# FAILED_SERVICES=""
# SUCCESS_SERVICES=""
#
# # Redis ๋ฐฐํฌ ํ™•์ธ
# echo "๐Ÿš€ Redis ๋ฐฐํฌ ์ƒํƒœ ํ™•์ธ ์ค‘..."
# if kubectl rollout status deployment/redis -n ${{ env.EKS_NAMESPACE }} --timeout=60s; then
# echo "โœ… Redis ๋ฐฐํฌ ์„ฑ๊ณต"
# SUCCESS_SERVICES="$SUCCESS_SERVICES redis"
# else
# echo "โŒ Redis ๋ฐฐํฌ ์‹คํŒจ! ์ง„๋‹จ ์ •๋ณด ์ถœ๋ ฅ ์ค‘..."
# FAILED_SERVICES="$FAILED_SERVICES redis"
# kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=redis
# kubectl describe deployment redis -n ${{ env.EKS_NAMESPACE }}
# POD=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=redis -o jsonpath='{.items[0].metadata.name}')
# kubectl describe pod $POD -n ${{ env.EKS_NAMESPACE }} || true
# kubectl logs $POD -n ${{ env.EKS_NAMESPACE }} --tail=100 || true
# fi
#
# # API Gateway ๋ฐฐํฌ ํ™•์ธ!!
# echo ""
# echo "๐Ÿš€ API Gateway ๋ฐฐํฌ ์ƒํƒœ ํ™•์ธ ์ค‘..."
# if kubectl rollout status deployment/api-gateway -n ${{ env.EKS_NAMESPACE }} --timeout=240s; then
# echo "โœ… API Gateway ๋ฐฐํฌ ์„ฑ๊ณต"
# SUCCESS_SERVICES="$SUCCESS_SERVICES api-gateway"
# else
# echo "โŒ API Gateway ๋ฐฐํฌ ์‹คํŒจ! ์ง„๋‹จ ์ •๋ณด ์ถœ๋ ฅ ์ค‘..."
# FAILED_SERVICES="$FAILED_SERVICES api-gateway"
# kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=api-gateway
# kubectl describe deployment api-gateway -n ${{ env.EKS_NAMESPACE }}
# POD=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=api-gateway -o jsonpath='{.items[0].metadata.name}')
# kubectl describe pod $POD -n ${{ env.EKS_NAMESPACE }} || true
# kubectl logs $POD -n ${{ env.EKS_NAMESPACE }} --tail=100 || true
# fi
#
# # User Service ๋ฐฐํฌ ํ™•์ธ
# echo ""
# echo "๐Ÿš€ User Service ๋ฐฐํฌ ์ƒํƒœ ํ™•์ธ ์ค‘..."
# if kubectl rollout status deployment/user-service -n ${{ env.EKS_NAMESPACE }} --timeout=180s; then
# echo "โœ… User Service ๋ฐฐํฌ ์„ฑ๊ณต"
# SUCCESS_SERVICES="$SUCCESS_SERVICES user-service"
# else
# echo "โŒ User Service ๋ฐฐํฌ ์‹คํŒจ! ์ง„๋‹จ ์ •๋ณด ์ถœ๋ ฅ ์ค‘..."
# FAILED_SERVICES="$FAILED_SERVICES user-service"
# kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=user-service
# kubectl describe deployment user-service -n ${{ env.EKS_NAMESPACE }}
# POD=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=user-service -o jsonpath='{.items[0].metadata.name}')
# kubectl describe pod $POD -n ${{ env.EKS_NAMESPACE }} || true
# kubectl logs $POD -n ${{ env.EKS_NAMESPACE }} --tail=100 || true
# fi
#
# # Trading Service ๋ฐฐํฌ ํ™•์ธ
# echo ""
# echo "๐Ÿš€ Trading Service ๋ฐฐํฌ ์ƒํƒœ ํ™•์ธ ์ค‘..."
# if kubectl rollout status deployment/trading-service -n ${{ env.EKS_NAMESPACE }} --timeout=180s; then
# echo "โœ… Trading Service ๋ฐฐํฌ ์„ฑ๊ณต"
# SUCCESS_SERVICES="$SUCCESS_SERVICES trading-service"
# else
# echo "โŒ Trading Service ๋ฐฐํฌ ์‹คํŒจ! ์ง„๋‹จ ์ •๋ณด ์ถœ๋ ฅ ์ค‘..."
# FAILED_SERVICES="$FAILED_SERVICES trading-service"
# kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=trading-service
# kubectl describe deployment trading-service -n ${{ env.EKS_NAMESPACE }}
# POD=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=trading-service -o jsonpath='{.items[0].metadata.name}')
# kubectl describe pod $POD -n ${{ env.EKS_NAMESPACE }} || true
# kubectl logs $POD -n ${{ env.EKS_NAMESPACE }} --tail=100 || true
# fi
#
# # Pay Service ๋ฐฐํฌ ํ™•์ธ
# echo ""
# echo "๐Ÿš€ Pay Service ๋ฐฐํฌ ์ƒํƒœ ํ™•์ธ ์ค‘..."
# if kubectl rollout status deployment/pay-service -n ${{ env.EKS_NAMESPACE }} --timeout=180s; then
# echo "โœ… Pay Service ๋ฐฐํฌ ์„ฑ๊ณต"
# SUCCESS_SERVICES="$SUCCESS_SERVICES pay-service"
# else
# echo "โŒ Pay Service ๋ฐฐํฌ ์‹คํŒจ! ์ง„๋‹จ ์ •๋ณด ์ถœ๋ ฅ ์ค‘..."
# FAILED_SERVICES="$FAILED_SERVICES pay-service"
# kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=pay-service
# kubectl describe deployment pay-service -n ${{ env.EKS_NAMESPACE }}
# POD=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=pay-service -o jsonpath='{.items[0].metadata.name}')
# kubectl describe pod $POD -n ${{ env.EKS_NAMESPACE }} || true
# kubectl logs $POD -n ${{ env.EKS_NAMESPACE }} --tail=100 || true
# fi
#
# # Vote Service ๋ฐฐํฌ ํ™•์ธ
# echo ""
# echo "๐Ÿš€ Vote Service ๋ฐฐํฌ ์ƒํƒœ ํ™•์ธ ์ค‘..."
# if kubectl rollout status deployment/vote-service -n ${{ env.EKS_NAMESPACE }} --timeout=180s; then
# echo "โœ… Vote Service ๋ฐฐํฌ ์„ฑ๊ณต"
# SUCCESS_SERVICES="$SUCCESS_SERVICES vote-service"
# else
# echo "โŒ Vote Service ๋ฐฐํฌ ์‹คํŒจ! ์ง„๋‹จ ์ •๋ณด ์ถœ๋ ฅ ์ค‘..."
# FAILED_SERVICES="$FAILED_SERVICES vote-service"
# kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=vote-service
# kubectl describe deployment vote-service -n ${{ env.EKS_NAMESPACE }}
# POD=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=vote-service -o jsonpath='{.items[0].metadata.name}')
# kubectl describe pod $POD -n ${{ env.EKS_NAMESPACE }} || true
# kubectl logs $POD -n ${{ env.EKS_NAMESPACE }} --tail=100 || true
# fi
#
# # Next.js Client ๋ฐฐํฌ ํ™•์ธ
# echo ""
# echo "๐Ÿš€ Next.js Client ๋ฐฐํฌ ์ƒํƒœ ํ™•์ธ ์ค‘..."
# if kubectl rollout status deployment/nextjs-client -n ${{ env.EKS_NAMESPACE }} --timeout=120s; then
# echo "โœ… Next.js Client ๋ฐฐํฌ ์„ฑ๊ณต"
# SUCCESS_SERVICES="$SUCCESS_SERVICES nextjs-client"
# else
# echo "โŒ Next.js Client ๋ฐฐํฌ ์‹คํŒจ! ์ง„๋‹จ ์ •๋ณด ์ถœ๋ ฅ ์ค‘..."
# FAILED_SERVICES="$FAILED_SERVICES nextjs-client"
# kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=nextjs-client
# kubectl describe deployment nextjs-client -n ${{ env.EKS_NAMESPACE }}
# POD=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=nextjs-client -o jsonpath='{.items[0].metadata.name}')
# kubectl describe pod $POD -n ${{ env.EKS_NAMESPACE }} || true
# kubectl logs $POD -n ${{ env.EKS_NAMESPACE }} --tail=100 || true
# fi
#
# # ์ตœ์ข… ๋ฐฐํฌ ๊ฒฐ๊ณผ ์š”์•ฝ
# echo ""
# echo "=================================================="
# echo "๐Ÿ“Š ๋ฐฐํฌ ๊ฒฐ๊ณผ ์š”์•ฝ"
# echo "=================================================="
#
# if [ -n "$SUCCESS_SERVICES" ]; then
# echo "โœ… ์„ฑ๊ณตํ•œ ์„œ๋น„์Šค:$SUCCESS_SERVICES"
# fi
#
# if [ -n "$FAILED_SERVICES" ]; then
# echo "โŒ ์‹คํŒจํ•œ ์„œ๋น„์Šค:$FAILED_SERVICES"
# echo ""
# echo "โš ๏ธ ์ผ๋ถ€ ์„œ๋น„์Šค ๋ฐฐํฌ๊ฐ€ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค!"
# exit 1
# else
# echo ""
# echo "๐ŸŽ‰ ๋ชจ๋“  ์„œ๋น„์Šค ๋ฐฐํฌ ์™„๋ฃŒ!"
# fi
#
# - name: Verify deployment
# if: github.ref == 'refs/heads/main'
# run: |
# kubectl get pods -n ${{ env.EKS_NAMESPACE }}
# kubectl get services -n ${{ env.EKS_NAMESPACE }}
# kubectl get ingress -n ${{ env.EKS_NAMESPACE }}
#
# - name: Prewarm Next.js Client
# if: github.ref == 'refs/heads/main'
# run: |
# echo "๐Ÿ”ฅ Next.js ํด๋ผ์ด์–ธํŠธ Prewarming ์‹œ์ž‘..."
# SITE_URL="https://xn--o79aq2k062a.store"
#
# # ๋ฐฐํฌ ์™„๋ฃŒ ๋Œ€๊ธฐ (์ตœ๋Œ€ 2๋ถ„)
# echo "โณ Next.js ํด๋ผ์ด์–ธํŠธ ์ค€๋น„ ๋Œ€๊ธฐ ์ค‘..."
# for i in {1..24}; do
# if kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=nextjs-client -o jsonpath='{.items[0].status.conditions[?(@.type=="Ready")].status}' | grep -q "True"; then
# echo "โœ… Next.js ํด๋ผ์ด์–ธํŠธ ์ค€๋น„ ์™„๋ฃŒ!"
# break
# fi
# echo "๋Œ€๊ธฐ ์ค‘... ($i/24)"
# sleep 5
# done
#
# # Prewarming ์š”์ฒญ (5ํšŒ)
# echo "๐Ÿ”ฅ ์›Œ๋ฐ์—… ์š”์ฒญ ์ „์†ก ์ค‘..."
# for i in {1..5}; do
# STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "$SITE_URL" || echo "000")
# if [ "$STATUS_CODE" = "200" ]; then
# echo "โœ… ์›Œ๋ฐ์—… ์š”์ฒญ $i/5 ์„ฑ๊ณต (HTTP $STATUS_CODE)"
# else
# echo "โš ๏ธ ์›Œ๋ฐ์—… ์š”์ฒญ $i/5 ์‹คํŒจ (HTTP $STATUS_CODE)"
# fi
# sleep 1
# done
#
# echo "๐ŸŽ‰ Prewarming ์™„๋ฃŒ! ์‚ฌ์šฉ์ž๋“ค์ด ๋น ๋ฅธ ์‘๋‹ต์„ ๊ฒฝํ—˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."
#
# - name: Diagnostics on failure
# if: failure()
# run: |
# kubectl get deploy -n ${{ env.EKS_NAMESPACE }}
# kubectl describe deploy api-gateway -n ${{ env.EKS_NAMESPACE }}
# kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=api-gateway -o wide
# POD=$(kubectl get pods -n ${{ env.EKS_NAMESPACE }} -l app=api-gateway -o jsonpath='{.items[0].metadata.name}')
# kubectl describe pod $POD -n ${{ env.EKS_NAMESPACE }} || true
# kubectl logs $POD -n ${{ env.EKS_NAMESPACE }} --tail=200 || true