Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7b000e2
Merge pull request #55 from YAPP-Github/develop
lvalentine6 Jul 5, 2025
4ce9e64
Merge pull request #128 from YAPP-Github/develop
lvalentine6 Jul 31, 2025
31145cf
Merge pull request #131 from YAPP-Github/develop
lvalentine6 Aug 1, 2025
613c3f0
Merge pull request #160 from YAPP-Github/develop
lvalentine6 Aug 13, 2025
8bd14ea
fix: prod 환경 컨테이너 포트 수정
lvalentine6 Aug 13, 2025
e231deb
fix: 임시적으로 응원 최대 개수를 인 당 10,000개까지 허용
leegwichan Aug 14, 2025
3fd45eb
Merge pull request #162 from YAPP-Github/hotfix/store-limit
leegwichan Aug 14, 2025
4092edf
fix: dev 환경과 동기화
lvalentine6 Aug 19, 2025
539a197
feat: db 마이그레이션을 위한 테스트 환경 구현
lvalentine6 Aug 19, 2025
65a6c5e
feat: 람다 실행을 위한 핸들러 구현
lvalentine6 Aug 19, 2025
27be4f7
feat: flyway 마이그레이션 추가
lvalentine6 Aug 19, 2025
5e4a65d
fix: 마이그레이션 작업을 위한 output 추가
lvalentine6 Aug 19, 2025
c161ee2
fix: 마이그레이션 작업을 위한 라우팅 테이블 output 추가
lvalentine6 Aug 19, 2025
6a6773c
fix: 타입 및 인자 수정
lvalentine6 Aug 19, 2025
3c2ea6a
fix: rds 주소 output 추가
lvalentine6 Aug 20, 2025
bd211b3
feat: rds 복제 확인을 위한 점프 호스트 추가
lvalentine6 Aug 20, 2025
0172dcc
fix: deprecated 된 리전 명령어를 id로 교체
lvalentine6 Aug 20, 2025
ea93542
fix: 복제 인스턴스 사양 변경
lvalentine6 Aug 20, 2025
88c92e2
fix: 마이그레이션 파일명 변경
lvalentine6 Aug 20, 2025
6b4df4a
feat: 마이그레이션 전용 프로파일 추가
lvalentine6 Aug 20, 2025
8a0cffc
feat: 마이그레이션 테스트 실행, 삭제 워크플로 추가
lvalentine6 Aug 20, 2025
e956741
fix: 워크플로에 맞춰 람다 핸들러 수정
lvalentine6 Aug 20, 2025
f25da75
fix(bootstrap): ECR에 테스트 이미지 라이프 사이클 추가
lvalentine6 Aug 20, 2025
379b4e1
fix(migration): 마이그레이션 리소스 수정
lvalentine6 Aug 20, 2025
f4ffef1
fix(migration): 워크플로에서 사용할수 있도록 output 정의
lvalentine6 Aug 20, 2025
fe866d9
fix(migration): IAM 정책, sg 그룹 정의 추가
lvalentine6 Aug 20, 2025
20f90c7
fix(common): ECR에 삭제 정책 정의 추가
lvalentine6 Aug 20, 2025
8c0180f
fix(dev,prod): S3 output 추가
lvalentine6 Aug 20, 2025
bf7ad46
fix: dev가 아닌 prod를 복제하도록 수정
lvalentine6 Aug 20, 2025
13d6bd3
fix: 참조 환경 변경
lvalentine6 Aug 20, 2025
5bbc984
fix: 참조 변수명 수정
lvalentine6 Aug 20, 2025
7f31913
fix: dev 환경과의 충돌을 방지하기 위해 임시 삭제
lvalentine6 Aug 20, 2025
f2675c0
fix: 워크플로 에러 해결
lvalentine6 Aug 20, 2025
3ef42aa
fix: 핸들러 예외 처리 로직 강화
lvalentine6 Aug 20, 2025
0fbaa4e
fix: sg, iam 정책 추가
lvalentine6 Aug 20, 2025
fc14910
fix: 람다 의존성 목록 추가
lvalentine6 Aug 20, 2025
545d270
fix: 핸들러 코드에 order_index 적용
lvalentine6 Aug 20, 2025
05a42b9
fix: 핸들러 이름 수정, 워크플로 수정
lvalentine6 Aug 21, 2025
5cbac91
fix: 워크플로 이름 변경 및 참조 수정
lvalentine6 Aug 21, 2025
d0d6a5d
Merge branch 'develop' into fix/prod-db-migration
lvalentine6 Aug 21, 2025
f647e31
test: prod 환경에 맞게 테스트 비활성화
lvalentine6 Aug 21, 2025
83e1791
fix: 워크플로 결과 알림 추가
lvalentine6 Aug 21, 2025
ba539c7
fix: 커스텀 정책 분리
lvalentine6 Aug 21, 2025
2021c09
fix: sg 참조 수정
lvalentine6 Aug 21, 2025
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
246 changes: 246 additions & 0 deletions .github/workflows/deploy-migration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
name: 'Deploy Migration Test Environment'

