This commit is contained in:
hiondal
2025-02-17 23:24:16 +09:00
parent 86d487dd79
commit 4d1aa843f0
10 changed files with 199 additions and 0 deletions
+64
View File
@@ -0,0 +1,64 @@
# 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_MEMBER_URL
ARG REACT_APP_MYSUB_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
#index.html의 헤더에서 이 값을 읽어 환경변수를 생성함
#api.js에서 이 환경변수를 이용함: 예) window.__runtime_config__.MEMBER_URL
RUN echo "window.__runtime_config__ = { \
MEMBER_URL: '${REACT_APP_MEMBER_URL}', \
MYSUB_URL: '${REACT_APP_MYSUB_URL}', \
RECOMMEND_URL: '${REACT_APP_RECOMMEND_URL}' \
}" > /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;"]
+101
View File
@@ -0,0 +1,101 @@
def PIPELINE_ID = "${env.BUILD_NUMBER}"
def getImageTag() {
def dateFormat = new java.text.SimpleDateFormat('yyyyMMddHHmmss')
def currentDate = new Date()
return dateFormat.format(currentDate)
}
podTemplate(
label: "${PIPELINE_ID}",
serviceAccount: 'jenkins',
containers: [
containerTemplate(name: 'node', image: 'node:20-slim', ttyEnabled: true, command: 'cat'),
containerTemplate(name: 'podman', image: "mgoltzsche/podman", ttyEnabled: true, command: 'cat', privileged: true),
containerTemplate(name: 'azure-cli', image: 'hiondal/azure-kubectl:latest', command: 'cat', ttyEnabled: true),
containerTemplate(name: 'envsubst', image: "hiondal/envsubst", command: 'sleep', args: '1h')
],
volumes: [
emptyDirVolume(mountPath: '/root/.azure', memory: false)
]
) {
node(PIPELINE_ID) {
def props
def imageTag = getImageTag()
def manifest = "deploy.yaml"
def namespace
stage("Get Source") {
checkout scm
props = readProperties file: "deployment/deploy_env_vars"
namespace = "${props.teamid}-${props.root_project}-ns"
}
stage("Setup AKS") {
container('azure-cli') {
withCredentials([azureServicePrincipal('azure-credentials')]) {
sh """
az login --service-principal -u \$AZURE_CLIENT_ID -p \$AZURE_CLIENT_SECRET -t \$AZURE_TENANT_ID
az aks get-credentials --resource-group ictcoe-edu --name ${props.teamid}-aks --overwrite-existing
kubectl create namespace ${namespace} --dry-run=client -o yaml | kubectl apply -f -
"""
}
}
}
stage('Build & Push Image') {
container('podman') {
withCredentials([usernamePassword(
credentialsId: 'acr-credentials',
usernameVariable: 'USERNAME',
passwordVariable: 'PASSWORD'
)]) {
def imagePath = "${props.registry}/${props.image_org}/lifesub-web:${imageTag}"
sh """
podman login ${props.registry} --username \$USERNAME --password \$PASSWORD
podman build \
--build-arg PROJECT_FOLDER="." \
--build-arg REACT_APP_MEMBER_URL="${props.react_app_member_url}" \
--build-arg REACT_APP_MYSUB_URL="${props.react_app_mysub_url}" \
--build-arg REACT_APP_RECOMMEND_URL="${props.react_app_recommend_url}" \
--build-arg BUILD_FOLDER="container" \
--build-arg EXPORT_PORT="${props.export_port}" \
-f container/Dockerfile-lifesub-web \
-t ${imagePath} .
podman push ${imagePath}
"""
}
}
}
stage('Generate & Apply Manifest') {
container('envsubst') {
sh """
export namespace=${namespace}
export lifesub_web_image_path=${props.registry}/${props.image_org}/lifesub-web:${imageTag}
export replicas=${props.replicas}
export export_port=${props.export_port}
export resources_requests_cpu=${props.resources_requests_cpu}
export resources_requests_memory=${props.resources_requests_memory}
export resources_limits_cpu=${props.resources_limits_cpu}
export resources_limits_memory=${props.resources_limits_memory}
envsubst < deployment/${manifest}.template > deployment/${manifest}
cat deployment/${manifest}
"""
}
container('azure-cli') {
sh """
kubectl apply -f deployment/${manifest}
echo "Waiting for deployment to be ready..."
kubectl -n ${namespace} wait --for=condition=available deployment/lifesub-web --timeout=300s
"""
}
}
}
}
+44
View File
@@ -0,0 +1,44 @@
# Frontend Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: lifesub-web
namespace: ${namespace}
spec:
replicas: ${replicas}
selector:
matchLabels:
app: lifesub-web
template:
metadata:
labels:
app: lifesub-web
spec:
containers:
- name: lifesub-web
image: ${lifesub_web_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}
---
# Frontend Service
apiVersion: v1
kind: Service
metadata:
name: lifesub-web
namespace: ${namespace}
spec:
selector:
app: lifesub-web
ports:
- port: 80
targetPort: ${export_port}
type: LoadBalancer
+22
View File
@@ -0,0 +1,22 @@
# Team Settings
teamid=dg0200
root_project=lifesub-web
# Container Registry Settings
registry=dg0200cr.azurecr.io
image_org=lifesub
# Application Settings
replicas=1
export_port=18080
# Backend Service URLs
react_app_member_url=http://20.249.185.127/member
react_app_mysub_url=http://20.249.185.127/mysub
react_app_recommend_url=http://20.249.185.127/recommend
# Resource Settings
resources_requests_cpu=256m
resources_requests_memory=256Mi
resources_limits_cpu=1024m
resources_limits_memory=1024Mi
+29
View File
@@ -0,0 +1,29 @@
server {
listen 18080;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
# Cache static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, no-transform";
}
}
# Health check endpoint
location /health {
access_log off;
return 200 'healthy\n';
add_header Content-Type text/plain;
}
# Error pages
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}