Skip to content

Commit 017b09b

Browse files
authored
Merge pull request #26 from MaxedOut-Muneo/feat/#25
[feat] prod 환경 분리
2 parents 0c174a2 + 6c5a142 commit 017b09b

6 files changed

Lines changed: 231 additions & 2 deletions

File tree

.github/workflows/cd-prod.yaml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: CD PROD
2+
3+
on:
4+
push:
5+
branches:
6+
- prod
7+
workflow_dispatch:
8+
9+
jobs:
10+
deploy-prod:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Docker Buildx
18+
uses: docker/setup-buildx-action@v3
19+
20+
- name: Login to Docker Hub
21+
uses: docker/login-action@v3
22+
with:
23+
username: ${{ secrets.DOCKERHUB_USERNAME }}
24+
password: ${{ secrets.DOCKERHUB_TOKEN }}
25+
26+
- name: Extract Docker metadata
27+
id: meta
28+
uses: docker/metadata-action@v5
29+
with:
30+
images: dykkim/muneo
31+
tags: |
32+
type=raw,value=prod-latest
33+
type=sha,format=short,prefix=prod-
34+
35+
- name: Build and push image
36+
uses: docker/build-push-action@v6
37+
with:
38+
context: .
39+
file: ./Dockerfile
40+
push: true
41+
tags: ${{ steps.meta.outputs.tags }}
42+
labels: ${{ steps.meta.outputs.labels }}
43+
cache-from: type=gha
44+
cache-to: type=gha,mode=max
45+
46+
- name: Copy prod deploy files to EC2
47+
uses: appleboy/scp-action@v0.1.7
48+
with:
49+
host: ${{ secrets.EC2_HOST }}
50+
username: ${{ secrets.EC2_USERNAME }}
51+
key: ${{ secrets.EC2_SSH_KEY }}
52+
port: ${{ secrets.EC2_PORT }}
53+
source: "docker-compose.prod.yml,nginx/conf.d/prod.conf"
54+
target: ${{ secrets.EC2_DEPLOY_PATH_PROD }}
55+
strip_components: 0
56+
overwrite: true
57+
58+
- name: Deploy prod stack on EC2
59+
uses: appleboy/ssh-action@v1.0.3
60+
env:
61+
DEPLOY_PATH: ${{ secrets.EC2_DEPLOY_PATH }}
62+
DEPLOY_PATH_PROD: ${{ secrets.EC2_DEPLOY_PATH_PROD }}
63+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
64+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
65+
DOCKERHUB_IMAGE: dykkim/muneo
66+
PROD_APP_ENV: ${{ secrets.PROD_APP_ENV }}
67+
with:
68+
host: ${{ secrets.EC2_HOST }}
69+
username: ${{ secrets.EC2_USERNAME }}
70+
key: ${{ secrets.EC2_SSH_KEY }}
71+
port: ${{ secrets.EC2_PORT }}
72+
envs: DEPLOY_PATH,DEPLOY_PATH_PROD,DOCKERHUB_USERNAME,DOCKERHUB_TOKEN,DOCKERHUB_IMAGE,PROD_APP_ENV
73+
script_stop: true
74+
script: |
75+
set -e
76+
77+
sudo systemctl enable --now docker || true
78+
79+
mkdir -p "${DEPLOY_PATH_PROD}"
80+
cd "${DEPLOY_PATH_PROD}"
81+
mkdir -p nginx/conf.d
82+
83+
printf "%s" "${PROD_APP_ENV}" > .env
84+
{
85+
echo ""
86+
echo "DOCKERHUB_IMAGE=${DOCKERHUB_IMAGE}"
87+
echo "IMAGE_TAG=prod-latest"
88+
} >> .env
89+
90+
echo "${DOCKERHUB_TOKEN}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin
91+
92+
docker compose -f docker-compose.prod.yml pull app-prod redis-prod
93+
docker compose -f docker-compose.prod.yml up -d --remove-orphans app-prod redis-prod
94+
95+
# Keep one shared nginx stack (dev path), and update only its prod server block.
96+
mkdir -p "${DEPLOY_PATH}/nginx/conf.d"
97+
cp -f "${DEPLOY_PATH_PROD}/nginx/conf.d/prod.conf" "${DEPLOY_PATH}/nginx/conf.d/prod.conf"
98+
99+
cd "${DEPLOY_PATH}"
100+
docker compose exec -T nginx nginx -t
101+
docker compose exec -T nginx nginx -s reload
102+
docker compose exec -T nginx sh -c "grep -n 'api-prod.muneo.ai.kr\\|risk-detector\\|proxy_read_timeout\\|proxy_request_buffering' /etc/nginx/conf.d/prod.conf || true"
103+
104+
docker image prune -f

.github/workflows/cd.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
username: ${{ secrets.EC2_USERNAME }}
5151
key: ${{ secrets.EC2_SSH_KEY }}
5252
port: ${{ secrets.EC2_PORT }}
53-
source: "docker-compose.yml,nginx/conf.d/default.conf"
53+
source: "docker-compose.yml,nginx/conf.d/default.conf,nginx/conf.d/prod.conf"
5454
target: ${{ secrets.EC2_DEPLOY_PATH }}
5555
strip_components: 0
5656
overwrite: true

