feat: start deployment
This commit is contained in:
parent
9cbb1b63cc
commit
6d628427a6
140
deployment/Jenkinsfile
vendored
Normal file
140
deployment/Jenkinsfile
vendored
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
pipeline {
|
||||||
|
agent {
|
||||||
|
kubernetes {
|
||||||
|
yaml """
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: podman
|
||||||
|
image: quay.io/podman/stable:latest
|
||||||
|
command:
|
||||||
|
- cat
|
||||||
|
tty: true
|
||||||
|
securityContext:
|
||||||
|
privileged: true
|
||||||
|
- name: envsubst
|
||||||
|
image: bhgedigital/envsubst
|
||||||
|
command:
|
||||||
|
- cat
|
||||||
|
tty: true
|
||||||
|
- name: azure-cli
|
||||||
|
image: mcr.microsoft.com/azure-cli:latest
|
||||||
|
command:
|
||||||
|
- cat
|
||||||
|
tty: true
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
environment {
|
||||||
|
// 빌드 정보
|
||||||
|
imageTag = sh(script: "echo ${BUILD_NUMBER}", returnStdout: true).trim()
|
||||||
|
manifest = "deploy.yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Checkout') {
|
||||||
|
steps {
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Load Deploy Variables') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
// deploy_env_vars 파일에서 환경변수 로드
|
||||||
|
if (fileExists('deployment/deploy_env_vars')) {
|
||||||
|
def envVars = readFile('deploy_env_vars').trim()
|
||||||
|
envVars.split('\n').each { line ->
|
||||||
|
if (line.contains('=')) {
|
||||||
|
def (key, value) = line.split('=', 2)
|
||||||
|
env."${key}" = value
|
||||||
|
echo "Loaded: ${key} = ${value}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error "deploy_env_vars 파일이 없습니다!"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 이미지 경로 설정
|
||||||
|
env.imagePath = "${env.REGISTRY}/${env.IMAGE_ORG}/smarketing-frontend:${imageTag}"
|
||||||
|
echo "Image Path: ${env.imagePath}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Build & Push Image') {
|
||||||
|
container('podman') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
sh """
|
||||||
|
podman build \\
|
||||||
|
--build-arg PROJECT_FOLDER="." \\
|
||||||
|
--build-arg REACT_APP_AUTH_URL="${env.AUTH_URL}" \\
|
||||||
|
--build-arg REACT_APP_MEMBER_URL="${env.MEMBER_URL}" \\
|
||||||
|
--build-arg REACT_APP_STORE_URL="${env.STORE_URL}" \\
|
||||||
|
--build-arg REACT_APP_CONTENT_URL="${env.CONTENT_URL}" \\
|
||||||
|
--build-arg REACT_APP_RECOMMEND_URL="${env.RECOMMEND_URL}" \\
|
||||||
|
--build-arg BUILD_FOLDER="deployment/container" \\
|
||||||
|
--build-arg EXPORT_PORT="${env.EXPORT_PORT}" \\
|
||||||
|
-f deployment/container/Dockerfile-smarketing-frontend \\
|
||||||
|
-t ${env.imagePath} .
|
||||||
|
|
||||||
|
podman push ${env.imagePath}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Generate & Apply Manifest') {
|
||||||
|
container('envsubst') {
|
||||||
|
steps {
|
||||||
|
sh """
|
||||||
|
export namespace=${env.NAMESPACE}
|
||||||
|
export smarketing_frontend_image_path=${env.imagePath}
|
||||||
|
export replicas=${env.REPLICAS}
|
||||||
|
export export_port=${env.EXPORT_PORT}
|
||||||
|
export ingress_host=${env.INGRESS_HOST}
|
||||||
|
export resources_requests_cpu=${env.RESOURCES_REQUESTS_CPU}
|
||||||
|
export resources_requests_memory=${env.RESOURCES_REQUESTS_MEMORY}
|
||||||
|
export resources_limits_cpu=${env.RESOURCES_LIMITS_CPU}
|
||||||
|
export resources_limits_memory=${env.RESOURCES_LIMITS_MEMORY}
|
||||||
|
|
||||||
|
envsubst < deployment/${manifest}.template > deployment/${manifest}
|
||||||
|
echo "Generated manifest file:"
|
||||||
|
cat deployment/${manifest}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
container('azure-cli') {
|
||||||
|
steps {
|
||||||
|
sh """
|
||||||
|
kubectl apply -f deployment/${manifest}
|
||||||
|
|
||||||
|
echo "Waiting for deployment to be ready..."
|
||||||
|
kubectl -n ${env.NAMESPACE} wait --for=condition=available deployment/smarketing-frontend --timeout=300s
|
||||||
|
|
||||||
|
echo "Deployment completed successfully!"
|
||||||
|
kubectl -n ${env.NAMESPACE} get pods -l app=smarketing-frontend
|
||||||
|
kubectl -n ${env.NAMESPACE} get svc smarketing-frontend-service
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
|
success {
|
||||||
|
echo "✅ smarketing-frontend 배포가 성공적으로 완료되었습니다!"
|
||||||
|
}
|
||||||
|
failure {
|
||||||
|
echo "❌ smarketing-frontend 배포 중 오류가 발생했습니다."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
136
deployment/Jenkinsfile_ArgoCD
Normal file
136
deployment/Jenkinsfile_ArgoCD
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
pipeline {
|
||||||
|
agent {
|
||||||
|
kubernetes {
|
||||||
|
yaml """
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: podman
|
||||||
|
image: quay.io/podman/stable:latest
|
||||||
|
command:
|
||||||
|
- cat
|
||||||
|
tty: true
|
||||||
|
securityContext:
|
||||||
|
privileged: true
|
||||||
|
- name: git
|
||||||
|
image: alpine/git:latest
|
||||||
|
command:
|
||||||
|
- cat
|
||||||
|
tty: true
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
environment {
|
||||||
|
imageTag = sh(script: "echo ${BUILD_NUMBER}", returnStdout: true).trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Checkout') {
|
||||||
|
steps {
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Load Deploy Variables') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
// deploy_env_vars 파일에서 환경변수 로드
|
||||||
|
if (fileExists('deploy_env_vars')) {
|
||||||
|
def envVars = readFile('deploy_env_vars').trim()
|
||||||
|
envVars.split('\n').each { line ->
|
||||||
|
if (line.contains('=')) {
|
||||||
|
def (key, value) = line.split('=', 2)
|
||||||
|
env."${key}" = value
|
||||||
|
echo "Loaded: ${key} = ${value}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error "deploy_env_vars 파일이 없습니다!"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 이미지 경로 설정
|
||||||
|
env.imagePath = "${env.REGISTRY}/${env.IMAGE_ORG}/smarketing-frontend:${imageTag}"
|
||||||
|
echo "Image Path: ${env.imagePath}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Build & Push Image') {
|
||||||
|
container('podman') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
sh """
|
||||||
|
podman build \\
|
||||||
|
--build-arg PROJECT_FOLDER="." \\
|
||||||
|
--build-arg REACT_APP_AUTH_URL="${env.AUTH_URL}" \\
|
||||||
|
--build-arg REACT_APP_MEMBER_URL="${env.MEMBER_URL}" \\
|
||||||
|
--build-arg REACT_APP_STORE_URL="${env.STORE_URL}" \\
|
||||||
|
--build-arg REACT_APP_CONTENT_URL="${env.CONTENT_URL}" \\
|
||||||
|
--build-arg REACT_APP_RECOMMEND_URL="${env.RECOMMEND_URL}" \\
|
||||||
|
--build-arg BUILD_FOLDER="deployment/container" \\
|
||||||
|
--build-arg EXPORT_PORT="${env.EXPORT_PORT}" \\
|
||||||
|
-f deployment/container/Dockerfile-smarketing-frontend \\
|
||||||
|
-t ${env.imagePath} .
|
||||||
|
|
||||||
|
podman push ${env.imagePath}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Update Manifest Repository') {
|
||||||
|
container('git') {
|
||||||
|
withCredentials([usernamePassword(
|
||||||
|
credentialsId: 'github-credentials-${env.TEAMID}',
|
||||||
|
usernameVariable: 'GIT_USERNAME',
|
||||||
|
passwordVariable: 'GIT_PASSWORD'
|
||||||
|
)]) {
|
||||||
|
steps {
|
||||||
|
sh """
|
||||||
|
# Git 설정
|
||||||
|
git config --global user.name "Jenkins"
|
||||||
|
git config --global user.email "jenkins@company.com"
|
||||||
|
|
||||||
|
# Manifest Repository Clone
|
||||||
|
git clone https://\$GIT_USERNAME:\$GIT_PASSWORD@github.com/${env.GITHUB_ORG}/smarketing-manifest.git
|
||||||
|
cd smarketing-manifest
|
||||||
|
|
||||||
|
# Frontend 이미지 태그 업데이트
|
||||||
|
echo "Updating smarketing-frontend deployment with image tag: ${imageTag}"
|
||||||
|
|
||||||
|
if [ -f "smarketing-frontend/deployment.yaml" ]; then
|
||||||
|
# 기존 이미지 태그를 새 태그로 교체
|
||||||
|
sed -i "s|image: ${env.REGISTRY}/${env.IMAGE_ORG}/smarketing-frontend:.*|image: ${env.imagePath}|g" smarketing-frontend/deployment.yaml
|
||||||
|
|
||||||
|
echo "Updated frontend deployment file:"
|
||||||
|
cat smarketing-frontend/deployment.yaml | grep "image:"
|
||||||
|
else
|
||||||
|
echo "Warning: Frontend deployment file not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 변경사항 커밋 및 푸시
|
||||||
|
git add .
|
||||||
|
git commit -m "Update smarketing-frontend image tag to ${imageTag}" || echo "No changes to commit"
|
||||||
|
git push origin main
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
|
success {
|
||||||
|
echo "✅ smarketing-frontend 이미지 빌드 및 Manifest 업데이트가 완료되었습니다!"
|
||||||
|
}
|
||||||
|
failure {
|
||||||
|
echo "❌ smarketing-frontend CI/CD 파이프라인 중 오류가 발생했습니다."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
deployment/container/Dockerfile-smarketing-frontend
Normal file
82
deployment/container/Dockerfile-smarketing-frontend
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# Build stage
|
||||||
|
FROM node:20-slim AS builder
|
||||||
|
ARG PROJECT_FOLDER
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
COPY ${PROJECT_FOLDER}/package*.json ./
|
||||||
|
RUN npm ci --only=production
|
||||||
|
|
||||||
|
# Build application
|
||||||
|
COPY ${PROJECT_FOLDER} .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Run stage
|
||||||
|
FROM nginx:stable-alpine
|
||||||
|
|
||||||
|
ARG BUILD_FOLDER
|
||||||
|
ARG EXPORT_PORT
|
||||||
|
ARG REACT_APP_AUTH_URL
|
||||||
|
ARG REACT_APP_MEMBER_URL
|
||||||
|
ARG REACT_APP_STORE_URL
|
||||||
|
ARG REACT_APP_CONTENT_URL
|
||||||
|
ARG REACT_APP_RECOMMEND_URL
|
||||||
|
|
||||||
|
# Create nginx user if it doesn't exist
|
||||||
|
RUN adduser -S nginx || true
|
||||||
|
|
||||||
|
# Copy build files
|
||||||
|
COPY --from=builder /app/build /usr/share/nginx/html
|
||||||
|
|
||||||
|
# Create runtime config with all smarketing APIs
|
||||||
|
# index.html의 헤더에서 이 값을 읽어 환경변수를 생성함
|
||||||
|
# api.js에서 이 환경변수를 이용함
|
||||||
|
RUN echo "console.log('=== RUNTIME-ENV.JS 로드됨 (Docker 빌드) ==='); \
|
||||||
|
window.__runtime_config__ = { \
|
||||||
|
AUTH_URL: '${REACT_APP_AUTH_URL}', \
|
||||||
|
MEMBER_URL: '${REACT_APP_MEMBER_URL}', \
|
||||||
|
STORE_URL: '${REACT_APP_STORE_URL}', \
|
||||||
|
CONTENT_URL: '${REACT_APP_CONTENT_URL}', \
|
||||||
|
RECOMMEND_URL: '${REACT_APP_RECOMMEND_URL}', \
|
||||||
|
ENV: 'production', \
|
||||||
|
DEBUG: false, \
|
||||||
|
API_TIMEOUT: 30000, \
|
||||||
|
RETRY_ATTEMPTS: 3, \
|
||||||
|
RETRY_DELAY: 1000, \
|
||||||
|
VERSION: '1.0.0', \
|
||||||
|
BUILD_DATE: new Date().toISOString() \
|
||||||
|
}; \
|
||||||
|
window.getApiConfig = () => window.__runtime_config__; \
|
||||||
|
window.getApiUrl = (serviceName) => { \
|
||||||
|
const config = window.__runtime_config__; \
|
||||||
|
const urlKey = \`\${serviceName.toUpperCase()}_URL\`; \
|
||||||
|
return config[urlKey] || null; \
|
||||||
|
}; \
|
||||||
|
console.log('✅ [RUNTIME] Docker 빌드 런타임 설정 로드 완료');" > /usr/share/nginx/html/runtime-env.js
|
||||||
|
|
||||||
|
# Copy and process nginx configuration
|
||||||
|
COPY ${BUILD_FOLDER}/nginx.conf /etc/nginx/templates/default.conf.template
|
||||||
|
|
||||||
|
# Add custom nginx settings
|
||||||
|
RUN echo "client_max_body_size 100M;" > /etc/nginx/conf.d/client_max_body_size.conf
|
||||||
|
RUN echo "proxy_buffer_size 128k;" > /etc/nginx/conf.d/proxy_buffer_size.conf
|
||||||
|
RUN echo "proxy_buffers 4 256k;" > /etc/nginx/conf.d/proxy_buffers.conf
|
||||||
|
RUN echo "proxy_busy_buffers_size 256k;" > /etc/nginx/conf.d/proxy_busy_buffers_size.conf
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
RUN chown -R nginx:nginx /usr/share/nginx/html && \
|
||||||
|
chmod -R 755 /usr/share/nginx/html && \
|
||||||
|
chown -R nginx:nginx /var/cache/nginx && \
|
||||||
|
chown -R nginx:nginx /var/log/nginx && \
|
||||||
|
chown -R nginx:nginx /etc/nginx/conf.d && \
|
||||||
|
touch /var/run/nginx.pid && \
|
||||||
|
chown -R nginx:nginx /var/run/nginx.pid
|
||||||
|
|
||||||
|
USER nginx
|
||||||
|
|
||||||
|
EXPOSE ${EXPORT_PORT}
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
69
deployment/container/nginx.conf
Normal file
69
deployment/container/nginx.conf
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log main;
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
|
||||||
|
# Basic settings
|
||||||
|
sendfile on;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
types_hash_max_size 2048;
|
||||||
|
|
||||||
|
# Gzip compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 10240;
|
||||||
|
gzip_proxied expired no-cache no-store private must-revalidate;
|
||||||
|
gzip_types
|
||||||
|
text/plain
|
||||||
|
text/css
|
||||||
|
text/xml
|
||||||
|
text/javascript
|
||||||
|
application/x-javascript
|
||||||
|
application/xml+rss
|
||||||
|
application/javascript
|
||||||
|
application/json;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 18080;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
# 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;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html index.htm;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
|
||||||
|
# Cache static assets
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Health check endpoint
|
||||||
|
location /health {
|
||||||
|
access_log off;
|
||||||
|
return 200 "healthy\n";
|
||||||
|
add_header Content-Type text/plain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
86
deployment/deploy.yaml.template
Normal file
86
deployment/deploy.yaml.template
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
# ConfigMap
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: smarketing-frontend-config
|
||||||
|
namespace: ${namespace}
|
||||||
|
data:
|
||||||
|
runtime-env.js: |
|
||||||
|
window.__runtime_config__ = {
|
||||||
|
AUTH_URL: 'http://${ingress_host}/auth',
|
||||||
|
CONTENT_URL: 'http://${ingress_host}/content',
|
||||||
|
AI_URL: 'http://${ingress_host}/ai'
|
||||||
|
};
|
||||||
|
|
||||||
|
---
|
||||||
|
# Deployment
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: smarketing-frontend
|
||||||
|
namespace: ${namespace}
|
||||||
|
labels:
|
||||||
|
app: smarketing-frontend
|
||||||
|
spec:
|
||||||
|
replicas: ${replicas}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: smarketing-frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: smarketing-frontend
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: acr-secret
|
||||||
|
containers:
|
||||||
|
- name: smarketing-frontend
|
||||||
|
image: ${smarketing_frontend_image_path}
|
||||||
|
imagePullPolicy: Always
|
||||||
|
ports:
|
||||||
|
- containerPort: ${export_port}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: ${resources_requests_cpu}
|
||||||
|
memory: ${resources_requests_memory}
|
||||||
|
limits:
|
||||||
|
cpu: ${resources_limits_cpu}
|
||||||
|
memory: ${resources_limits_memory}
|
||||||
|
volumeMounts:
|
||||||
|
- name: runtime-config
|
||||||
|
mountPath: /usr/share/nginx/html/runtime-env.js
|
||||||
|
subPath: runtime-env.js
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: ${export_port}
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: ${export_port}
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
volumes:
|
||||||
|
- name: runtime-config
|
||||||
|
configMap:
|
||||||
|
name: smarketing-frontend-config
|
||||||
|
|
||||||
|
---
|
||||||
|
# Service
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: smarketing-frontend-service
|
||||||
|
namespace: ${namespace}
|
||||||
|
labels:
|
||||||
|
app: smarketing-frontend
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: ${export_port}
|
||||||
|
protocol: TCP
|
||||||
|
selector:
|
||||||
|
app: smarketing-frontend
|
||||||
34
deployment/deploy_env_vars
Normal file
34
deployment/deploy_env_vars
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# smarketing-frontend 배포 환경변수 설정
|
||||||
|
# 이 파일을 실제 환경에 맞게 수정하세요
|
||||||
|
|
||||||
|
# Container Registry 설정
|
||||||
|
REGISTRY=acrdigitalgarage02.azurecr.io
|
||||||
|
IMAGE_ORG=smarketing
|
||||||
|
|
||||||
|
# Kubernetes 설정
|
||||||
|
NAMESPACE=smarketing
|
||||||
|
REPLICAS=1
|
||||||
|
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
|
||||||
|
|
||||||
|
# API URLs (⭐ smarketing-backend ingress를 통해 라우팅)
|
||||||
|
# 현재 설정된 백엔드 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
|
||||||
|
MENU_URL=http://smarketing.20.249.184.228.nip.io/api/menu
|
||||||
|
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
|
||||||
|
|
||||||
|
# GitHub 설정 (실제 팀 설정으로 변경)
|
||||||
|
GITHUB_ORG=won-ktds
|
||||||
|
TEAMID=smarketing
|
||||||
52
deployment/manifest/deployment.yaml
Normal file
52
deployment/manifest/deployment.yaml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: smarketing-frontend
|
||||||
|
namespace: ${namespace}
|
||||||
|
labels:
|
||||||
|
app: smarketing-frontend
|
||||||
|
spec:
|
||||||
|
replicas: ${replicas}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: smarketing-frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: smarketing-frontend
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: acr-secret
|
||||||
|
containers:
|
||||||
|
- name: smarketing-frontend
|
||||||
|
image: ${smarketing_frontend_image_path}
|
||||||
|
imagePullPolicy: Always
|
||||||
|
ports:
|
||||||
|
- containerPort: ${export_port}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: ${resources_requests_cpu}
|
||||||
|
memory: ${resources_requests_memory}
|
||||||
|
limits:
|
||||||
|
cpu: ${resources_limits_cpu}
|
||||||
|
memory: ${resources_limits_memory}
|
||||||
|
volumeMounts:
|
||||||
|
- name: runtime-config
|
||||||
|
mountPath: /usr/share/nginx/html/runtime-env.js
|
||||||
|
subPath: runtime-env.js
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: ${export_port}
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: ${export_port}
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
volumes:
|
||||||
|
- name: runtime-config
|
||||||
|
configMap:
|
||||||
|
name: smarketing-frontend-config
|
||||||
74
deployment/manifest/frontend-configmap.yaml
Normal file
74
deployment/manifest/frontend-configmap.yaml
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: smarketing-frontend-config
|
||||||
|
namespace: ${namespace}
|
||||||
|
data:
|
||||||
|
runtime-env.js: |
|
||||||
|
console.log('=== RUNTIME-ENV.JS 로드됨 (배포 환경) ===');
|
||||||
|
|
||||||
|
window.__runtime_config__ = {
|
||||||
|
// 백엔드 API 구조에 맞게 URL 설정
|
||||||
|
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',
|
||||||
|
|
||||||
|
// Gateway URL (운영 환경)
|
||||||
|
GATEWAY_URL: 'http://${ingress_host}',
|
||||||
|
|
||||||
|
// 기능 플래그
|
||||||
|
FEATURES: {
|
||||||
|
ANALYTICS: true,
|
||||||
|
PUSH_NOTIFICATIONS: true,
|
||||||
|
SOCIAL_LOGIN: false,
|
||||||
|
MULTI_LANGUAGE: false,
|
||||||
|
API_HEALTH_CHECK: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 환경 설정 (배포 환경)
|
||||||
|
ENV: 'production',
|
||||||
|
DEBUG: false,
|
||||||
|
|
||||||
|
// API 타임아웃 설정
|
||||||
|
API_TIMEOUT: 30000,
|
||||||
|
|
||||||
|
// 재시도 설정
|
||||||
|
RETRY_ATTEMPTS: 3,
|
||||||
|
RETRY_DELAY: 1000,
|
||||||
|
|
||||||
|
// 버전 정보
|
||||||
|
VERSION: '1.0.0',
|
||||||
|
BUILD_DATE: new Date().toISOString()
|
||||||
|
};
|
||||||
|
|
||||||
|
// 설정 검증 함수
|
||||||
|
const validateConfig = () => {
|
||||||
|
const config = window.__runtime_config__;
|
||||||
|
const requiredUrls = ['AUTH_URL', 'STORE_URL', 'SALES_URL', 'RECOMMEND_URL'];
|
||||||
|
|
||||||
|
for (const url of requiredUrls) {
|
||||||
|
if (!config[url]) {
|
||||||
|
console.error(`❌ [CONFIG] 필수 URL 누락: ${url}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ [CONFIG] 설정 검증 완료');
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 전역 설정 접근 함수
|
||||||
|
window.getApiConfig = () => window.__runtime_config__;
|
||||||
|
window.getApiUrl = (serviceName) => {
|
||||||
|
const config = window.__runtime_config__;
|
||||||
|
const urlKey = `${serviceName.toUpperCase()}_URL`;
|
||||||
|
return config[urlKey] || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 설정 검증 실행
|
||||||
|
validateConfig();
|
||||||
|
console.log('✅ [RUNTIME] 런타임 설정 로드 완료 (배포 환경)');
|
||||||
15
deployment/manifest/service.yaml
Normal file
15
deployment/manifest/service.yaml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: smarketing-frontend-service
|
||||||
|
namespace: ${namespace}
|
||||||
|
labels:
|
||||||
|
app: smarketing-frontend
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: ${export_port}
|
||||||
|
protocol: TCP
|
||||||
|
selector:
|
||||||
|
app: smarketing-frontend
|
||||||
Loading…
x
Reference in New Issue
Block a user