on:
workflow_dispatch:
inputs:
branch:
description: '테스트할 브랜치 이름'
required: true
default: 'dev'

permissions:
contents: read

concurrency:
group: terraform-migration
cancel-in-progress: false

env:
AWS_REGION: ap-northeast-2

jobs:
build-lambda-handler:
name: Build Lambda Handler
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.branch }}

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'

- name: Install dependencies and create zip file
run: |
mkdir -p build/lambda-package
pip install -r ./terraform-db-migration/lambda_src/requirements.txt -t ./build/lambda-package
cp ./terraform-db-migration/lambda_src/handler.py ./build/lambda-package/
cd ./build/lambda-package
zip -r ../migration_lambda.zip .

- name: Upload Lambda artifact
uses: actions/upload-artifact@v4
with:
name: lambda-build
path: ./build/migration_lambda.zip

terraform-apply-migration:
name: Terraform Apply MIGRATION
runs-on: ubuntu-latest
needs: build-lambda-handler
outputs:
tf_outputs_json: ${{ steps.get-outputs.outputs.data }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.branch }}

- name: Download Lambda artifact
uses: actions/download-artifact@v5
with:
name: lambda-build
path: ./build

- uses: hashicorp/setup-terraform@v3

- 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: Terraform Init (migration)
run: terraform init
working-directory: ./terraform-db-migration

- name: Terraform Apply MIGRATION
run: terraform apply -auto-approve
working-directory: ./terraform-db-migration

- name: Get Terraform Outputs
id: get-outputs
run: |
echo "data<<EOF" >> $GITHUB_OUTPUT
terraform output -json >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
working-directory: ./terraform-db-migration

build-and-run-migration:
name: Build Image and Run Migration Sequence
runs-on: ubuntu-latest
needs: terraform-apply-migration
steps:
- name: Checkout specific branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.branch }}

- name: Parse Terraform Outputs and Set Env
id: parse-tf
run: |
TF_OUTPUTS='${{ needs.terraform-apply-migration.outputs.tf_outputs_json }}'
echo "ECR_REPOSITORY=$(echo "$TF_OUTPUTS" | jq -r '.ecr_repository_name.value')" >> $GITHUB_ENV
echo "PROD_ECS_CLUSTER_NAME=$(echo "$TF_OUTPUTS" | jq -r '.prod_ecs_cluster_name.value')" >> $GITHUB_ENV
echo "PROD_ECS_SERVICE_NAME=$(echo "$TF_OUTPUTS" | jq -r '.prod_ecs_api_service_name.value')" >> $GITHUB_ENV
echo "LAMBDA_FUNCTION_NAME=$(echo "$TF_OUTPUTS" | jq -r '.migration_lambda_function_name.value')" >> $GITHUB_ENV
echo "VPC_SUBNET=$(echo "$TF_OUTPUTS" | jq -r '.private_subnet_id.value')" >> $GITHUB_ENV
echo "TASK_SECURITY_GROUP=$(echo "$TF_OUTPUTS" | jq -r '.task_security_group_id.value')" >> $GITHUB_ENV
echo "CLONED_RDS_ADDRESS=$(echo "$TF_OUTPUTS" | jq -r '.cloned_rds_address.value')" >> $GITHUB_ENV
echo "CLONED_S3_BUCKET_NAME=$(echo "$TF_OUTPUTS" | jq -r '.cloned_s3_bucket_name.value')" >> $GITHUB_ENV

- 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: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 21
java-package: jdk
architecture: 'x64'
cache: 'gradle'

- name: Get TEST_JWT_SECRET_KEY from SSM
id: get-test-secret
run: |
SECRET_VALUE=$(aws ssm get-parameter --name "/common/TEST_JWT_SECRET_KEY" --with-decryption --query "Parameter.Value" --output text)
echo "TEST_JWT_SECRET_KEY=$SECRET_VALUE" >> $GITHUB_ENV