docker-compose.prod.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
services:
2+
app-prod:
3+
image: ${DOCKERHUB_IMAGE:-dykkim/muneo}:${IMAGE_TAG:-latest}
4+
container_name: muneo-app-prod
5+
restart: unless-stopped
6+
expose:
7+
- "8080"
8+
environment:
9+
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE}
10+
SERVER_PORT: ${SERVER_PORT:-8080}
11+
SERVER_FORWARD_HEADERS_STRATEGY: framework
12+
REDIS_HOST: redis-prod
13+
REDIS_PORT: 6379
14+
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis1234}
15+
JWT_SECRET: ${JWT_SECRET}
16+
JWT_ACCESS_TOKEN_EXPIRATION: ${JWT_ACCESS_TOKEN_EXPIRATION:-3600}
17+
JWT_REFRESH_TOKEN_EXPIRATION: ${JWT_REFRESH_TOKEN_EXPIRATION:-1209600}
18+
AI_API_BASE_URL: ${AI_API_BASE_URL}
19+
AI_API_CONNECT_TIMEOUT_MS: ${AI_API_CONNECT_TIMEOUT_MS:-5000}
20+
AI_API_READ_TIMEOUT_MS: ${AI_API_READ_TIMEOUT_MS:-120000}
21+
KAKAO_CLIENT_ID: ${KAKAO_CLIENT_ID}
22+
KAKAO_CLIENT_SECRET: ${KAKAO_CLIENT_SECRET}
23+
OAUTH_FRONTEND_SUCCESS_URI: ${OAUTH_FRONTEND_SUCCESS_URI}
24+
OAUTH_FRONTEND_SIGNUP_URI: ${OAUTH_FRONTEND_SIGNUP_URI}
25+
OAUTH_FRONTEND_FAILURE_URI: ${OAUTH_FRONTEND_FAILURE_URI}
26+
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS}
27+
COOKIE_SAME_SITE: ${COOKIE_SAME_SITE:-Lax}
28+
COOKIE_DOMAIN: ${COOKIE_DOMAIN:-}
29+
COOKIE_SECURE: ${COOKIE_SECURE}
30+
EMAIL_FEATURE_ENABLED: ${EMAIL_FEATURE_ENABLED:-false}
31+
PROD_DB_URL: ${PROD_DB_URL}
32+
PROD_DB_USERNAME: ${PROD_DB_USERNAME}
33+
PROD_DB_PASSWORD: ${PROD_DB_PASSWORD}
34+
DDL_AUTO: ${DDL_AUTO:-validate}
35+
depends_on:
36+
redis-prod:
37+
condition: service_healthy
38+
networks:
39+
- muneo-shared-net
40+
- muneo-prod-net
41+
42+
redis-prod:
43+
image: redis:7-alpine
44+
container_name: muneo-redis-prod
45+
restart: unless-stopped
46+
command: >
47+
sh -c "redis-server --appendonly yes
48+
--requirepass '${REDIS_PASSWORD:-redis1234}'"
49+
volumes:
50+
- redis-prod-data:/data
51+
healthcheck:
52+
test: ["CMD-SHELL", "redis-cli -a '${REDIS_PASSWORD:-redis1234}' ping | grep PONG"]
53+
interval: 10s
54+
timeout: 3s
55+
retries: 5
56+
start_period: 5s
57+
networks:
58+
- muneo-prod-net
59+
60+
volumes:
61+
redis-prod-data:
62+
63+
networks:
64+
muneo-shared-net:
65+
external: true
66+
name: muneo-shared-net
67+
muneo-prod-net:
68+
name: muneo-prod-net
69+
driver: bridge

docker-compose.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ services:
6767
- "80:80"
6868
- "443:443"
6969
volumes:
70-
- ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf:ro
70+
- ./nginx/conf.d:/etc/nginx/conf.d:ro
7171
- ./certs:/etc/nginx/certs:ro
7272
networks:
7373
- muneo-net
@@ -77,4 +77,5 @@ volumes:
7777

7878
networks:
7979
muneo-net:
80+
name: muneo-shared-net
8081
driver: bridge

nginx/conf.d/prod.conf

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
server {
2+
listen 80;
3+
server_name api-prod.muneo.ai.kr;
4+
5+
return 301 https://$host$request_uri;
6+
}
7+
8+
server {
9+
listen 443 ssl;
10+
http2 on;
11+
12+
server_name api-prod.muneo.ai.kr;
13+
14+
ssl_certificate /etc/nginx/certs/muneo.ai.kr.pem;
15+
ssl_certificate_key /etc/nginx/certs/muneo.ai.kr.key;
16+
17+
client_max_body_size 20m;
18+
19+
# Long-running AI analysis endpoints need higher upstream timeouts than nginx defaults (60s).
20+
location = /api/v1/risk-detector/analyze {
21+
proxy_pass http://app-prod:8080;
22+
23+
proxy_http_version 1.1;
24+
proxy_request_buffering off;
25+
proxy_connect_timeout 10s;
26+
proxy_send_timeout 180s;
27+
proxy_read_timeout 180s;
28+
29+
proxy_set_header Host $host;
30+
proxy_set_header X-Real-IP $remote_addr;
31+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
32+
proxy_set_header X-Forwarded-Proto https;
33+
proxy_set_header X-Forwarded-Host $host;
34+
proxy_set_header X-Forwarded-Port 443;
35+
}
36+
37+
location / {
38+
proxy_pass http://app-prod:8080;
39+
40+
proxy_http_version 1.1;
41+
proxy_connect_timeout 10s;
42+
proxy_send_timeout 180s;
43+
proxy_read_timeout 180s;
44+
45+
proxy_set_header Host $host;
46+
proxy_set_header X-Real-IP $remote_addr;
47+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
48+
proxy_set_header X-Forwarded-Proto https;
49+
proxy_set_header X-Forwarded-Host $host;
50+
proxy_set_header X-Forwarded-Port 443;
51+
52+
proxy_set_header Upgrade $http_upgrade;
53+
proxy_set_header Connection $connection_upgrade;
54+
}
55+
}

src/main/java/com/example/muneoserver/domain/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)