Compare commits

..

2 Commits

Author SHA1 Message Date
tusuii
f951b0b970 prisma seed added
Some checks failed
eCommerce-backend/pipeline/head There was a failure building this commit
2026-02-25 00:09:52 +05:30
tusuii
c744d87016 minikube working 2026-02-24 22:06:14 +05:30
28 changed files with 840 additions and 391 deletions

79
Jenkinsfile vendored
View File

@@ -31,6 +31,20 @@ pipeline {
}
}
stage('Install Tools') {
steps {
sh '''
# Ensure kustomize is available
if ! command -v kustomize &>/dev/null; then
echo "Installing kustomize..."
curl -sL "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.4.3/kustomize_v5.4.3_linux_amd64.tar.gz" \
| tar xz -C /usr/local/bin/
fi
kustomize version
'''
}
}
stage('Test') {
steps {
sh 'npm ci && npm test -- --reporter=verbose 2>&1 || true'
@@ -42,10 +56,10 @@ pipeline {
// steps {
// withSonarQubeEnv('SonarQube') {
// sh """
// npx sonar-scanner \
// -Dsonar.projectKey=${SONAR_PROJECT} \
// -Dsonar.projectName='eCommerce Backend' \
// -Dsonar.sources=src \
// npx sonar-scanner \\
// -Dsonar.projectKey=${SONAR_PROJECT} \\
// -Dsonar.projectName='eCommerce Backend' \\
// -Dsonar.sources=src \\
// -Dsonar.host.url=${SONAR_HOST_URL}
// """
// }
@@ -100,16 +114,63 @@ pipeline {
}
}
stage('Deploy to K8s') {
stage('Validate Manifests') {
steps {
sh """
echo "── Validating Kustomize build ──"
kustomize build ${K8S_OVERLAY}
echo "✅ Kustomize build succeeded"
"""
}
}
stage('Deploy Infrastructure') {
steps {
withKubeConfig([credentialsId: "${K8S_CRED_ID}"]) {
// Apply the full kustomize overlay (namespace, secrets, DBs, redis, app, job)
sh "kubectl apply -k ${K8S_OVERLAY}"
// Wait for databases to be ready first
sh "kubectl rollout status statefulset/postgres -n ${K8S_NAMESPACE} --timeout=300s"
sh "kubectl rollout status statefulset/mongodb -n ${K8S_NAMESPACE} --timeout=300s"
sh "kubectl rollout status deployment/redis -n ${K8S_NAMESPACE} --timeout=120s"
echo "✅ Infrastructure (Postgres, MongoDB, Redis) is ready."
}
}
}
stage('Run DB Migrations') {
steps {
withKubeConfig([credentialsId: "${K8S_CRED_ID}"]) {
// Delete previous migration job if it exists (Jobs are immutable)
sh "kubectl delete job prisma-migrate -n ${K8S_NAMESPACE} --ignore-not-found=true"
// Re-apply to create a fresh migration job
sh "kubectl apply -k ${K8S_OVERLAY}"
// Wait for the migration job to complete
sh """
echo "Waiting for Prisma migration job to complete..."
kubectl wait --for=condition=complete \
job/prisma-migrate \
-n ${K8S_NAMESPACE} \
--timeout=120s \
&& echo "✅ Prisma migration succeeded" \
|| {
echo "❌ Migration failed — showing logs:"
kubectl logs job/prisma-migrate -n ${K8S_NAMESPACE} --tail=50
exit 1
}
"""
}
}
}
stage('Deploy Application') {
steps {
withKubeConfig([credentialsId: "${K8S_CRED_ID}"]) {
sh "kubectl rollout status deployment/ecommerce-app -n ${K8S_NAMESPACE} --timeout=300s"
echo "✅ Backend deployed successfully."
}
}
@@ -126,8 +187,8 @@ pipeline {
--attach \
-n ${K8S_NAMESPACE} \
-- curl -sf http://ecommerce-app:80/health \
&& echo "Health check PASSED" \
|| echo "Health check FAILED (non-blocking)"
&& echo "Health check PASSED" \
|| echo "⚠️ Health check FAILED (non-blocking)"
"""
}
}
@@ -145,7 +206,7 @@ pipeline {
post {
success {
echo "✅ Build #${env.BUILD_NUMBER} — eCommerce Backend deployed → http://api.local"
echo "✅ Build #${env.BUILD_NUMBER} — eCommerce Backend deployed → NodePort 30080"
}
failure {
echo "❌ Pipeline failed. Check stage logs above."

46
env-backend.txt Normal file
View File

@@ -0,0 +1,46 @@
# Server Configuration
NODE_ENV=development
PORT=3000
HOST=localhost
# Database Configuration
# DATABASE_URL="postgresql://vaishnavi:admin@localhost:5432/vaishnavi_db?schema=public"
DATABASE_URL=postgresql://vaishnavi:admin@host.docker.internal:5432/vaishnavi_db?schema=public
# MONGODB_URI="mongodb://localhost:27017/vaishnavi_products"
MONGODB_URI=mongodb+srv://techintern_db_user:LiIb5oaof93wx0MY@cluster0.bnv4nae.mongodb.net/vaishnavi_products
REDIS_URL="redis://localhost:6379"
# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_EXPIRES_IN=7d
JWT_REFRESH_SECRET=your-refresh-token-secret
JWT_REFRESH_EXPIRES_IN=30d
# AWS S3 Configuration
AWS_ACCESS_KEY_ID=uA7WvT9fhydcozyz5alo
AWS_SECRET_ACCESS_KEY=AusEy6KKqanQQU3Zw3rXYBaiS5BM8aPoAKfpcbFr
AWS_REGION="us-east-1"
AWS_S3_BUCKET=e-commerce
AWS_ENDPOINT=s3.sahasrarameta.tech
AWS_PORT=443
AWS_SSL=true
EMAIL_USER=vaibhav.sahasrara@gmail.com
EMAIL_PASS=pezjcxfnegguzkuh
FRONTEND_URL=http://localhost:3000,https://vaishnavi-test.myriadcara.in
CORS_ORIGIN=http://localhost:3000,http://localhost:5173,http://localhost:5174,https://vaishnavi-admin.myriadcara.in,https://vaishnavi-bakend.myriadcara.in,https://vaishnavi-test.myriadcara.in
PAYTM_MERCHANT_ID=your_merchant_id
PAYTM_MERCHANT_KEY=abcd1234abcd1234
PAYTM_WEBSITE=WEBSTAGING
PAYTM_HOST=securegw-stage.paytm.in
PAYTM_CALLBACK_URL=http://localhost:3000/api/payments/paytm/callback
# FRONTEND_URL=http://localhost:5173

178
k8s/base/backend.yaml Normal file
View File

@@ -0,0 +1,178 @@
---
# ── eCommerce Backend Service ──
apiVersion: v1
kind: Service
metadata:
name: ecommerce-app
namespace: ecommerce
labels:
app: ecommerce-app
app.kubernetes.io/part-of: ecommerce
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 3000
protocol: TCP
name: http
selector:
app: ecommerce-app
---
# ── eCommerce Backend Deployment ──
apiVersion: apps/v1
kind: Deployment
metadata:
name: ecommerce-app
namespace: ecommerce
labels:
app: ecommerce-app
app.kubernetes.io/part-of: ecommerce
spec:
replicas: 2
selector:
matchLabels:
app: ecommerce-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: ecommerce-app
spec:
containers:
- name: ecommerce-app
image: ecommerce-backend:latest # patched by kustomize overlay
ports:
- containerPort: 3000
name: http
envFrom:
- configMapRef:
name: ecommerce-config
env:
# ── Database ──
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: DATABASE_URL
- name: MONGODB_URI
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: MONGODB_URI
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: REDIS_URL
# ── JWT ──
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: JWT_SECRET
- name: JWT_EXPIRES_IN
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: JWT_EXPIRES_IN
- name: JWT_REFRESH_SECRET
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: JWT_REFRESH_SECRET
- name: JWT_REFRESH_EXPIRES_IN
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: JWT_REFRESH_EXPIRES_IN
# ── AWS S3 / MinIO ──
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: AWS_ACCESS_KEY_ID
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: AWS_SECRET_ACCESS_KEY
- name: AWS_REGION
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: AWS_REGION
- name: AWS_S3_BUCKET
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: AWS_S3_BUCKET
- name: AWS_ENDPOINT
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: AWS_ENDPOINT
# ── Email ──
- name: EMAIL_USER
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: EMAIL_USER
- name: EMAIL_PASS
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: EMAIL_PASS
# ── Paytm ──
- name: PAYTM_MERCHANT_ID
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: PAYTM_MERCHANT_ID
- name: PAYTM_MERCHANT_KEY
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: PAYTM_MERCHANT_KEY
- name: PAYTM_WEBSITE
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: PAYTM_WEBSITE
- name: PAYTM_HOST
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: PAYTM_HOST
- name: PAYTM_CALLBACK_URL
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: PAYTM_CALLBACK_URL
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 5

View File

@@ -1,21 +1,13 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
name: ecommerce-config
namespace: ecommerce
labels:
app.kubernetes.io/part-of: ecommerce
data:
NODE_ENV: "production"
PORT: "3000"
HOST: "0.0.0.0"
JWT_EXPIRES_IN: "7d"
JWT_REFRESH_EXPIRES_IN: "30d"
AWS_REGION: "us-east-1"
AWS_S3_BUCKET: "e-commerce"
AWS_ENDPOINT: "s3.sahasrarameta.tech"
AWS_PORT: "443"
AWS_SSL: "true"
PAYTM_WEBSITE: "WEBSTAGING"
PAYTM_CHANNEL_ID: "WEB"
PAYTM_INDUSTRY_TYPE: "Retail"
PAYTM_HOST: "securegw-stage.paytm.in"
FRONTEND_URL: "http://localhost:5173"
CORS_ORIGIN: "http://localhost:3000,http://localhost:5173,http://localhost:5174,https://vaishnavi-admin.myriadcara.in,https://vaishnavi-bakend.myriadcara.in,https://vaishnavi-test.myriadcara.in"
FRONTEND_URL: "http://localhost:3000,https://vaishnavi-test.myriadcara.in"

View File

@@ -1,87 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ecommerce-app
namespace: ecommerce
labels:
app: ecommerce-app
spec:
replicas: 1
selector:
matchLabels:
app: ecommerce-app
template:
metadata:
labels:
app: ecommerce-app
spec:
initContainers:
- name: wait-for-postgres
image: postgres:15-alpine
command:
- sh
- -c
- |
until pg_isready -h postgres -p 5432 -U vaishnavi; do
echo "Waiting for PostgreSQL..."; sleep 3
done
- name: wait-for-mongodb
image: mongo:7
command:
- sh
- -c
- |
until mongosh --host mongodb --port 27017 \
--eval "db.adminCommand('ping')" --quiet; do
echo "Waiting for MongoDB..."; sleep 3
done
- name: run-migrations
image: ecommerce-backend:latest
command:
- sh
- -c
- npx prisma migrate deploy
envFrom:
- secretRef:
name: app-secret
env:
- name: NODE_ENV
value: "production"
containers:
- name: ecommerce-app
image: ecommerce-backend:latest
ports:
- containerPort: 3000
name: http
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secret
volumeMounts:
- name: uploads-volume
mountPath: /app/uploads
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 10
failureThreshold: 3
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 20
failureThreshold: 3
volumes:
- name: uploads-volume
emptyDir: {}

View File

@@ -1,21 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ecommerce-ingress
namespace: ecommerce
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
spec:
rules:
- host: api.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ecommerce-app
port:
number: 80

View File

@@ -1,16 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: ecommerce
resources:
- namespace.yaml
- secrets.yaml
- configmap.yaml
- secret.yaml
- postgres-pvc.yaml
- postgres-statefulset.yaml
- postgres-service.yaml
- mongodb-pvc.yaml
- mongodb-statefulset.yaml
- mongodb-service.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
- postgres.yaml
- mongodb.yaml
- redis.yaml
- migration-job.yaml
- backend.yaml

View File

@@ -0,0 +1,58 @@
---
# ── Prisma Migration Job ──
# Runs `prisma migrate deploy` before the app starts.
# Jenkins re-creates this Job on every deploy (unique name per build).
apiVersion: batch/v1
kind: Job
metadata:
name: prisma-migrate
namespace: ecommerce
labels:
app: prisma-migrate
app.kubernetes.io/part-of: ecommerce
spec:
backoffLimit: 3
ttlSecondsAfterFinished: 300
template:
metadata:
labels:
app: prisma-migrate
spec:
restartPolicy: Never
initContainers:
# Wait for PostgreSQL to be ready before running migrations
- name: wait-for-postgres
image: postgres:15-alpine
command:
- sh
- -c
- |
echo "Waiting for PostgreSQL to accept connections..."
until pg_isready -h postgres -p 5432 -U ecommerce; do
echo " PostgreSQL not ready yet — sleeping 3s"
sleep 3
done
echo "PostgreSQL is ready!"
env:
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: POSTGRES_PASSWORD
containers:
- name: migrate
image: ecommerce-backend:latest # patched by kustomize overlay
command: ["npx", "prisma", "migrate", "deploy"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: DATABASE_URL
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi

View File

@@ -1,11 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodb-data
namespace: ecommerce
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi

View File

@@ -1,12 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: mongodb
namespace: ecommerce
spec:
type: ClusterIP
selector:
app: mongodb
ports:
- port: 27017
targetPort: 27017

View File

@@ -1,53 +0,0 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
namespace: ecommerce
labels:
app: mongodb
spec:
serviceName: mongodb
replicas: 1
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
securityContext:
fsGroup: 999
containers:
- name: mongodb
image: mongo:7
ports:
- containerPort: 27017
env:
- name: MONGO_INITDB_DATABASE
value: "vaishnavi_products"
volumeMounts:
- name: mongodb-data
mountPath: /data/db
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
readinessProbe:
exec:
command: [mongosh, --eval, "db.adminCommand('ping')", --quiet]
initialDelaySeconds: 15
periodSeconds: 5
failureThreshold: 6
livenessProbe:
exec:
command: [mongosh, --eval, "db.adminCommand('ping')", --quiet]
initialDelaySeconds: 30
periodSeconds: 10
volumes:
- name: mongodb-data
persistentVolumeClaim:
claimName: mongodb-data

81
k8s/base/mongodb.yaml Normal file
View File

@@ -0,0 +1,81 @@
---
# ── MongoDB Service ──
apiVersion: v1
kind: Service
metadata:
name: mongodb
namespace: ecommerce
labels:
app: mongodb
app.kubernetes.io/part-of: ecommerce
spec:
clusterIP: None # Headless for StatefulSet
ports:
- port: 27017
targetPort: 27017
protocol: TCP
name: mongodb
selector:
app: mongodb
---
# ── MongoDB StatefulSet ──
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
namespace: ecommerce
labels:
app: mongodb
app.kubernetes.io/part-of: ecommerce
spec:
serviceName: mongodb
replicas: 1
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: mongo:7
ports:
- containerPort: 27017
name: mongodb
volumeMounts:
- name: mongodb-data
mountPath: /data/db
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
readinessProbe:
tcpSocket:
port: 27017
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 5
livenessProbe:
exec:
command:
- mongosh
- --eval
- "db.adminCommand('ping')"
initialDelaySeconds: 60
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 5
volumeClaimTemplates:
- metadata:
name: mongodb-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi

View File

@@ -2,3 +2,6 @@ apiVersion: v1
kind: Namespace
metadata:
name: ecommerce
labels:
app.kubernetes.io/part-of: ecommerce
app.kubernetes.io/managed-by: kustomize

View File

@@ -1,11 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
namespace: ecommerce
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi

View File

@@ -1,12 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: ecommerce
spec:
type: ClusterIP
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432

View File

@@ -1,59 +0,0 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: ecommerce
labels:
app: postgres
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
securityContext:
fsGroup: 999
containers:
- name: postgres
image: postgres:15-alpine
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: "vaishnavi_db"
- name: POSTGRES_USER
value: "vaishnavi"
- name: POSTGRES_PASSWORD
value: "admin"
- name: PGDATA
value: "/var/lib/postgresql/data/pgdata"
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
readinessProbe:
exec:
command: [pg_isready, -U, vaishnavi, -d, vaishnavi_db]
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 6
livenessProbe:
exec:
command: [pg_isready, -U, vaishnavi, -d, vaishnavi_db]
initialDelaySeconds: 30
periodSeconds: 10
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-data

99
k8s/base/postgres.yaml Normal file
View File

@@ -0,0 +1,99 @@
---
# ── PostgreSQL Service ──
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: ecommerce
labels:
app: postgres
app.kubernetes.io/part-of: ecommerce
spec:
clusterIP: None # Headless for StatefulSet
ports:
- port: 5432
targetPort: 5432
protocol: TCP
name: postgres
selector:
app: postgres
---
# ── PostgreSQL StatefulSet ──
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: ecommerce
labels:
app: postgres
app.kubernetes.io/part-of: ecommerce
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15-alpine
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: POSTGRES_PASSWORD
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: ecommerce-secrets
key: POSTGRES_DB
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
readinessProbe:
exec:
command:
- sh
- -c
- pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
exec:
command:
- sh
- -c
- pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"
initialDelaySeconds: 30
periodSeconds: 15
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi

63
k8s/base/redis.yaml Normal file
View File

@@ -0,0 +1,63 @@
---
# ── Redis Service ──
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: ecommerce
labels:
app: redis
app.kubernetes.io/part-of: ecommerce
spec:
ports:
- port: 6379
targetPort: 6379
protocol: TCP
name: redis
selector:
app: redis
---
# ── Redis Deployment ──
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: ecommerce
labels:
app: redis
app.kubernetes.io/part-of: ecommerce
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
name: redis
command: ["redis-server", "--appendonly", "yes"]
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
readinessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 15
periodSeconds: 20

47
k8s/base/secrets.yaml Normal file
View File

@@ -0,0 +1,47 @@
apiVersion: v1
kind: Secret
metadata:
name: ecommerce-secrets
namespace: ecommerce
labels:
app.kubernetes.io/part-of: ecommerce
type: Opaque
data:
# ── Database credentials (base64-encoded) ──
# echo -n 'value' | base64
# postgresql://vaishnavi:admin@postgres:5432/vaishnavi_db?schema=public
DATABASE_URL: cG9zdGdyZXNxbDovL3ZhaXNobmF2aTphZG1pbkBwb3N0Z3Jlczo1NDMyL3ZhaXNobmF2aV9kYj9zY2hlbWE9cHVibGlj
# mongodb+srv://techintern_db_user:...@cluster0.bnv4nae.mongodb.net/vaishnavi_products
MONGODB_URI: bW9uZ29kYitzcnY6Ly90ZWNoaW50ZXJuX2RiX3VzZXI6TGlJYjVvYW9mOTN3eDBNWUBjbHVzdGVyMC5ibnY0bmFlLm1vbmdvZGIubmV0L3ZhaXNobmF2aV9wcm9kdWN0cw==
# redis://redis:6379
REDIS_URL: cmVkaXM6Ly9yZWRpczo2Mzc5
# ── JWT ──
JWT_SECRET: eW91ci1zdXBlci1zZWNyZXQtand0LWtleS1jaGFuZ2UtdGhpcy1pbi1wcm9kdWN0aW9u
JWT_EXPIRES_IN: N2Q=
JWT_REFRESH_SECRET: eW91ci1yZWZyZXNoLXRva2VuLXNlY3JldA==
JWT_REFRESH_EXPIRES_IN: MzBk
# ── AWS S3 / MinIO ──
AWS_ACCESS_KEY_ID: dUE3V3ZUOWZoeWRjb3p5ejVhbG8=
AWS_SECRET_ACCESS_KEY: QXVzRXk2S0txYW5RUVUzWnczclhZQmFpUzVCTThhUG9BS2ZwY2JGcg==
AWS_REGION: dXMtZWFzdC0x
AWS_S3_BUCKET: ZS1jb21tZXJjZQ==
AWS_ENDPOINT: czMuc2FoYXNyYXJhbWV0YS50ZWNo
# ── Email ──
EMAIL_USER: dmFpYmhhdi5zYWhhc3JhcmFAZ21haWwuY29t
EMAIL_PASS: cGV6amN4Zm5lZ2d1emt1aA==
# ── Paytm payment gateway ──
PAYTM_MERCHANT_ID: eW91cl9tZXJjaGFudF9pZA==
PAYTM_MERCHANT_KEY: YWJjZDEyMzRhYmNkMTIzNA==
PAYTM_WEBSITE: V0VCU1RBR0lORw==
PAYTM_HOST: c2VjdXJlZ3ctc3RhZ2UucGF5dG0uaW4=
PAYTM_CALLBACK_URL: aHR0cDovL2xvY2FsaG9zdDozMDAwL2FwaS9wYXltZW50cy9wYXl0bS9jYWxsYmFjaw==
# ── Postgres init credentials (used by the StatefulSet) ──
POSTGRES_USER: dmFpc2huYXZp
POSTGRES_PASSWORD: YWRtaW4=
POSTGRES_DB: dmFpc2huYXZpX2Ri

View File

@@ -1,13 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: ecommerce-app
namespace: ecommerce
spec:
type: ClusterIP
selector:
app: ecommerce-app
ports:
- name: http
port: 80
targetPort: 3000

View File

@@ -1,28 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: ecommerce
resources:
- ../../base
images:
- name: ecommerce-backend
newName: 192.168.108.200:80/vaishnavi-ecommerce/ecommerce-backend
newTag: latest # Jenkins will patch this via: kustomize edit set image
patches:
- path: patches/deployment-patch.yaml
target:
kind: Deployment
name: ecommerce-app
# apiVersion: kustomize.config.k8s.io/v1beta1
# kind: Kustomization
# namespace: ecommerce
# resources:
# - ../../base
# images:
# - name: ecommerce-backend
# newName: ecommerce-backend
# newTag: latest
# patches:
# - path: patches/deployment-patch.yaml
# target:
# kind: Deployment
# name: ecommerce-app

View File

@@ -1,33 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ecommerce-app
namespace: ecommerce
spec:
replicas: 1
template:
spec:
initContainers:
- name: run-migrations
imagePullPolicy: Always
# imagePullSecrets are set at pod level below
containers:
- name: ecommerce-app
imagePullPolicy: Always
imagePullSecrets:
- name: harbor-registry-secret # kubectl create secret docker-registry harbor-registry-secret ...
# apiVersion: apps/v1
# kind: Deployment
# metadata:
# name: ecommerce-app
# namespace: ecommerce
# spec:
# template:
# spec:
# initContainers:
# - name: run-migrations
# imagePullPolicy: Never
# containers:
# - name: ecommerce-app
# imagePullPolicy: Never

View File

@@ -0,0 +1,49 @@
# Minikube backend patches — single replica, reduced resources, NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ecommerce-app
namespace: ecommerce
spec:
replicas: 1
template:
spec:
containers:
- name: ecommerce-app
# Never pull — use minikube's local Docker daemon image
imagePullPolicy: Never
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
---
apiVersion: v1
kind: Service
metadata:
name: ecommerce-app
namespace: ecommerce
spec:
type: NodePort
ports:
- port: 80
targetPort: 3000
nodePort: 30080
protocol: TCP
name: http
---
# Migration job also needs imagePullPolicy: Never
apiVersion: batch/v1
kind: Job
metadata:
name: prisma-migrate
namespace: ecommerce
spec:
template:
spec:
containers:
- name: migrate
imagePullPolicy: Never

View File

@@ -0,0 +1,17 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: ecommerce
# ── Use locally built image (minikube docker-env) ──
images:
- name: ecommerce-backend
newName: ecommerce-backend
newTag: minikube
# ── Patches ──
patches:
- path: backend-patch.yaml

View File

@@ -0,0 +1,36 @@
# On-premise backend patches
# Adjust replicas, resource limits, and expose via NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ecommerce-app
namespace: ecommerce
spec:
replicas: 2
template:
spec:
containers:
- name: ecommerce-app
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "2"
memory: 2Gi
---
# Expose the backend as a NodePort for on-premise access
apiVersion: v1
kind: Service
metadata:
name: ecommerce-app
namespace: ecommerce
spec:
type: NodePort
ports:
- port: 80
targetPort: 3000
nodePort: 30080
protocol: TCP
name: http

View File

@@ -0,0 +1,19 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: ecommerce
# ── Image overrides ──
# Jenkins will run: kustomize edit set image ecommerce-backend=<HARBOR_IMAGE>:<TAG>
images:
- name: ecommerce-backend
newName: 192.168.108.200:80/vaishnavi-ecommerce/ecommerce-backend
newTag: latest
# ── Strategic-merge patches ──
patches:
- path: backend-patch.yaml
- path: secrets-patch.yaml

View File

@@ -0,0 +1,42 @@
apiVersion: v1
kind: Secret
metadata:
name: ecommerce-secrets
namespace: ecommerce
type: Opaque
data:
# ── Override secrets for on-premise ──
# Update these values for your on-premise environment.
# echo -n 'value' | base64
# postgresql://vaishnavi:admin@postgres:5432/vaishnavi_db?schema=public
DATABASE_URL: cG9zdGdyZXNxbDovL3ZhaXNobmF2aTphZG1pbkBwb3N0Z3Jlczo1NDMyL3ZhaXNobmF2aV9kYj9zY2hlbWE9cHVibGlj
# JWT
JWT_SECRET: eW91ci1zdXBlci1zZWNyZXQtand0LWtleS1jaGFuZ2UtdGhpcy1pbi1wcm9kdWN0aW9u
JWT_EXPIRES_IN: N2Q=
JWT_REFRESH_SECRET: eW91ci1yZWZyZXNoLXRva2VuLXNlY3JldA==
JWT_REFRESH_EXPIRES_IN: MzBk
# AWS S3 / MinIO
AWS_ACCESS_KEY_ID: dUE3V3ZUOWZoeWRjb3p5ejVhbG8=
AWS_SECRET_ACCESS_KEY: QXVzRXk2S0txYW5RUVUzWnczclhZQmFpUzVCTThhUG9BS2ZwY2JGcg==
AWS_REGION: dXMtZWFzdC0x
AWS_S3_BUCKET: ZS1jb21tZXJjZQ==
AWS_ENDPOINT: czMuc2FoYXNyYXJhbWV0YS50ZWNo
# Email
EMAIL_USER: dmFpYmhhdi5zYWhhc3JhcmFAZ21haWwuY29t
EMAIL_PASS: cGV6amN4Zm5lZ2d1emt1aA==
# Paytm
PAYTM_MERCHANT_ID: eW91cl9tZXJjaGFudF9pZA==
PAYTM_MERCHANT_KEY: YWJjZDEyMzRhYmNkMTIzNA==
PAYTM_WEBSITE: V0VCU1RBR0lORw==
PAYTM_HOST: c2VjdXJlZ3ctc3RhZ2UucGF5dG0uaW4=
PAYTM_CALLBACK_URL: aHR0cDovL2xvY2FsaG9zdDozMDAwL2FwaS9wYXltZW50cy9wYXl0bS9jYWxsYmFjaw==
# Postgres init credentials
POSTGRES_USER: dmFpc2huYXZp
POSTGRES_PASSWORD: YWRtaW4=
POSTGRES_DB: dmFpc2huYXZpX2Ri

View File

@@ -74,7 +74,7 @@ async function main() {
for (const categoryData of categories) {
await prisma.category.upsert({
where: { slug: categoryData.slug },
where: { unique_slug_per_parent: { slug: categoryData.slug, parentId: null } },
update: {},
create: categoryData,
});