From 27ad50f574afdfed1e9a1937b6c63c0117887843 Mon Sep 17 00:00:00 2001 From: tusuii Date: Thu, 19 Feb 2026 18:34:10 +0530 Subject: [PATCH] added deployment files --- .dockerignore | 10 ++++++++ Dockerfile | 28 ++++++++++++++++++++++ k8s/deployment.yaml | 57 +++++++++++++++++++++++++++++++++++++++++++++ k8s/hpa.yaml | 25 ++++++++++++++++++++ k8s/ingress.yaml | 28 ++++++++++++++++++++++ k8s/namespace.yaml | 6 +++++ k8s/service.yaml | 16 +++++++++++++ nginx.conf | 31 ++++++++++++++++++++++++ 8 files changed, 201 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 k8s/deployment.yaml create mode 100644 k8s/hpa.yaml create mode 100644 k8s/ingress.yaml create mode 100644 k8s/namespace.yaml create mode 100644 k8s/service.yaml create mode 100644 nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2af03eb --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +node_modules/ +dist/ +.git/ +.gitignore +*.log +.env* +.vscode/ +.idea/ +k8s/ +README.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..712442c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +# ─── Stage 1: Build ────────────────────────────────────────────────────────── +FROM node:20-alpine AS builder + +WORKDIR /app + +# Install dependencies first (layer-cache friendly) +COPY package.json package-lock.json ./ +RUN npm ci --frozen-lockfile + +# Copy source and build +COPY . . +RUN npm run build + +# ─── Stage 2: Serve ────────────────────────────────────────────────────────── +FROM nginx:1.27-alpine AS runner + +# Remove default nginx content +RUN rm -rf /usr/share/nginx/html/* + +# Copy built assets from builder stage +COPY --from=builder /app/dist /usr/share/nginx/html + +# Copy custom nginx config (handles SPA routing) +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml new file mode 100644 index 0000000..d4fc908 --- /dev/null +++ b/k8s/deployment.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ecommerce-web + namespace: ecommerce + labels: + app: ecommerce-web +spec: + replicas: 2 + selector: + matchLabels: + app: ecommerce-web + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app: ecommerce-web + spec: + containers: + - name: ecommerce-web + # Replace with your actual image name after pushing to a registry + # e.g., docker.io//ecommerce-web:latest + image: ecommerce-web:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + protocol: TCP + resources: + requests: + cpu: "100m" + memory: "64Mi" + limits: + cpu: "250m" + memory: "128Mi" + livenessProbe: + httpGet: + path: /healthz + port: 80 + initialDelaySeconds: 10 + periodSeconds: 15 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /healthz + port: 80 + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: false + runAsNonRoot: false + restartPolicy: Always diff --git a/k8s/hpa.yaml b/k8s/hpa.yaml new file mode 100644 index 0000000..bcaa6b9 --- /dev/null +++ b/k8s/hpa.yaml @@ -0,0 +1,25 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: ecommerce-web + namespace: ecommerce +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: ecommerce-web + minReplicas: 2 + maxReplicas: 8 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 80 diff --git a/k8s/ingress.yaml b/k8s/ingress.yaml new file mode 100644 index 0000000..6121804 --- /dev/null +++ b/k8s/ingress.yaml @@ -0,0 +1,28 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ecommerce-web + namespace: ecommerce + annotations: + # For nginx ingress controller + nginx.ingress.kubernetes.io/rewrite-target: / + # Uncomment below if using cert-manager for TLS + # cert-manager.io/cluster-issuer: letsencrypt-prod +spec: + ingressClassName: nginx + rules: + - host: ecommerce.example.com # Replace with your actual domain + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: ecommerce-web + port: + number: 80 + # Uncomment and configure for HTTPS/TLS + # tls: + # - hosts: + # - ecommerce.example.com + # secretName: ecommerce-web-tls diff --git a/k8s/namespace.yaml b/k8s/namespace.yaml new file mode 100644 index 0000000..8dd5fa8 --- /dev/null +++ b/k8s/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: ecommerce + labels: + app.kubernetes.io/name: ecommerce-web diff --git a/k8s/service.yaml b/k8s/service.yaml new file mode 100644 index 0000000..8718130 --- /dev/null +++ b/k8s/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: ecommerce-web + namespace: ecommerce + labels: + app: ecommerce-web +spec: + selector: + app: ecommerce-web + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 80 + type: ClusterIP diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..97d889f --- /dev/null +++ b/nginx.conf @@ -0,0 +1,31 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + gzip_min_length 1024; + + # Cache static assets aggressively + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|avif|webp|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + try_files $uri =404; + } + + # SPA fallback: send all unmatched routes to index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Disable access logs for health probes (optional) + location /healthz { + access_log off; + return 200 "ok"; + add_header Content-Type text/plain; + } +}