Skip to content

Commit b9e4589

Browse files
authored
setting: AWS 계정 이관 및 deploy.sh → Docker Compose 전환, Nginx HTTPS 적용 (#57)
1 parent d902492 commit b9e4589

9 files changed

Lines changed: 204 additions & 72 deletions

File tree

.github/workflows/cicd-release.yml

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ on:
55
types:
66
- published
77

8+
env:
9+
AWS_REGION: ap-northeast-2
10+
ECR_REGISTRY: 909176971481.dkr.ecr.ap-northeast-2.amazonaws.com
11+
ECR_REPOSITORY: linktrip
12+
813
jobs:
9-
build-and-push:
14+
build-and-deploy:
1015
runs-on: ubuntu-latest
1116

1217
steps:
@@ -29,37 +34,98 @@ jobs:
2934
restore-keys: |
3035
${{ runner.os }}-gradle-
3136
37+
- name: JAR 빌드
38+
run: ./gradlew :linktrip-bootstrap:bootJar
39+
3240
- name: AWS 자격 증명 설정
3341
uses: aws-actions/configure-aws-credentials@v4
3442
with:
3543
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
3644
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
37-
aws-region: ap-northeast-2
45+
aws-region: ${{ env.AWS_REGION }}
3846

3947
- name: ECR 로그인
4048
id: ecr-login
4149
uses: aws-actions/amazon-ecr-login@v2
4250

43-
- name: ECR 비밀번호 발급
44-
id: ecr-password
45-
run: echo "password=$(aws ecr get-login-password --region ap-northeast-2)" >> $GITHUB_OUTPUT
51+
- name: Docker 이미지 빌드 및 푸시
52+
run: |
53+
docker build -t ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest .
54+
docker push ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest
4655
47-
- name: 이미지 빌드 및 푸쉬
56+
- name: GCP credentials 파일 생성
4857
env:
49-
ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }}
50-
ECR_REPOSITORY: linktrip
51-
ECR_PASSWORD: ${{ steps.ecr-password.outputs.password }}
52-
run: |
53-
./gradlew :linktrip-bootstrap:bootBuildImage
58+
GCP_CREDENTIALS_JSON: ${{ secrets.GCP_CREDENTIALS_JSON }}
59+
run: echo "$GCP_CREDENTIALS_JSON" > gcp-credentials.json
5460

