Skip to content

Commit cb29c2c

Browse files
infra: terraform 환경 구축
* infra: terraform 환경 구축 * gitignore * gitignore * chore: ignore secrets.tf * infra: deploy.yml & backend 조금 수정 * fix: profile 변경 * infra: deploy.yml * infra: deploy.yml
1 parent b9e73b3 commit cb29c2c

6 files changed

Lines changed: 652 additions & 9 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
name: deploy
2+
env:
3+
IMAGE_NAME: waitfair-backend
4+
5+
on:
6+
push:
7+
paths:
8+
- ".github/workflows/**"
9+
- "backend/src/**"
10+
- "backend/build.gradle.kts"
11+
- "backend/Dockerfile"
12+
branches:
13+
- main
14+
15+
# 권한 최소화/명시화
16+
permissions:
17+
contents: write # 태그/릴리즈
18+
packages: write # GHCR 푸시
19+
20+
jobs:
21+
makeTagAndRelease:
22+
runs-on: ubuntu-latest
23+
outputs:
24+
tag_name: ${{ steps.create_tag.outputs.new_tag }}
25+
steps:
26+
- uses: actions/checkout@v4
27+
- name: Create Tag
28+
id: create_tag
29+
uses: mathieudutour/github-tag-action@v6.2
30+
with:
31+
github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
32+
- name: Create Release
33+
id: create_release
34+
uses: actions/create-release@v1
35+
env:
36+
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
37+
with:
38+
tag_name: ${{ steps.create_tag.outputs.new_tag }}
39+
release_name: Release ${{ steps.create_tag.outputs.new_tag }}
40+
body: ${{ steps.create_tag.outputs.changelog }}
41+
draft: false
42+
prerelease: false
43+
44+
buildImageAndPush:
45+
name: 도커 이미지 빌드와 푸시
46+
needs: makeTagAndRelease
47+
defaults:
48+
run:
49+
working-directory: backend # 원하는 디렉토리
50+
runs-on: ubuntu-latest
51+
outputs:
52+
owner_lc: ${{ steps.export_owner.outputs.owner_lc }}
53+
image_name: ${{ steps.export_image.outputs.image_name }}
54+
steps:
55+
- uses: actions/checkout@v4
56+
57+
#환경 변수
58+
#도플러 변경 예정
59+
- name: application-secret 추가
60+
env:
61+
ACTIONS_STEP_DEBUG: true
62+
APPLICATION_SECRET: ${{ secrets.APPLICATION_SECRET }}
63+
run: echo "$APPLICATION_SECRET" > src/main/resources/application-secret.yml
64+
65+
- name: Docker Buildx 설치
66+
uses: docker/setup-buildx-action@v2
67+
68+
- name: 레지스트리 로그인
69+
uses: docker/login-action@v2
70+
with:
71+
registry: ghcr.io
72+
username: ${{ github.actor }}
73+
password: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
74+
75+
- name: set lower case owner name
76+
id: export_owner
77+
run: |
78+
OWNER_LC="${GITHUB_REPOSITORY_OWNER,,}"
79+
echo "owner_lc=$OWNER_LC" >> $GITHUB_OUTPUT
80+
81+
- name: export image name
82+
id: export_image
83+
run: echo "image_name=app251127" >> $GITHUB_OUTPUT
84+
85+
- name: 빌드 앤 푸시
86+
uses: docker/build-push-action@v3
87+
with:
88+
context: ./backend
89+
push: true
90+
cache-from: type=registry,ref=ghcr.io/${{ steps.export_owner.outputs.owner_lc }}/${{ steps.export_image.outputs.image_name }}:cache
91+
cache-to: type=registry,ref=ghcr.io/${{ steps.export_owner.outputs.owner_lc }}/${{ steps.export_image.outputs.image_name }}:cache,mode=max
92+
tags: |
93+
ghcr.io/${{ steps.export_owner.outputs.owner_lc }}/${{ steps.export_image.outputs.image_name }}:${{ needs.makeTagAndRelease.outputs.tag_name }},
94+
ghcr.io/${{ steps.export_owner.outputs.owner_lc }}/${{ steps.export_image.outputs.image_name }}:latest
95+
96+
deploy:
97+
runs-on: ubuntu-latest
98+
needs: [buildImageAndPush]
99+
steps:
100+
- uses: aws-actions/configure-aws-credentials@v4
101+
with:
102+
aws-region: ${{ secrets.AWS_REGION }}
103+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
104+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
105+
106+
- name: 인스턴스 ID 가져오기
107+
id: get_instance_id
108+
run: |
109+
INSTANCE_ID=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=dev-ec2-1" "Name=instance-state-name,Values=running" --query "Reservations[].Instances[].InstanceId" --output text)
110+
echo "INSTANCE_ID=$INSTANCE_ID" >> $GITHUB_ENV
111+
echo $INSTANCE_ID
112+
113+
- name: AWS SSM Send-Command
114+
uses: peterkimzz/aws-ssm-send-command@master
115+
id: ssm
116+
with:
117+
aws-region: ${{ secrets.AWS_REGION }}
118+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
119+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
120+
instance-ids: ${{ env.INSTANCE_ID }}
121+
working-directory: /
122+
comment: Deploy
123+
command: |
124+
125+
# 공통 변수
126+
IMAGE="ghcr.io/${{ needs.buildImageAndPush.outputs.owner_lc }}/${{ needs.buildImageAndPush.outputs.image_name }}:latest"
127+
NETWORK="common"
128+
HEALTH_ENDPOINT="/actuator/health"
129+
TIMEOUT=60
130+
131+
# 현재 실행 중인 컨테이너 확인
132+
if docker ps --format '{{.Names}}' | grep -q "app1_1"; then
133+
CURRENT="app1_1"
134+
NEXT="app1_2"
135+
CURRENT_PORT=8080
136+
NEXT_PORT=8081
137+
else
138+
CURRENT="app1_2"
139+
NEXT="app1_1"
140+
CURRENT_PORT=8081
141+
NEXT_PORT=8080
142+
fi
143+
144+
# 다음 컨테이너 실행
145+
echo "Starting new container: $NEXT on port $NEXT_PORT..."
146+
docker pull "$IMAGE"
147+
docker stop "$NEXT" 2>/dev/null
148+
docker rm "$NEXT" 2>/dev/null
149+
docker run -d \
150+
--network $NETWORK \
151+
--name "$NEXT" \
152+
-p "$NEXT_PORT":8080 \
153+
"$IMAGE"
154+
155+
# 헬스체크 대기
156+
echo "Waiting for health check..."
157+
START_TIME=$(date +%s)
158+
while true; do
159+
CONTENT=$(curl -s http://localhost:$NEXT_PORT$HEALTH_ENDPOINT)
160+
161+
if [[ "$CONTENT" == *'"status":"UP"'* ]]; then
162+
echo "✅ $NEXT is UP!"
163+
break
164+
fi
165+
166+
ELAPSED_TIME=$(( $(date +%s) - START_TIME ))
167+
if [[ $ELAPSED_TIME -ge $TIMEOUT ]]; then
168+
echo "❌ Timeout: $NEXT did not start in $TIMEOUT seconds."
169+
docker stop "$NEXT"
170+
docker rm "$NEXT"
171+
exit 1
172+
fi
173+
174+
echo "⏳ Waiting for $NEXT to be UP..."
175+
sleep 5
176+
done
177+
178+
# 기존 컨테이너 중지 및 제거
179+
echo "Stopping old container: $CURRENT"
180+
docker stop "$CURRENT" 2>/dev/null
181+
docker rm "$CURRENT" 2>/dev/null
182+
183+
# dangling image 제거
184+
docker image prune -f
185+
186+
echo "✅ Deployment complete. Running container: $NEXT on port $NEXT_PORT"

backend/Dockerfile

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,53 @@
22
FROM gradle:8.10.0-jdk21 AS builder
33
WORKDIR /app
44

5-
# 프로젝트 전체 복사 (컨텍스트: backend/)
6-
COPY . .
5+
# Gradle 설정 파일 먼저 복사 (캐시 최적화)
6+
COPY build.gradle.kts settings.gradle.kts ./
7+
COPY gradle gradle
8+
COPY gradlew .
9+
RUN chmod +x gradlew
710

8-
# Gradle Wrapper 실행 권한 부여 후 빌드
9-
RUN chmod +x gradlew \
10-
&& ./gradlew clean bootJar --no-daemon
11+
# 의존성 캐시
12+
RUN ./gradlew dependencies --no-daemon
1113

12-
# 2단계: 실행만 하는 가벼운 JRE 이미지
14+
# 소스 코드 복사
15+
COPY src src
16+
17+
# Spring Boot 실행용 JAR 생성
18+
RUN ./gradlew bootJar --no-daemon -x test
19+
20+
# 두 번째 스테이지: 실행만 하는 가벼운 JRE 이미지
1321
FROM eclipse-temurin:21-jre
1422
WORKDIR /app
1523

16-
# 빌드 결과 JAR 복사 (libs 안에 하나만 있다고 가정)
24+
# 첫 번째 스테이지에서 빌드된 JAR 파일 복사
1725
COPY --from=builder /app/build/libs/*.jar app.jar
1826

1927
EXPOSE 8080
20-
ENTRYPOINT ["java", "-jar", "app.jar"]
28+
# 실행할 JAR 파일 지정
29+
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prod", "app.jar"]
30+
31+
32+
33+
34+
35+
## 1단계: Gradle로 Spring Boot JAR 빌드
36+
#FROM gradle:8.10.0-jdk21 AS builder
37+
#WORKDIR /app
38+
#
39+
## 프로젝트 전체 복사 (컨텍스트: backend/)
40+
#COPY . .
41+
#
42+
## Gradle Wrapper 실행 권한 부여 후 빌드
43+
#RUN chmod +x gradlew \
44+
# && ./gradlew clean bootJar --no-daemon
45+
#
46+
## 2단계: 실행만 하는 가벼운 JRE 이미지
47+
#FROM eclipse-temurin:21-jre
48+
#WORKDIR /app
49+
#
50+
## 빌드 결과 JAR 복사 (libs 안에 하나만 있다고 가정)
51+
#COPY --from=builder /app/build/libs/*.jar app.jar
52+
#
53+
#EXPOSE 8080
54+
#ENTRYPOINT ["java", "-jar", "app.jar"]

backend/src/main/java/com/back/global/properties/SiteProperties.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@
1111
@Component
1212
@ConfigurationProperties(prefix = "custom.site")
1313
public class SiteProperties {
14+
private String domain;
15+
private String backUrl;
1416
private String frontUrl;
1517
}

infra/.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
local/.env
2-
.idea
2+
.idea
3+
.terraform
4+
terraform.tfstate
5+
.terraform.lock.hcl
6+
terraform.tfstate.backup
7+
secrets.tf

0 commit comments

Comments
 (0)