refactor: all
This commit is contained in:
parent
ca1e7dbdf0
commit
e6f2c3a810
@ -4,7 +4,15 @@ server {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
|
||||
# Gzip compression
|
||||
# 에러 페이지 설정
|
||||
error_page 404 /index.html;
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
# 로깅 설정
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
|
||||
# Gzip compression 최적화
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
@ -17,30 +25,118 @@ server {
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/json;
|
||||
application/json
|
||||
application/xml
|
||||
image/svg+xml;
|
||||
|
||||
# Handle client routing (Vue Router)
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
# Brotli compression (더 좋은 압축률)
|
||||
# brotli on;
|
||||
# brotli_comp_level 6;
|
||||
# brotli_types text/xml image/svg+xml application/x-font-ttf image/vnd.microsoft.icon application/x-font-opentype application/json font/eot application/vnd.ms-fontobject application/javascript font/otf application/xml application/xhtml+xml text/javascript application/x-javascript text/plain application/x-font-truetype application/xml+rss image/x-icon font/opentype text/css image/x-win-bitmap;
|
||||
|
||||
# Security headers
|
||||
# 보안 헤더 강화
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.googleapis.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' http://smarketing.20.249.184.228.nip.io https://smarketing.20.249.184.228.nip.io" always;
|
||||
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
# CORS 설정 (필요시)
|
||||
add_header Access-Control-Allow-Origin "*" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;
|
||||
|
||||
# SPA 라우팅 처리 (Vue Router)
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
|
||||
# HTML 파일은 캐시하지 않음 (런타임 설정 반영 위해)
|
||||
location ~* \.html$ {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
add_header Pragma "no-cache";
|
||||
}
|
||||
}
|
||||
|
||||
# Health check endpoint
|
||||
# 런타임 환경 설정 파일 - 캐시하지 않음
|
||||
location /runtime-env.js {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
add_header Pragma "no-cache";
|
||||
}
|
||||
|
||||
# 정적 자산 캐시 최적화
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
|
||||
# 정적 파일에 대한 로깅 최소화
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# manifest.json과 service worker 캐시 설정
|
||||
location ~* \.(json|webmanifest)$ {
|
||||
expires 1d;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
location /sw.js {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
}
|
||||
|
||||
# 파비콘 캐시
|
||||
location /favicon.ico {
|
||||
expires 1M;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# 헬스체크 엔드포인트
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
}
|
||||
|
||||
# API 프록시 (필요시 백엔드로 직접 프록시)
|
||||
# location /api/ {
|
||||
# proxy_pass http://smarketing.20.249.184.228.nip.io/api/;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# proxy_connect_timeout 30s;
|
||||
# proxy_send_timeout 30s;
|
||||
# proxy_read_timeout 30s;
|
||||
# }
|
||||
|
||||
# 숨겨진 파일 접근 차단
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# 불필요한 파일 접근 차단
|
||||
location ~* \.(log|txt|md|yml|yaml|conf)$ {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# 압축된 자산 우선 제공
|
||||
location ~* \.(js|css)$ {
|
||||
gzip_static on;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# 추가 서버 블록 (HTTPS 리다이렉트, 필요시)
|
||||
# server {
|
||||
# listen 8080;
|
||||
# server_name smarketing.20.249.184.228.nip.io;
|
||||
# return 301 https://$server_name$request_uri;
|
||||
# }
|
||||
@ -140,7 +140,7 @@ metadata:
|
||||
labels:
|
||||
app: smarketing-frontend
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: ${export_port}
|
||||
@ -157,6 +157,7 @@ metadata:
|
||||
namespace: ${namespace}
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "false"
|
||||
spec:
|
||||
rules:
|
||||
- host: ${ingress_host}
|
||||
|
||||
@ -14,14 +14,14 @@ export_port=18080
|
||||
# Gateway/Ingress 설정 (⭐ smarketing-backend와 동일한 IP 사용)
|
||||
ingress_host=smarketing.20.249.184.228.nip.io
|
||||
|
||||
# 리소스 설정
|
||||
resources_requests_cpu=256m
|
||||
resources_requests_memory=256Mi
|
||||
resources_limits_cpu=1024m
|
||||
resources_limits_memory=1024Mi
|
||||
# 리소스 설정 (프론트엔드에 맞게 조정)
|
||||
resources_requests_cpu=128m # 프론트엔드는 CPU 사용량이 적음
|
||||
resources_requests_memory=128Mi # 메모리도 적게 사용
|
||||
resources_limits_cpu=512m # 제한도 낮게 설정
|
||||
resources_limits_memory=512Mi
|
||||
|
||||
# API URLs (⭐ smarketing-backend ingress를 통해 라우팅)
|
||||
# 현재 설정된 백엔드 API들과 일치
|
||||
# 백엔드 서비스별 API 경로들
|
||||
auth_url=http://smarketing.20.249.184.228.nip.io/api/auth
|
||||
member_url=http://smarketing.20.249.184.228.nip.io/api/member
|
||||
store_url=http://smarketing.20.249.184.228.nip.io/api/store
|
||||
@ -30,6 +30,39 @@ sales_url=http://smarketing.20.249.184.228.nip.io/api/sales
|
||||
content_url=http://smarketing.20.249.184.228.nip.io/api/content
|
||||
recommend_url=http://smarketing.20.249.184.228.nip.io/api/recommend
|
||||
|
||||
# Frontend 이미지 경로 설정
|
||||
smarketing_frontend_image_path=${registry}/${image_org}/smarketing-frontend:latest
|
||||
|
||||
# GitHub 설정
|
||||
github_org=won-ktds
|
||||
teamid=smarketing
|
||||
teamid=smarketing
|
||||
|
||||
# 환경 플래그
|
||||
environment=production
|
||||
debug_mode=false
|
||||
|
||||
# SSL/TLS 설정 (필요시)
|
||||
ssl_enabled=false
|
||||
ssl_redirect=false
|
||||
|
||||
# 로깅 레벨
|
||||
log_level=info
|
||||
|
||||
# 헬스체크 설정
|
||||
health_check_path=/health
|
||||
health_check_interval=30s
|
||||
health_check_timeout=5s
|
||||
health_check_retries=3
|
||||
|
||||
# 보안 설정
|
||||
security_headers_enabled=true
|
||||
cors_enabled=true
|
||||
allowed_origins=*
|
||||
|
||||
# 캐시 설정
|
||||
static_cache_enabled=true
|
||||
static_cache_duration=1y
|
||||
|
||||
# 압축 설정
|
||||
gzip_enabled=true
|
||||
gzip_compression_level=6
|
||||
@ -5,6 +5,7 @@ metadata:
|
||||
namespace: ${namespace}
|
||||
labels:
|
||||
app: smarketing-frontend
|
||||
version: v1
|
||||
spec:
|
||||
replicas: ${replicas}
|
||||
selector:
|
||||
@ -14,6 +15,7 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
app: smarketing-frontend
|
||||
version: v1
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: acr-secret
|
||||
@ -23,6 +25,7 @@ spec:
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: ${export_port}
|
||||
name: http
|
||||
resources:
|
||||
requests:
|
||||
cpu: ${resources_requests_cpu}
|
||||
@ -34,19 +37,53 @@ spec:
|
||||
- name: runtime-config
|
||||
mountPath: /usr/share/nginx/html/runtime-env.js
|
||||
subPath: runtime-env.js
|
||||
readOnly: true
|
||||
env:
|
||||
- name: NGINX_PORT
|
||||
value: "${export_port}"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: ${export_port}
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
successThreshold: 1
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: ${export_port}
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
successThreshold: 1
|
||||
# 시작 프로브 추가 (컨테이너 시작 시간이 오래 걸릴 수 있음)
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: ${export_port}
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 30
|
||||
successThreshold: 1
|
||||
volumes:
|
||||
- name: runtime-config
|
||||
configMap:
|
||||
name: smarketing-frontend-config
|
||||
name: smarketing-frontend-config
|
||||
defaultMode: 0644
|
||||
# 배포 전략 설정
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 0
|
||||
maxSurge: 1
|
||||
# 재시작 정책
|
||||
restartPolicy: Always
|
||||
# DNS 정책
|
||||
dnsPolicy: ClusterFirst
|
||||
@ -8,14 +8,14 @@ data:
|
||||
console.log('=== RUNTIME-ENV.JS 로드됨 (배포 환경) ===');
|
||||
|
||||
window.__runtime_config__ = {
|
||||
// 백엔드 API 구조에 맞게 URL 설정
|
||||
// 백엔드 API 구조에 맞게 URL 설정 - ingress host 사용
|
||||
AUTH_URL: 'http://${ingress_host}/api/auth',
|
||||
MEMBER_URL: 'http://${ingress_host}/api/member',
|
||||
STORE_URL: 'http://${ingress_host}/api/store',
|
||||
MENU_URL: 'http://${ingress_host}/api/menu',
|
||||
SALES_URL: 'http://${ingress_host}/api/sales',
|
||||
CONTENT_URL: 'http://${ingress_host}/api/content',
|
||||
RECOMMEND_URL: 'http://${ingress_host}/api/recommendations',
|
||||
RECOMMEND_URL: 'http://${ingress_host}/api/recommend',
|
||||
|
||||
// Gateway URL (운영 환경)
|
||||
GATEWAY_URL: 'http://${ingress_host}',
|
||||
|
||||
@ -1,18 +1,62 @@
|
||||
//* public/runtime-env.js - 백엔드 API 경로에 맞게 수정
|
||||
//* public/runtime-env.js - 배포 환경 우선 설정
|
||||
console.log('=== RUNTIME-ENV.JS 로드됨 ===');
|
||||
|
||||
// 배포 환경 감지 함수
|
||||
const isProduction = () => {
|
||||
// 프로덕션 환경 감지 로직
|
||||
return window.location.hostname !== 'localhost' &&
|
||||
window.location.hostname !== '127.0.0.1' &&
|
||||
!window.location.hostname.includes('dev');
|
||||
};
|
||||
|
||||
// 기본 ingress host 설정 (deploy_env_vars에서 설정된 값)
|
||||
const DEFAULT_INGRESS_HOST = 'smarketing.20.249.184.228.nip.io';
|
||||
|
||||
// 환경별 API URL 설정
|
||||
const getBaseUrl = () => {
|
||||
if (isProduction()) {
|
||||
// 프로덕션: ingress host 사용
|
||||
return `http://${DEFAULT_INGRESS_HOST}`;
|
||||
} else {
|
||||
// 개발환경: localhost 사용
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
const baseUrl = getBaseUrl();
|
||||
|
||||
window.__runtime_config__ = {
|
||||
// ⚠️ 수정: 백엔드 API 구조에 맞게 URL 설정
|
||||
AUTH_URL: 'http://localhost:8081/api/auth',
|
||||
MEMBER_URL: 'http://localhost:8081/api/member',
|
||||
STORE_URL: 'http://localhost:8082/api/store',
|
||||
MENU_URL: 'http://localhost:8082/api/menu',
|
||||
SALES_URL: 'http://localhost:8082/api/sales', // store 서비스
|
||||
CONTENT_URL: 'http://localhost:8083/api/content',
|
||||
RECOMMEND_URL: 'http://localhost:8084/api/recommendations', // ⚠️ 수정: 올바른 경로
|
||||
// 프로덕션 환경에서는 ingress host 사용, 개발환경에서는 localhost
|
||||
AUTH_URL: isProduction() ?
|
||||
`${baseUrl}/api/auth` :
|
||||
'http://localhost:8081/api/auth',
|
||||
|
||||
MEMBER_URL: isProduction() ?
|
||||
`${baseUrl}/api/member` :
|
||||
'http://localhost:8081/api/member',
|
||||
|
||||
STORE_URL: isProduction() ?
|
||||
`${baseUrl}/api/store` :
|
||||
'http://localhost:8082/api/store',
|
||||
|
||||
MENU_URL: isProduction() ?
|
||||
`${baseUrl}/api/menu` :
|
||||
'http://localhost:8082/api/menu',
|
||||
|
||||
SALES_URL: isProduction() ?
|
||||
`${baseUrl}/api/sales` :
|
||||
'http://localhost:8082/api/sales',
|
||||
|
||||
CONTENT_URL: isProduction() ?
|
||||
`${baseUrl}/api/content` :
|
||||
'http://localhost:8083/api/content',
|
||||
|
||||
RECOMMEND_URL: isProduction() ?
|
||||
`${baseUrl}/api/recommend` :
|
||||
'http://localhost:8084/api/recommendations',
|
||||
|
||||
// Gateway URL (운영 환경용)
|
||||
GATEWAY_URL: 'http://20.1.2.3',
|
||||
// Gateway URL
|
||||
GATEWAY_URL: isProduction() ? baseUrl : 'http://20.1.2.3',
|
||||
|
||||
// 기능 플래그
|
||||
FEATURES: {
|
||||
@ -20,17 +64,17 @@ window.__runtime_config__ = {
|
||||
PUSH_NOTIFICATIONS: true,
|
||||
SOCIAL_LOGIN: false,
|
||||
MULTI_LANGUAGE: false,
|
||||
API_HEALTH_CHECK: true, // ⚠️ 추가
|
||||
API_HEALTH_CHECK: true,
|
||||
},
|
||||
|
||||
// 환경 설정
|
||||
ENV: 'development',
|
||||
DEBUG: true,
|
||||
ENV: isProduction() ? 'production' : 'development',
|
||||
DEBUG: !isProduction(),
|
||||
|
||||
// ⚠️ 추가: API 타임아웃 설정
|
||||
// API 타임아웃 설정
|
||||
API_TIMEOUT: 30000,
|
||||
|
||||
// ⚠️ 추가: 재시도 설정
|
||||
// 재시도 설정
|
||||
RETRY_ATTEMPTS: 3,
|
||||
RETRY_DELAY: 1000,
|
||||
|
||||
@ -38,7 +82,7 @@ window.__runtime_config__ = {
|
||||
VERSION: '1.0.0',
|
||||
BUILD_DATE: new Date().toISOString(),
|
||||
|
||||
// ⚠️ 추가: 백엔드 서비스 포트 정보 (디버깅용)
|
||||
// 백엔드 서비스 포트 정보 (디버깅용)
|
||||
BACKEND_PORTS: {
|
||||
AUTH: 8081,
|
||||
STORE: 8082,
|
||||
@ -47,7 +91,7 @@ window.__runtime_config__ = {
|
||||
}
|
||||
};
|
||||
|
||||
// ⚠️ 추가: 설정 검증 함수
|
||||
// 설정 검증 함수
|
||||
const validateConfig = () => {
|
||||
const config = window.__runtime_config__;
|
||||
const requiredUrls = ['AUTH_URL', 'STORE_URL', 'SALES_URL', 'RECOMMEND_URL'];
|
||||
@ -63,8 +107,13 @@ const validateConfig = () => {
|
||||
return true;
|
||||
};
|
||||
|
||||
// ⚠️ 추가: 개발 환경에서만 상세 로깅
|
||||
// 환경별 상세 로깅
|
||||
if (window.__runtime_config__.DEBUG) {
|
||||
console.log('=== 현재 환경 정보 ===');
|
||||
console.log('🌍 Environment:', window.__runtime_config__.ENV);
|
||||
console.log('🏠 Hostname:', window.location.hostname);
|
||||
console.log('🔧 Is Production:', isProduction());
|
||||
|
||||
console.log('=== 백엔드 API URLs ===');
|
||||
console.log('🔐 AUTH_URL:', window.__runtime_config__.AUTH_URL);
|
||||
console.log('🏪 STORE_URL:', window.__runtime_config__.STORE_URL);
|
||||
@ -74,12 +123,9 @@ if (window.__runtime_config__.DEBUG) {
|
||||
|
||||
console.log('=== 설정 상세 정보 ===');
|
||||
console.log('전체 설정:', window.__runtime_config__);
|
||||
|
||||
// 설정 검증 실행
|
||||
validateConfig();
|
||||
}
|
||||
|
||||
// ⚠️ 추가: 전역 설정 접근 함수
|
||||
// 전역 설정 접근 함수
|
||||
window.getApiConfig = () => window.__runtime_config__;
|
||||
window.getApiUrl = (serviceName) => {
|
||||
const config = window.__runtime_config__;
|
||||
@ -87,4 +133,7 @@ window.getApiUrl = (serviceName) => {
|
||||
return config[urlKey] || null;
|
||||
};
|
||||
|
||||
console.log('✅ [RUNTIME] 런타임 설정 로드 완료');
|
||||
// 설정 검증 실행
|
||||
validateConfig();
|
||||
|
||||
console.log(`✅ [RUNTIME] 런타임 설정 로드 완료 (${window.__runtime_config__.ENV} 환경)`);
|
||||
Loading…
x
Reference in New Issue
Block a user