55-
- name: 서버 재시작 스크립트 실행
61+
- name: 배포 파일 EC2에 전송
62+
uses: appleboy/scp-action@master
63+
with:
64+
host: ${{ secrets.SERVER_HOST }}
65+
username: ec2-user
66+
key: ${{ secrets.SERVER_KEY }}
67+
source: "docker/docker-compose.prod.yml,gcp-credentials.json"
68+
target: "~/linktrip/"
69+
strip_components: 0
70+
overwrite: true
71+
72+
- name: EC2 파일 정리 및 배포
5673
uses: appleboy/ssh-action@master
74+
env:
75+
JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }}
76+
DISCORD_WEBHOOK_ERROR_URL: ${{ secrets.DISCORD_WEBHOOK_ERROR_URL }}
77+
DISCORD_MENTION_USER_ID: ${{ secrets.DISCORD_MENTION_USER_ID }}
78+
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
79+
YOUTUBE_API_KEY: ${{ secrets.YOUTUBE_API_KEY }}
5780
with:
5881
host: ${{ secrets.SERVER_HOST }}
59-
username: ubuntu
82+
username: ec2-user
6083
key: ${{ secrets.SERVER_KEY }}
84+
envs: JWT_SECRET_KEY,DISCORD_WEBHOOK_ERROR_URL,DISCORD_MENTION_USER_ID,GCP_PROJECT_ID,YOUTUBE_API_KEY
6185
script: |
62-
./deploy.sh
86+
set -e
87+
88+
DEPLOY_DIR=~/linktrip
89+
90+
# Docker Compose 플러그인 설치 (없으면)
91+
if ! docker compose version > /dev/null 2>&1; then
92+
sudo mkdir -p /usr/local/lib/docker/cli-plugins
93+
sudo curl -SL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-$(uname -m) -o /usr/local/lib/docker/cli-plugins/docker-compose
94+
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
95+
fi
96+
97+
# ECR 로그인
98+
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 909176971481.dkr.ecr.ap-northeast-2.amazonaws.com
99+
100+
# SCP로 전송된 파일 정리 (strip_components=0이라 docker/ 폴더 안에 들어감)
101+
mkdir -p $DEPLOY_DIR
102+
mv -f $DEPLOY_DIR/docker/docker-compose.prod.yml $DEPLOY_DIR/docker-compose.prod.yml 2>/dev/null || true
103+
rmdir $DEPLOY_DIR/docker 2>/dev/null || true
104+
chmod 600 $DEPLOY_DIR/gcp-credentials.json
105+
106+
# .env 파일 생성
107+
echo "JWT_SECRET_KEY=${JWT_SECRET_KEY}" > $DEPLOY_DIR/.env
108+
echo "DISCORD_WEBHOOK_ERROR_URL=${DISCORD_WEBHOOK_ERROR_URL}" >> $DEPLOY_DIR/.env
109+
echo "DISCORD_MENTION_USER_ID=${DISCORD_MENTION_USER_ID}" >> $DEPLOY_DIR/.env
110+
echo "GCP_PROJECT_ID=${GCP_PROJECT_ID}" >> $DEPLOY_DIR/.env
111+
echo "YOUTUBE_API_KEY=${YOUTUBE_API_KEY}" >> $DEPLOY_DIR/.env
112+
chmod 600 $DEPLOY_DIR/.env
113+
114+
# 네트워크 생성 (없으면)
115+
docker network create linktrip-network 2>/dev/null || true
116+
117+
# 기존 컨테이너 정리 (docker run으로 만든 잔여 컨테이너)
118+
docker stop linktrip-app 2>/dev/null || true
119+
docker rm linktrip-app 2>/dev/null || true
120+
121+
# docker-compose 배포
122+
cd $DEPLOY_DIR
123+
docker compose -f docker-compose.prod.yml pull app
124+
docker compose -f docker-compose.prod.yml up -d --force-recreate
125+
docker image prune -f
126+
127+
echo ">>> 배포 완료"
128+
docker compose -f docker-compose.prod.yml ps
63129
64130
- name: 디스코드 배포 알림
65131
if: success()

