Skip to content

Merge pull request #125 from Yoonhojoon/hotfix/redis #202

Merge pull request #125 from Yoonhojoon/hotfix/redis

Merge pull request #125 from Yoonhojoon/hotfix/redis #202

Workflow file for this run

name: Terraform CI
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
terraform:
runs-on: ubuntu-22.04
defaults:
run:
working-directory: infrastructure
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.6.6
- 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: ap-northeast-2
- name: Create S3 bucket if not exists
run: |
aws s3api head-bucket --bucket mclass-terraform-state-20250731 2>/dev/null || aws s3 mb s3://mclass-terraform-state-20250731 --region ap-northeast-2
aws s3api put-bucket-versioning --bucket mclass-terraform-state-20250731 --versioning-configuration Status=Enabled
aws dynamodb describe-table --table-name terraform-lock --region ap-northeast-2 2>/dev/null || aws dynamodb create-table --table-name terraform-lock --attribute-definitions AttributeName=LockID,AttributeType=S --key-schema AttributeName=LockID,KeyType=HASH --billing-mode PAY_PER_REQUEST --region ap-northeast-2
- name: Terraform Init
run: terraform init
- name: Terraform Format Check
run: terraform fmt -check
- name: Terraform Validate
run: terraform validate
- name: Create terraform.tfvars from ENV_PROD
run: |
# 민감한 정보를 환경 변수로 설정하여 마스킹 (개행/공백 제거)
echo "${{ secrets.ENV_PROD }}" | tr -d '\r' | sed 's/[[:space:]]*$//' > .env.prod
# 환경 변수들을 추출하여 마스킹된 형태로 로그 출력
echo "🔍 환경변수 추출 중..."
DATABASE_PASSWORD=$(grep DATABASE_PASSWORD .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
DATABASE_URL=$(grep DATABASE_URL .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
JWT_SECRET=$(grep JWT_SECRET .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
REDIS_URL=$(grep REDIS_URL .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
KAKAO_CLIENT_ID=$(grep KAKAO_CLIENT_ID .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
KAKAO_CLIENT_SECRET=$(grep KAKAO_CLIENT_SECRET .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
GOOGLE_CLIENT_ID=$(grep GOOGLE_CLIENT_ID .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
GOOGLE_CLIENT_SECRET=$(grep GOOGLE_CLIENT_SECRET .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
NAVER_CLIENT_ID=$(grep NAVER_CLIENT_ID .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
NAVER_CLIENT_SECRET=$(grep NAVER_CLIENT_SECRET .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
INITIAL_ADMIN_EMAIL=$(grep INITIAL_ADMIN_EMAIL .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
INITIAL_ADMIN_PASSWORD=$(grep INITIAL_ADMIN_PASSWORD .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
INITIAL_ADMIN_NAME=$(grep INITIAL_ADMIN_NAME .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
EMAIL_HOST=$(grep EMAIL_HOST .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
EMAIL_USER=$(grep EMAIL_USER .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
EMAIL_PASS=$(grep EMAIL_PASS .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
EMAIL_FROM=$(grep EMAIL_FROM .env.prod | cut -d '=' -f2- | tr -d '\r' | sed 's/[[:space:]]*$//')
# METRICS_TOKEN 자동 생성 (64자리 랜덤 문자열)
METRICS_TOKEN=$(openssl rand -hex 32)
# DATABASE_URL 개행/공백 제거 확인 및 로그
echo "🔍 DATABASE_URL 형식 검증:"
echo "원본 DATABASE_URL 길이: ${#DATABASE_URL}"
CLEAN_DATABASE_URL=$(echo "$DATABASE_URL" | tr -d '\r' | sed 's/[[:space:]]*$//')
echo "정리된 DATABASE_URL 길이: ${#CLEAN_DATABASE_URL}"
if [ "$DATABASE_URL" != "$CLEAN_DATABASE_URL" ]; then
echo "⚠️ DATABASE_URL에서 개행/공백이 제거되었습니다"
DATABASE_URL="$CLEAN_DATABASE_URL"
else
echo "✅ DATABASE_URL 형식이 올바릅니다"
fi
# 민감한 정보를 마스킹하여 로그 출력
echo "DATABASE_PASSWORD: ${DATABASE_PASSWORD:0:4}***"
echo "DATABASE_URL: ${DATABASE_URL:0:20}***"
echo "JWT_SECRET: ${JWT_SECRET:0:8}***"
echo "REDIS_URL: ${REDIS_URL:0:20}***"
echo "KAKAO_CLIENT_ID: ${KAKAO_CLIENT_ID:0:10}***"
echo "GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:0:10}***"
echo "NAVER_CLIENT_ID: ${NAVER_CLIENT_ID:0:10}***"
echo "INITIAL_ADMIN_EMAIL: ${INITIAL_ADMIN_EMAIL:0:10}***"
echo "INITIAL_ADMIN_NAME: ${INITIAL_ADMIN_NAME:0:5}***"
echo "METRICS_TOKEN: ${METRICS_TOKEN:0:16}***"
# .env.prod 파일에서 환경변수들을 추출하여 terraform.tfvars 생성
cat > terraform.tfvars << EOF
database_password = "$DATABASE_PASSWORD"
database_url = "$DATABASE_URL"
jwt_secret = "$JWT_SECRET"
redis_url = "$REDIS_URL"
kakao_client_id = "$KAKAO_CLIENT_ID"
kakao_client_secret = "$KAKAO_CLIENT_SECRET"
google_client_id = "$GOOGLE_CLIENT_ID"
google_client_secret = "$GOOGLE_CLIENT_SECRET"
naver_client_id = "$NAVER_CLIENT_ID"
naver_client_secret = "$NAVER_CLIENT_SECRET"
initial_admin_email = "$INITIAL_ADMIN_EMAIL"
initial_admin_password = "$INITIAL_ADMIN_PASSWORD"
initial_admin_name = "$INITIAL_ADMIN_NAME"
metrics_token = "$METRICS_TOKEN"
email_host = "$EMAIL_HOST"
email_user = "$EMAIL_USER"
email_pass = "$EMAIL_PASS"
email_from = "$EMAIL_FROM"
EOF
# 민감한 정보가 포함된 .env.prod 파일 삭제
rm -f .env.prod
echo "✅ ENV_PROD에서 환경변수 추출 완료"
echo "📋 terraform.tfvars 파일이 생성되었습니다."
- name: Terraform Plan
run: terraform plan -no-color -lock=false -var-file=terraform.tfvars
# 실제 배포는 main 브랜치에서만 실행되도록 조건 분기
- name: Terraform Apply
if: github.ref == 'refs/heads/main'
run: terraform apply -auto-approve -lock=false -var-file=terraform.tfvars
- name: Show Terraform Outputs
if: github.ref == 'refs/heads/main'
run: |
echo "🚀 Terraform으로 생성된 리소스들:"
echo "📦 S3 Bucket: mclass-terraform-state-20250731"
echo "🔒 DynamoDB Table: terraform-lock"
echo "🏗️ VPC: $(terraform output -raw vpc_id 2>/dev/null || echo 'N/A')"
echo "🌐 ALB DNS: $(terraform output -raw alb_dns_name 2>/dev/null || echo 'N/A')"
echo "📦 ECR Repository: $(terraform output -raw ecr_repository_url 2>/dev/null || echo 'N/A')"
echo "🔗 RDS Endpoint: $(terraform output -raw rds_endpoint 2>/dev/null || echo 'N/A')"
echo "🔗 ECS Cluster: mclass-cluster"
echo "⚙️ ECS Service: mclass-service"
echo "📋 Task Definition: mclass-task"
echo ""
echo "✅ 모든 인프라가 Terraform으로 관리됩니다!"
# Prometheus 설정은 이미 prometheus.yml에 하드코딩되어 있음
- name: Verify AWS Resources
if: github.ref == 'refs/heads/main'
run: |
echo "🔍 AWS에서 실제 생성된 리소스 확인:"
echo ""
echo "📦 ECR Repository:"
aws ecr describe-repositories --repository-names mclass-server --region ap-northeast-2 --query 'repositories[0].repositoryUri' --output text || echo "❌ ECR Repository not found"
echo ""
echo "🔗 ECS Cluster:"
aws ecs describe-clusters --clusters mclass-cluster --region ap-northeast-2 --query 'clusters[0].clusterName' --output text || echo "❌ ECS Cluster not found"
echo ""
echo "⚙️ ECS Service:"
aws ecs describe-services --cluster mclass-cluster --services mclass-service --region ap-northeast-2 --query 'services[0].serviceName' --output text || echo "❌ ECS Service not found"
echo ""
echo "🌐 ALB:"
aws elbv2 describe-load-balancers --region ap-northeast-2 --query 'LoadBalancers[?contains(LoadBalancerName, `mclass`)].DNSName' --output text || echo "❌ ALB not found"
echo ""
echo "🔍 모니터링 설정 검증:"
echo "📊 Prometheus 설정: prometheus.yml 업데이트됨"
echo "🛡️ ALB 리스너 규칙: VPC 내부 IP 제한 적용됨"
echo "🔒 HTTP: 포트 80으로 간단한 구성"
echo "✅ 간소화된 모니터링 구성 완료!"
echo ""
echo "🔧 ECS 접속 명령어:"
echo "Prometheus 접속: aws ecs execute-command --cluster mclass-cluster --task [TASK_ID] --container prometheus --interactive --command \"/bin/sh\" --region ap-northeast-2"
echo "Grafana 접속: aws ecs execute-command --cluster mclass-cluster --task [TASK_ID] --container grafana --interactive --command \"/bin/sh\" --region ap-northeast-2"
echo "앱 접속: aws ecs execute-command --cluster mclass-cluster --task [TASK_ID] --container mclass-server --interactive --command \"/bin/sh\" --region ap-northeast-2"