From c744d87016e26e3da5c17428ff17f772c204209d Mon Sep 17 00:00:00 2001 From: tusuii Date: Tue, 24 Feb 2026 22:06:14 +0530 Subject: [PATCH] minikube working --- Jenkinsfile | 79 +++++++- env-backend.txt | 46 +++++ k8s/base/backend.yaml | 178 ++++++++++++++++++ k8s/base/configmap.yaml | 34 ++-- k8s/base/deployment.yaml | 87 --------- k8s/base/ingress.yaml | 21 --- k8s/base/kustomization.yaml | 30 ++- k8s/base/migration-job.yaml | 58 ++++++ k8s/base/mongodb-pvc.yaml | 11 -- k8s/base/mongodb-service.yaml | 12 -- k8s/base/mongodb-statefulset.yaml | 53 ------ k8s/base/mongodb.yaml | 81 ++++++++ k8s/base/namespace.yaml | 11 +- k8s/base/postgres-pvc.yaml | 11 -- k8s/base/postgres-service.yaml | 12 -- k8s/base/postgres-statefulset.yaml | 59 ------ k8s/base/postgres.yaml | 99 ++++++++++ k8s/base/redis.yaml | 63 +++++++ k8s/base/secrets.yaml | 47 +++++ k8s/base/service.yaml | 13 -- k8s/overlays/local/kustomization.yaml | 28 --- .../local/patches/deployment-patch.yaml | 33 ---- k8s/overlays/minikube/backend-patch.yaml | 49 +++++ k8s/overlays/minikube/kustomization.yaml | 17 ++ k8s/overlays/on-premise/backend-patch.yaml | 36 ++++ k8s/overlays/on-premise/kustomization.yaml | 19 ++ k8s/overlays/on-premise/secrets-patch.yaml | 42 +++++ 27 files changed, 839 insertions(+), 390 deletions(-) create mode 100644 env-backend.txt create mode 100644 k8s/base/backend.yaml delete mode 100644 k8s/base/deployment.yaml delete mode 100644 k8s/base/ingress.yaml create mode 100644 k8s/base/migration-job.yaml delete mode 100644 k8s/base/mongodb-pvc.yaml delete mode 100644 k8s/base/mongodb-service.yaml delete mode 100644 k8s/base/mongodb-statefulset.yaml create mode 100644 k8s/base/mongodb.yaml delete mode 100644 k8s/base/postgres-pvc.yaml delete mode 100644 k8s/base/postgres-service.yaml delete mode 100644 k8s/base/postgres-statefulset.yaml create mode 100644 k8s/base/postgres.yaml create mode 100644 k8s/base/redis.yaml create mode 100644 k8s/base/secrets.yaml delete mode 100644 k8s/base/service.yaml delete mode 100644 k8s/overlays/local/kustomization.yaml delete mode 100644 k8s/overlays/local/patches/deployment-patch.yaml create mode 100644 k8s/overlays/minikube/backend-patch.yaml create mode 100644 k8s/overlays/minikube/kustomization.yaml create mode 100644 k8s/overlays/on-premise/backend-patch.yaml create mode 100644 k8s/overlays/on-premise/kustomization.yaml create mode 100644 k8s/overlays/on-premise/secrets-patch.yaml diff --git a/Jenkinsfile b/Jenkinsfile index 7407d17..5133ed5 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -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." diff --git a/env-backend.txt b/env-backend.txt new file mode 100644 index 0000000..3a1f310 --- /dev/null +++ b/env-backend.txt @@ -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 diff --git a/k8s/base/backend.yaml b/k8s/base/backend.yaml new file mode 100644 index 0000000..b8ed5ff --- /dev/null +++ b/k8s/base/backend.yaml @@ -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 diff --git a/k8s/base/configmap.yaml b/k8s/base/configmap.yaml index 68f50f9..51a7ba5 100644 --- a/k8s/base/configmap.yaml +++ b/k8s/base/configmap.yaml @@ -1,21 +1,13 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: app-config - namespace: 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" +apiVersion: v1 +kind: ConfigMap +metadata: + name: ecommerce-config + namespace: ecommerce + labels: + app.kubernetes.io/part-of: ecommerce +data: + NODE_ENV: "production" + PORT: "3000" + HOST: "0.0.0.0" + 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" diff --git a/k8s/base/deployment.yaml b/k8s/base/deployment.yaml deleted file mode 100644 index 43355bd..0000000 --- a/k8s/base/deployment.yaml +++ /dev/null @@ -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: {} diff --git a/k8s/base/ingress.yaml b/k8s/base/ingress.yaml deleted file mode 100644 index f8ee834..0000000 --- a/k8s/base/ingress.yaml +++ /dev/null @@ -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 diff --git a/k8s/base/kustomization.yaml b/k8s/base/kustomization.yaml index 7995e6c..2c0b1b3 100644 --- a/k8s/base/kustomization.yaml +++ b/k8s/base/kustomization.yaml @@ -1,16 +1,14 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -namespace: ecommerce -resources: - - namespace.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 +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: ecommerce + +resources: + - namespace.yaml + - secrets.yaml + - configmap.yaml + - postgres.yaml + - mongodb.yaml + - redis.yaml + - migration-job.yaml + - backend.yaml diff --git a/k8s/base/migration-job.yaml b/k8s/base/migration-job.yaml new file mode 100644 index 0000000..8813b06 --- /dev/null +++ b/k8s/base/migration-job.yaml @@ -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 diff --git a/k8s/base/mongodb-pvc.yaml b/k8s/base/mongodb-pvc.yaml deleted file mode 100644 index a191dd1..0000000 --- a/k8s/base/mongodb-pvc.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: mongodb-data - namespace: ecommerce -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 5Gi diff --git a/k8s/base/mongodb-service.yaml b/k8s/base/mongodb-service.yaml deleted file mode 100644 index c9af8f4..0000000 --- a/k8s/base/mongodb-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: mongodb - namespace: ecommerce -spec: - type: ClusterIP - selector: - app: mongodb - ports: - - port: 27017 - targetPort: 27017 diff --git a/k8s/base/mongodb-statefulset.yaml b/k8s/base/mongodb-statefulset.yaml deleted file mode 100644 index 9886ba4..0000000 --- a/k8s/base/mongodb-statefulset.yaml +++ /dev/null @@ -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 diff --git a/k8s/base/mongodb.yaml b/k8s/base/mongodb.yaml new file mode 100644 index 0000000..3af1b25 --- /dev/null +++ b/k8s/base/mongodb.yaml @@ -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 diff --git a/k8s/base/namespace.yaml b/k8s/base/namespace.yaml index 0c996fc..5cc5c62 100644 --- a/k8s/base/namespace.yaml +++ b/k8s/base/namespace.yaml @@ -1,4 +1,7 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: ecommerce +apiVersion: v1 +kind: Namespace +metadata: + name: ecommerce + labels: + app.kubernetes.io/part-of: ecommerce + app.kubernetes.io/managed-by: kustomize diff --git a/k8s/base/postgres-pvc.yaml b/k8s/base/postgres-pvc.yaml deleted file mode 100644 index f322106..0000000 --- a/k8s/base/postgres-pvc.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres-data - namespace: ecommerce -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 5Gi diff --git a/k8s/base/postgres-service.yaml b/k8s/base/postgres-service.yaml deleted file mode 100644 index 06951d8..0000000 --- a/k8s/base/postgres-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: postgres - namespace: ecommerce -spec: - type: ClusterIP - selector: - app: postgres - ports: - - port: 5432 - targetPort: 5432 diff --git a/k8s/base/postgres-statefulset.yaml b/k8s/base/postgres-statefulset.yaml deleted file mode 100644 index efb3e6a..0000000 --- a/k8s/base/postgres-statefulset.yaml +++ /dev/null @@ -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 diff --git a/k8s/base/postgres.yaml b/k8s/base/postgres.yaml new file mode 100644 index 0000000..1d99dfd --- /dev/null +++ b/k8s/base/postgres.yaml @@ -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 diff --git a/k8s/base/redis.yaml b/k8s/base/redis.yaml new file mode 100644 index 0000000..40b9a78 --- /dev/null +++ b/k8s/base/redis.yaml @@ -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 diff --git a/k8s/base/secrets.yaml b/k8s/base/secrets.yaml new file mode 100644 index 0000000..53f7667 --- /dev/null +++ b/k8s/base/secrets.yaml @@ -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 diff --git a/k8s/base/service.yaml b/k8s/base/service.yaml deleted file mode 100644 index 2c95e36..0000000 --- a/k8s/base/service.yaml +++ /dev/null @@ -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 diff --git a/k8s/overlays/local/kustomization.yaml b/k8s/overlays/local/kustomization.yaml deleted file mode 100644 index d1ae579..0000000 --- a/k8s/overlays/local/kustomization.yaml +++ /dev/null @@ -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 diff --git a/k8s/overlays/local/patches/deployment-patch.yaml b/k8s/overlays/local/patches/deployment-patch.yaml deleted file mode 100644 index 228852b..0000000 --- a/k8s/overlays/local/patches/deployment-patch.yaml +++ /dev/null @@ -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 diff --git a/k8s/overlays/minikube/backend-patch.yaml b/k8s/overlays/minikube/backend-patch.yaml new file mode 100644 index 0000000..c5b2056 --- /dev/null +++ b/k8s/overlays/minikube/backend-patch.yaml @@ -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 diff --git a/k8s/overlays/minikube/kustomization.yaml b/k8s/overlays/minikube/kustomization.yaml new file mode 100644 index 0000000..154cd16 --- /dev/null +++ b/k8s/overlays/minikube/kustomization.yaml @@ -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 diff --git a/k8s/overlays/on-premise/backend-patch.yaml b/k8s/overlays/on-premise/backend-patch.yaml new file mode 100644 index 0000000..267584c --- /dev/null +++ b/k8s/overlays/on-premise/backend-patch.yaml @@ -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 diff --git a/k8s/overlays/on-premise/kustomization.yaml b/k8s/overlays/on-premise/kustomization.yaml new file mode 100644 index 0000000..5029e91 --- /dev/null +++ b/k8s/overlays/on-premise/kustomization.yaml @@ -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=: +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 diff --git a/k8s/overlays/on-premise/secrets-patch.yaml b/k8s/overlays/on-premise/secrets-patch.yaml new file mode 100644 index 0000000..860b1b7 --- /dev/null +++ b/k8s/overlays/on-premise/secrets-patch.yaml @@ -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