Dockerfile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
FROM eclipse-temurin:21-jre-alpine
2+
3+
WORKDIR /app
4+
5+
COPY linktrip-bootstrap/build/libs/*.jar app.jar
6+
7+
ENV JAVA_OPTS="-XX:+UseG1GC \
8+
-XX:+UseContainerSupport \
9+
-Xms256m -Xmx384m \
10+
-XX:ReservedCodeCacheSize=128m \
11+
-XX:MaxMetaspaceSize=128m \
12+
-XX:+HeapDumpOnOutOfMemoryError \
13+
-XX:+ExitOnOutOfMemoryError \
14+
-XX:+UseStringDeduplication \
15+
-Dfile.encoding=UTF-8"
16+
17+
EXPOSE 8080
18+
19+
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

deploy.sh

Lines changed: 0 additions & 36 deletions
This file was deleted.
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@ services:
1212
--collation-server=utf8mb4_0900_ai_ci
1313
--default-time-zone=+09:00
1414
volumes:
15-
- ./mysql/data:/var/lib/mysql
15+
- mysql-data:/var/lib/mysql
1616
ports:
1717
- "3306:3306"
1818
networks:
1919
- linktrip-network
2020

21+
volumes:
22+
mysql-data:
23+
2124
networks:
2225
linktrip-network:
2326
name: linktrip-network

docker/docker-compose.nginx.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
services:
2+
nginx:
3+
image: nginx:alpine
4+
container_name: linktrip-nginx
5+
restart: unless-stopped
6+
ports:
7+
- "80:80"
8+
- "443:443"
9+
volumes:
10+
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
11+
- certbot-etc:/etc/letsencrypt:ro
12+
- certbot-var:/var/www/certbot:ro
13+
networks:
14+
- linktrip-network
15+
16+
certbot:
17+
image: certbot/certbot
18+
container_name: linktrip-certbot
19+
volumes:
20+
- certbot-etc:/etc/letsencrypt
21+
- certbot-var:/var/www/certbot
22+
23+
volumes:
24+
certbot-etc:
25+
certbot-var:
26+
27+
networks:
28+
linktrip-network:
29+
name: linktrip-network
30+
external: true

docker/docker-compose.prod.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
services:
2+
app:
3+
image: 909176971481.dkr.ecr.ap-northeast-2.amazonaws.com/linktrip:latest
4+
container_name: linktrip-app
5+
restart: unless-stopped
6+
expose:
7+
- "8080"
8+
mem_limit: 1280m
9+
environment:
10+
- SPRING_PROFILES_ACTIVE=prod
11+
- TZ=Asia/Seoul
12+
- JWT_SECRET_KEY=${JWT_SECRET_KEY}
13+
- JWT_EXPIRATION_MS=${JWT_EXPIRATION_MS:-86400000}
14+
- DISCORD_WEBHOOK_ERROR_URL=${DISCORD_WEBHOOK_ERROR_URL}
15+
- DISCORD_MENTION_USER_ID=${DISCORD_MENTION_USER_ID}
16+
- GCP_PROJECT_ID=${GCP_PROJECT_ID}
17+
- GCP_CREDENTIALS_PATH=/app/config/gcp-credentials.json
18+
- GCP_VERTEX_AI_LOCATION=us-central1
19+
- YOUTUBE_API_KEY=${YOUTUBE_API_KEY}
20+
volumes:
21+
- ./gcp-credentials.json:/app/config/gcp-credentials.json:ro
22+
- /etc/localtime:/etc/localtime:ro
23+
networks:
24+
- linktrip-network
25+
26+
networks:
27+
linktrip-network:
28+
name: linktrip-network
29+
external: true

docker/nginx/nginx-init.conf

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
server {
2+
listen 80;
3+
server_name linktrip.cloud;
4+
5+
location /.well-known/acme-challenge/ {
6+
root /var/www/certbot;
7+
}
8+
9+
location / {
10+
return 200 'certbot challenge ready';
11+
add_header Content-Type text/plain;
12+
}
13+
}

docker/nginx/nginx.conf

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
server {
2+
listen 80;
3+
server_name linktrip.cloud;
4+
5+
location /.well-known/acme-challenge/ {
6+
root /var/www/certbot;
7+
}
8+
9+
location / {
10+
return 301 https://$host$request_uri;
11+
}
12+
}
13+
14+
server {
15+
listen 443 ssl;
16+
server_name linktrip.cloud;
17+
18+
ssl_certificate /etc/letsencrypt/live/linktrip.cloud/fullchain.pem;
19+
ssl_certificate_key /etc/letsencrypt/live/linktrip.cloud/privkey.pem;
20+
21+
location / {
22+
proxy_pass http://linktrip-app:8080;
23+
proxy_set_header Host $host;
24+
proxy_set_header X-Real-IP $remote_addr;
25+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
26+
proxy_set_header X-Forwarded-Proto $scheme;
27+
}
28+
}

linktrip-bootstrap/build.gradle.kts

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,32 +29,12 @@ tasks {
2929
}
3030

3131
getByName<org.springframework.boot.gradle.tasks.bundling.BootBuildImage>("bootBuildImage") {
32-
imageName.set("${System.getenv("ECR_REGISTRY")}/${System.getenv("ECR_REPOSITORY")}")
32+
imageName.set("${System.getenv("ECR_REGISTRY") ?: "linktrip"}/${System.getenv("ECR_REPOSITORY") ?: "linktrip"}")
3333
environment.set(
3434
mapOf(
3535
"BP_JVM_VERSION" to "21",
36-
"BPE_SPRING_PROFILES_ACTIVE" to "prod",
37-
"BPE_JAVA_TOOL_OPTIONS" to
38-
buildString {
39-
append("-XX:+UseG1GC ")
40-
append("-XX:+UseContainerSupport ")
41-
append("-Xms512m -Xmx512m ")
42-
append("-XX:+HeapDumpOnOutOfMemoryError ")
43-
append("-XX:HeapDumpPath=/root/heapDump/%Y%m%d_%H%M%S.hprof ")
44-
append("-XX:+UseStringDeduplication ")
45-
append("-XX:+ExitOnOutOfMemoryError ")
46-
append("-Dfile.encoding=UTF-8")
47-
},
4836
),
4937
)
50-
docker {
51-
publishRegistry {
52-
url.set(System.getenv("ECR_REGISTRY"))
53-
username.set("AWS")
54-
password.set(System.getenv("ECR_PASSWORD") ?: "")
55-
}
56-
}
57-
publish.set(true)
5838
}
5939
}
6040

0 commit comments

Comments
 (0)