- name: Build with Gradle
run: |
chmod +x gradlew
./gradlew clean build -Dspring.profiles.active=migration
env:
TEST_JWT_SECRET_KEY: ${{ env.TEST_JWT_SECRET_KEY }}

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2

- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
run: |
IMAGE_TAG="migration-test-$(date +'%Y%m%d-%H%M%S')"
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "image_uri=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT

- name: Get Latest PROD Task Definition Info
id: get-prod-info
run: |
TASK_DEF_ARN=$(aws ecs describe-services --cluster "${{ env.PROD_ECS_CLUSTER_NAME }}" --services "${{ env.PROD_ECS_SERVICE_NAME }}" --query "services[0].taskDefinition" --output text)
CONTAINER_NAME=$(aws ecs describe-task-definition --task-definition "$TASK_DEF_ARN" --query "taskDefinition.containerDefinitions[0].name" --output text)
echo "task_definition_arn=$TASK_DEF_ARN" >> $GITHUB_OUTPUT
echo "container_name=$CONTAINER_NAME" >> $GITHUB_OUTPUT

- name: Create New Task Definition with Updated Image
id: update-task-def
run: |
TASK_DEF=$(aws ecs describe-task-definition --task-definition "${{ steps.get-prod-info.outputs.task_definition_arn }}" --query "taskDefinition")

NEW_TASK_DEF=$(echo "$TASK_DEF" | jq --arg IMAGE "${{ steps.build-image.outputs.image_uri }}" '
.containerDefinitions[0].image = $IMAGE |
del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .placementConstraints, .compatibilities, .registeredAt, .registeredBy)
')

NEW_TASK_DEF_ARN=$(aws ecs register-task-definition --cli-input-json "$NEW_TASK_DEF" --query "taskDefinition.taskDefinitionArn" --output text)
echo "new_task_definition_arn=$NEW_TASK_DEF_ARN" >> $GITHUB_OUTPUT

- name: Invoke Pre-processing Lambda
run: |
META=$(aws lambda invoke \
--function-name "${{ env.LAMBDA_FUNCTION_NAME }}" \
--payload '{"task":"preprocess"}' \
--cli-binary-format raw-in-base64-out \
response.json)
echo "$META" | jq .
echo "$META" | jq -e '.FunctionError == null' >/dev/null || { echo "Preprocess Lambda failed"; exit 1; }

- name: Run DB Migration ECS Task
id: ecs-run-task
run: |
MIGRATION_RDS_URL="jdbc:mysql://${{ env.CLONED_RDS_ADDRESS }}/eatda?useUnicode=true&characterEncoding=UTF-8"
TASK_ARN=$(aws ecs run-task \
--cluster ${{ env.PROD_ECS_CLUSTER_NAME }} \
--task-definition ${{ steps.update-task-def.outputs.new_task_definition_arn }} \
--launch-type EC2 \
--network-configuration "awsvpcConfiguration={subnets=[${{ env.VPC_SUBNET }}],securityGroups=[${{ env.TASK_SECURITY_GROUP }}]}" \
--overrides '{ "containerOverrides": [ { "name": "${{ steps.get-prod-info.outputs.container_name }}", "environment": [ { "name": "SPRING_PROFILES_ACTIVE", "value": "migration" }, { "name": "MIGRATION_RDS_URL", "value": "'"${MIGRATION_RDS_URL}"'" }, { "name": "MIGRATION_S3_BUCKET", "value": "${{ env.CLONED_S3_BUCKET_NAME }}" } ] } ] }' \
--query "tasks[0].taskArn" --output text)
echo "task_arn=$TASK_ARN" >> $GITHUB_OUTPUT
if [ -z "$TASK_ARN" ] || [ "$TASK_ARN" = "None" ]; then
echo "Failed to start ECS task"; exit 1;
fi

- name: Wait for ECS Task to Complete
run: |
aws ecs wait tasks-stopped --cluster ${{ env.PROD_ECS_CLUSTER_NAME }} --tasks ${{ steps.ecs-run-task.outputs.task_arn }}

- name: Invoke Post-processing Lambda
run: |
aws lambda invoke --function-name ${{ env.LAMBDA_FUNCTION_NAME }} --payload '{"task": "postprocess"}' response.json

notify:
name: Send Discord Notification (Migration)
runs-on: ubuntu-latest
needs: build-and-run-migration
if: always()
steps:
- name: Prepare Notification Info
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT

- name: Discord Notify (Success)
if: needs.build-and-run-migration.result == 'success'
uses: tsickert/[email protected]
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK }}
embed-title: "✅ Migration Test 배포 성공!"
embed-color: 65280
embed-description: |
마이그레이션 테스트 환경이 성공적으로 구축되었습니다.
**커밋**: [${{ steps.vars.outputs.sha_short }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }})
**실행자**: ${{ github.actor }}
embed-url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"

- name: Discord Notify (Failure)
if: needs.build-and-run-migration.result != 'success'
uses: tsickert/[email protected]
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK }}
embed-title: "❌ Migration Test 배포 실패!"
embed-color: 16711680
embed-description: |
마이그레이션 테스트 환경 구축중 오류가 발생했습니다.
**커밋**: [${{ steps.vars.outputs.sha_short }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }})
**실행자**: ${{ github.actor }}
embed-url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
46 changes: 46 additions & 0 deletions .github/workflows/destroy-migration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: 'Destroy Migration Test Environment'

on:
workflow_dispatch:
inputs:
branch:
description: '리소스를 생성했던 브랜치 이름'
required: true
default: 'dev'

permissions:
contents: read

concurrency:
group: terraform-migration-destroy
cancel-in-progress: false

env:
AWS_REGION: ap-northeast-2

jobs:
terraform-destroy-migration:
name: Terraform Destroy MIGRATION
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.event.inputs.branch }}

- uses: hashicorp/setup-terraform@v3

- 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_KEY_ID }}
aws-region: ${{ env.AWS_REGION }}

- name: Terraform Init (migration)
run: terraform init
working-directory: ./terraform-db-migration

- name: Terraform Destroy MIGRATION
run: terraform destroy -auto-approve
working-directory: ./terraform-db-migration
2 changes: 1 addition & 1 deletion src/main/java/eatda/service/cheer/CheerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
@RequiredArgsConstructor
public class CheerService {

private static final int MAX_CHEER_SIZE = 3;
private static final int MAX_CHEER_SIZE = 10_000;

private final MemberRepository memberRepository;
private final StoreRepository storeRepository;
Expand Down
56 changes: 56 additions & 0 deletions src/main/resources/application-migration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
logging:
level:
org.hibernate.SQL: INFO

spring:
cloud:
aws:
region:
static: ap-northeast-2
s3:
bucket: ${MIGRATION_S3_BUCKET}

servlet:
multipart:
max-file-size: 5MB
max-request-size: 10MB

config:
import: "aws-parameterstore:/prod/"

datasource:
url: ${MIGRATION_RDS_URL}
username: ${MYSQL_USER_NAME}
password: ${MYSQL_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver

jpa:
hibernate:
ddl-auto: validate

flyway:
enabled: true
baseline-on-migrate: false
locations:
- classpath:db/migration
- classpath:db/seed/prod

jwt:
access-token-expiration: 1h
refresh-token-expiration: 14d
secret-key: ${JWT_SECRET_KEY}

cors:
origin:
- "https://www.eatda.net"
- "https://eatda.net"

oauth:
client-id: ${OAUTH_CLIENT_ID}
redirect-path: /login/callback
allowed-origins:
- "https://www.eatda.net"
- "https://eatda.net"

kakao:
api-key: ${KAKAO_API_KEY}
2 changes: 2 additions & 0 deletions src/test/java/eatda/service/cheer/CheerServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -38,6 +39,7 @@ class CheerServiceTest extends BaseServiceTest {
class RegisterCheer {

@Test
@Disabled("현재 한시적으로 MAX_CHEER_SIZE=10000 으로 운영 중")
void 응원_개수가_최대_개수를_초과하면_예외가_발생한다() {
Member member = memberGenerator.generate("123");
Store store1 = storeGenerator.generate("124", "서울시 강남구 역삼동 123-45");
Expand Down
20 changes: 20 additions & 0 deletions terraform-bootstrap/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
locals {
default_ecr_lifecycle_policy = jsonencode({
rules = [
{
rulePriority = 1,
description = "7일이 지난 마이그레이션 테스트용 임시 이미지 자동 삭제",
selection = {
tagStatus = "tagged",
tagPrefixList = ["migration-test-"],
countType = "sinceImagePushed",
countUnit = "days",
countNumber = 7
},
action = {
type = "expire"
}
}
]
})
}
Loading