added k8s files and jenkinsfile
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
FROM node:20-bullseye-slim
|
FROM mirror.gcr.io/library/node:20-bullseye-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
130
Jenkinsfile
vendored
Normal file
130
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
|
||||||
|
parameters {
|
||||||
|
string(
|
||||||
|
name: 'NODE_IP',
|
||||||
|
defaultValue: '192.168.108.200',
|
||||||
|
description: 'On-premise Kubernetes node IP'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
environment {
|
||||||
|
HARBOR = '192.168.108.200:80'
|
||||||
|
IMAGE = '192.168.108.200:80/vaishnavi-ecommerce/backend'
|
||||||
|
OLD_IMAGE = '192.168.49.2:30004/vaishnavi-ecommerce/backend:latest'
|
||||||
|
TAG = "${env.BUILD_NUMBER}"
|
||||||
|
NAMESPACE = 'ecommerce'
|
||||||
|
K8S_DIR = 'k8s/backend'
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Build Image') {
|
||||||
|
steps {
|
||||||
|
sh "docker build -t ${IMAGE}:${TAG} -t ${IMAGE}:latest ."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Push to Harbor') {
|
||||||
|
steps {
|
||||||
|
withCredentials([usernamePassword(
|
||||||
|
credentialsId: 'harbor-credentials',
|
||||||
|
usernameVariable: 'HARBOR_USER',
|
||||||
|
passwordVariable: 'HARBOR_PASS'
|
||||||
|
)]) {
|
||||||
|
sh """
|
||||||
|
echo "\$HARBOR_PASS" | docker login ${HARBOR} -u "\$HARBOR_USER" --password-stdin
|
||||||
|
docker push ${IMAGE}:${TAG}
|
||||||
|
docker push ${IMAGE}:latest
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Apply Namespace') {
|
||||||
|
steps {
|
||||||
|
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
|
||||||
|
sh "kubectl apply -f ${K8S_DIR}/00-namespace.yaml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Apply ConfigMap') {
|
||||||
|
steps {
|
||||||
|
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
|
||||||
|
sh """
|
||||||
|
sed "s/NODE_IP_PLACEHOLDER/${params.NODE_IP}/g" \
|
||||||
|
${K8S_DIR}/configmap.yaml | kubectl apply -f -
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Apply Secret') {
|
||||||
|
steps {
|
||||||
|
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
|
||||||
|
sh "kubectl apply -f ${K8S_DIR}/secret.yaml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Run Migration') {
|
||||||
|
steps {
|
||||||
|
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
|
||||||
|
sh """
|
||||||
|
kubectl delete job backend-migration -n ${NAMESPACE} --ignore-not-found=true
|
||||||
|
|
||||||
|
sed "s|${OLD_IMAGE}|${IMAGE}:${TAG}|g" \
|
||||||
|
${K8S_DIR}/migration-job.yaml | kubectl apply -f -
|
||||||
|
|
||||||
|
kubectl wait --for=condition=complete job/backend-migration \
|
||||||
|
-n ${NAMESPACE} --timeout=120s
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Deploy Backend') {
|
||||||
|
steps {
|
||||||
|
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
|
||||||
|
sh """
|
||||||
|
sed "s|${OLD_IMAGE}|${IMAGE}:${TAG}|g" \
|
||||||
|
${K8S_DIR}/deployment.yaml | kubectl apply -f -
|
||||||
|
kubectl apply -f ${K8S_DIR}/service.yaml
|
||||||
|
kubectl apply -f ${K8S_DIR}/ingress.yaml
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Verify Rollout') {
|
||||||
|
steps {
|
||||||
|
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
|
||||||
|
sh "kubectl rollout status deployment/backend -n ${NAMESPACE} --timeout=180s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Smoke Test') {
|
||||||
|
steps {
|
||||||
|
sh "curl -f http://${params.NODE_IP}:30080/health"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
sh "docker rmi ${IMAGE}:${TAG} || true"
|
||||||
|
sh "docker rmi ${IMAGE}:latest || true"
|
||||||
|
}
|
||||||
|
success {
|
||||||
|
echo "Deploy successful. Backend accessible at http://${params.NODE_IP}:30080"
|
||||||
|
}
|
||||||
|
failure {
|
||||||
|
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
|
||||||
|
sh "kubectl get pods -n ${NAMESPACE} || true"
|
||||||
|
sh "kubectl describe deployment/backend -n ${NAMESPACE} || true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
k8s/backend/00-namespace.yaml
Normal file
4
k8s/backend/00-namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: ecommerce
|
||||||
25
k8s/backend/configmap.yaml
Normal file
25
k8s/backend/configmap.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: backend-configmap
|
||||||
|
namespace: ecommerce
|
||||||
|
data:
|
||||||
|
NODE_ENV: "production"
|
||||||
|
PORT: "3000"
|
||||||
|
SEND_REAL_WHATSAPP: "false"
|
||||||
|
MONGODB_URI: "mongodb://mongodb.database.svc.cluster.local:27017/vaishnavi_products"
|
||||||
|
REDIS_URL: "redis://redis.database.svc.cluster.local:6379"
|
||||||
|
AWS_REGION: "us-east-1"
|
||||||
|
AWS_S3_BUCKET: "e-commerce"
|
||||||
|
AWS_ENDPOINT: "s3.sahasrarameta.tech"
|
||||||
|
AWS_PORT: "443"
|
||||||
|
AWS_SSL: "true"
|
||||||
|
JWT_EXPIRES_IN: "7d"
|
||||||
|
JWT_REFRESH_EXPIRES_IN: "30d"
|
||||||
|
FRONTEND_URL: "http://NODE_IP_PLACEHOLDER:30081"
|
||||||
|
CORS_ORIGIN: "http://NODE_IP_PLACEHOLDER:30081,http://NODE_IP_PLACEHOLDER:30082,https://vaishnavi-admin.myriadcara.in,https://vaishnavi-bakend.myriadcara.in,https://vaishnavi-test.myriadcara.in"
|
||||||
|
PAYTM_WEBSITE: "WEBSTAGING"
|
||||||
|
PAYTM_HOST: "securegw-stage.paytm.in"
|
||||||
|
PAYTM_CALLBACK_URL: "http://NODE_IP_PLACEHOLDER:30080/api/payments/paytm/callback"
|
||||||
|
WAPP_BASE_URL: "https://api.wappconnect.com"
|
||||||
|
WAPP_INSTANCE: "SSM"
|
||||||
45
k8s/backend/deployment.yaml
Normal file
45
k8s/backend/deployment.yaml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: backend
|
||||||
|
namespace: ecommerce
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: backend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: backend
|
||||||
|
image: 192.168.49.2:30004/vaishnavi-ecommerce/backend:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
ports:
|
||||||
|
- containerPort: 3000
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: backend-configmap
|
||||||
|
- secretRef:
|
||||||
|
name: backend-secret
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "250m"
|
||||||
|
memory: "256Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "500m"
|
||||||
|
memory: "512Mi"
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 3000
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 15
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 3000
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
20
k8s/backend/ingress.yaml
Normal file
20
k8s/backend/ingress.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: backend-ingress
|
||||||
|
namespace: ecommerce
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
rules:
|
||||||
|
- host: backend.local
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: backend
|
||||||
|
port:
|
||||||
|
number: 3000
|
||||||
22
k8s/backend/migration-job.yaml
Normal file
22
k8s/backend/migration-job.yaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: backend-migration
|
||||||
|
namespace: ecommerce
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: migration
|
||||||
|
image: 192.168.49.2:30004/vaishnavi-ecommerce/backend:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
command:
|
||||||
|
- npx
|
||||||
|
- prisma
|
||||||
|
- db
|
||||||
|
- push
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: backend-secret
|
||||||
|
restartPolicy: Never
|
||||||
|
backoffLimit: 3
|
||||||
17
k8s/backend/secret.yaml
Normal file
17
k8s/backend/secret.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: backend-secret
|
||||||
|
namespace: ecommerce
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
DATABASE_URL: cG9zdGdyZXNxbDovL3ZhaXNobmF2aTphZG1pbkBwb3N0Z3Jlcy5kYXRhYmFzZS5zdmMuY2x1c3Rlci5sb2NhbDo1NDMyL3ZhaXNobmF2aV9kYj9zY2hlbWE9cHVibGlj
|
||||||
|
JWT_SECRET: eW91ci1zdXBlci1zZWNyZXQtand0LWtleS1jaGFuZ2UtdGhpcy1pbi1wcm9kdWN0aW9u
|
||||||
|
JWT_REFRESH_SECRET: eW91ci1yZWZyZXNoLXRva2VuLXNlY3JldA==
|
||||||
|
AWS_ACCESS_KEY_ID: dUE3V3ZUOWZoeWRjb3p5ejVhbG8=
|
||||||
|
AWS_SECRET_ACCESS_KEY: QXVzRXk2S0txYW5RUVUzWnczclhZQmFpUzVCTThhUG9BS2ZwY2JGcg==
|
||||||
|
EMAIL_USER: dmFpYmhhdi5zYWhhc3JhcmFAZ21haWwuY29t
|
||||||
|
EMAIL_PASS: cGV6amN4Zm5lZ2d1emt1aA==
|
||||||
|
PAYTM_MERCHANT_ID: eW91cl9tZXJjaGFudF9pZA==
|
||||||
|
PAYTM_MERCHANT_KEY: YWJjZDEyMzRhYmNkMTIzNA==
|
||||||
|
WAPP_TOKEN: Y2x6Z2t0emRiYXdzNW1nZHU3c3M1YTRyYQ==
|
||||||
13
k8s/backend/service.yaml
Normal file
13
k8s/backend/service.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: backend
|
||||||
|
namespace: ecommerce
|
||||||
|
spec:
|
||||||
|
type: NodePort
|
||||||
|
selector:
|
||||||
|
app: backend
|
||||||
|
ports:
|
||||||
|
- port: 3000
|
||||||
|
targetPort: 3000
|
||||||
|
nodePort: 30080
|
||||||
4
k8s/database/00-namespace.yaml
Normal file
4
k8s/database/00-namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: database
|
||||||
218
k8s/database/DATABASE-SETUP.md
Normal file
218
k8s/database/DATABASE-SETUP.md
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
# Database Namespace — Setup & On-Premise Replication Guide
|
||||||
|
|
||||||
|
Covers PostgreSQL 16 and MongoDB 7 deployed in the `database` Kubernetes namespace.
|
||||||
|
Verified working on: **minikube** (local dev). On-premise steps are in [Section 4](#4-on-premise-replication).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. What's Deployed
|
||||||
|
|
||||||
|
| Resource | Namespace | Details |
|
||||||
|
|---|---|---|
|
||||||
|
| StatefulSet `postgres` | `database` | `postgres:16`, 1 replica, 5 Gi PVC |
|
||||||
|
| StatefulSet `mongodb` | `database` | `mongo:7`, 1 replica, 5 Gi PVC, no auth |
|
||||||
|
| Service `postgres` | `database` | ClusterIP, port 5432 |
|
||||||
|
| Service `mongodb` | `database` | ClusterIP, port 27017 |
|
||||||
|
| Secret `postgres-secret` | `database` | DB name, user, password, DATABASE_URL |
|
||||||
|
| PVC `postgres-pvc` | `database` | 5 Gi, ReadWriteOnce |
|
||||||
|
| PVC `mongodb-pvc` | `database` | 5 Gi, ReadWriteOnce |
|
||||||
|
| ConfigMap `tcp-services` | `ingress-nginx` | TCP passthrough for external PostgreSQL access |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Connection Strings
|
||||||
|
|
||||||
|
| Consumer | URL |
|
||||||
|
|---|---|
|
||||||
|
| Backend pod (in-cluster) | `postgresql://vaishnavi:admin@postgres.database.svc.cluster.local:5432/vaishnavi_db?schema=public` |
|
||||||
|
| Backend pod (in-cluster) | `mongodb://mongodb.database.svc.cluster.local:27017/vaishnavi_products` |
|
||||||
|
| External / pgAdmin (host) | `postgresql://vaishnavi:admin@postgres.local:5432/vaishnavi_db` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
k8s/database/
|
||||||
|
├── 00-namespace.yaml # database namespace
|
||||||
|
├── postgres-secret.yaml # base64-encoded credentials + DATABASE_URL
|
||||||
|
├── postgres-pvc.yaml # 5 Gi PVC
|
||||||
|
├── postgres-statefulset.yaml # postgres:16 StatefulSet
|
||||||
|
├── postgres-service.yaml # ClusterIP :5432
|
||||||
|
├── mongodb-pvc.yaml # 5 Gi PVC
|
||||||
|
├── mongodb-statefulset.yaml # mongo:7 StatefulSet, no auth
|
||||||
|
├── mongodb-service.yaml # ClusterIP :27017
|
||||||
|
└── nginx-tcp-configmap.yaml # TCP passthrough for postgres.local:5432
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. On-Premise Replication
|
||||||
|
|
||||||
|
### 4.1 Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes cluster (kubeadm, k3s, RKE2, or similar) with at least 1 worker node
|
||||||
|
- `kubectl` configured with cluster-admin rights
|
||||||
|
- A StorageClass that supports `ReadWriteOnce` PVCs
|
||||||
|
Common options:
|
||||||
|
- `local-path` (Rancher Local Path Provisioner — simplest for single-node)
|
||||||
|
- `longhorn` (multi-node HA storage)
|
||||||
|
- NFS provisioner
|
||||||
|
- Ingress-NGINX controller deployed (`kubectl get pods -n ingress-nginx`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.2 StorageClass: Install Local Path Provisioner (if needed)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
|
||||||
|
|
||||||
|
# Set as default if no other default exists
|
||||||
|
kubectl patch storageclass local-path \
|
||||||
|
-p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.3 Deploy the Databases
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd vaishnavi-ecommerce-backend/k8s/database
|
||||||
|
|
||||||
|
kubectl apply -f 00-namespace.yaml
|
||||||
|
kubectl apply -f postgres-secret.yaml
|
||||||
|
kubectl apply -f postgres-pvc.yaml
|
||||||
|
kubectl apply -f postgres-statefulset.yaml
|
||||||
|
kubectl apply -f postgres-service.yaml
|
||||||
|
kubectl apply -f mongodb-pvc.yaml
|
||||||
|
kubectl apply -f mongodb-statefulset.yaml
|
||||||
|
kubectl apply -f mongodb-service.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Wait for both pods to reach `Running`:
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n database -w
|
||||||
|
# Expected:
|
||||||
|
# mongodb-0 1/1 Running 0
|
||||||
|
# postgres-0 1/1 Running 0
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.4 External PostgreSQL Access via TCP Ingress (optional)
|
||||||
|
|
||||||
|
This lets you connect to PostgreSQL from outside the cluster using `postgres.local:5432`.
|
||||||
|
|
||||||
|
**Step 1 — Apply the TCP ConfigMap:**
|
||||||
|
```bash
|
||||||
|
kubectl apply -f nginx-tcp-configmap.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2 — Expose port 5432 on the ingress-nginx Service:**
|
||||||
|
```bash
|
||||||
|
kubectl patch svc ingress-nginx-controller -n ingress-nginx \
|
||||||
|
--type='json' \
|
||||||
|
-p='[{"op":"add","path":"/spec/ports/-","value":{"name":"postgres","port":5432,"targetPort":5432,"protocol":"TCP"}}]'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3 — Add `--tcp-services-configmap` arg to the ingress-nginx Deployment:**
|
||||||
|
```bash
|
||||||
|
kubectl patch deployment ingress-nginx-controller -n ingress-nginx \
|
||||||
|
--type='json' \
|
||||||
|
-p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--tcp-services-configmap=ingress-nginx/tcp-services"}]'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 4 — Add to `/etc/hosts` on every machine that needs external access:**
|
||||||
|
```
|
||||||
|
<NODE_IP> postgres.local
|
||||||
|
```
|
||||||
|
Replace `<NODE_IP>` with the IP of any cluster node (or load balancer IP if using MetalLB).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.5 Credentials / Secret Values
|
||||||
|
|
||||||
|
The secret values are baked into `postgres-secret.yaml`. To change them:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate new base64 values
|
||||||
|
echo -n "your_password" | base64
|
||||||
|
|
||||||
|
# Or use kubectl to create the secret directly (bypasses base64 manual encoding)
|
||||||
|
kubectl create secret generic postgres-secret \
|
||||||
|
--namespace=database \
|
||||||
|
--from-literal=POSTGRES_DB=vaishnavi_db \
|
||||||
|
--from-literal=POSTGRES_USER=vaishnavi \
|
||||||
|
--from-literal=POSTGRES_PASSWORD=admin \
|
||||||
|
--from-literal=DATABASE_URL="postgresql://vaishnavi:admin@postgres.database.svc.cluster.local:5432/vaishnavi_db?schema=public" \
|
||||||
|
--dry-run=client -o yaml > postgres-secret.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.6 Backend ConfigMap / Secret Reference
|
||||||
|
|
||||||
|
The backend reads DATABASE_URL and MONGODB_URI from its own configmap/secret in the `ecommerce` namespace. Ensure these point to the `database` namespace services:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
DATABASE_URL: postgresql://vaishnavi:admin@postgres.database.svc.cluster.local:5432/vaishnavi_db?schema=public
|
||||||
|
MONGODB_URI: mongodb://mongodb.database.svc.cluster.local:27017/vaishnavi_products
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Verification
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Both pods Running
|
||||||
|
kubectl get pods -n database
|
||||||
|
|
||||||
|
# PVCs Bound
|
||||||
|
kubectl get pvc -n database
|
||||||
|
|
||||||
|
# Services present
|
||||||
|
kubectl get svc -n database
|
||||||
|
|
||||||
|
# PostgreSQL accepting connections
|
||||||
|
kubectl exec -n database postgres-0 -- pg_isready -U vaishnavi -d vaishnavi_db
|
||||||
|
|
||||||
|
# PostgreSQL — list databases
|
||||||
|
kubectl exec -n database postgres-0 -- psql -U vaishnavi -d vaishnavi_db -c '\l'
|
||||||
|
|
||||||
|
# MongoDB ping
|
||||||
|
kubectl exec -n database mongodb-0 -- mongosh --eval "db.adminCommand('ping')" --quiet
|
||||||
|
|
||||||
|
# In-cluster connectivity test (PostgreSQL)
|
||||||
|
kubectl run psql-test --rm -it --image=postgres:16 --restart=Never -n database -- \
|
||||||
|
psql postgresql://vaishnavi:admin@postgres.database.svc.cluster.local:5432/vaishnavi_db -c '\l'
|
||||||
|
|
||||||
|
# In-cluster connectivity test (MongoDB)
|
||||||
|
kubectl run mongo-test --rm -it --image=mongo:7 --restart=Never -n database -- \
|
||||||
|
mongosh mongodb://mongodb.database.svc.cluster.local:27017/vaishnavi_products --eval "db.stats()"
|
||||||
|
|
||||||
|
# External PostgreSQL (after TCP ingress setup + /etc/hosts)
|
||||||
|
psql postgresql://vaishnavi:admin@postgres.local:5432/vaishnavi_db -c '\l'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Teardown
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Remove databases (data is lost when PVCs are deleted)
|
||||||
|
kubectl delete namespace database
|
||||||
|
|
||||||
|
# Remove TCP ingress config (if applied)
|
||||||
|
kubectl delete configmap tcp-services -n ingress-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
To preserve data before teardown, dump first:
|
||||||
|
```bash
|
||||||
|
# PostgreSQL dump
|
||||||
|
kubectl exec -n database postgres-0 -- \
|
||||||
|
pg_dump -U vaishnavi vaishnavi_db > vaishnavi_db_backup.sql
|
||||||
|
|
||||||
|
# MongoDB dump
|
||||||
|
kubectl exec -n database mongodb-0 -- \
|
||||||
|
mongodump --db vaishnavi_products --archive > vaishnavi_products_backup.archive
|
||||||
|
```
|
||||||
11
k8s/database/mongodb-pvc.yaml
Normal file
11
k8s/database/mongodb-pvc.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: mongodb-pvc
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
13
k8s/database/mongodb-service.yaml
Normal file
13
k8s/database/mongodb-service.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: mongodb
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: mongodb
|
||||||
|
ports:
|
||||||
|
- name: mongodb
|
||||||
|
port: 27017
|
||||||
|
targetPort: 27017
|
||||||
45
k8s/database/mongodb-statefulset.yaml
Normal file
45
k8s/database/mongodb-statefulset.yaml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: mongodb
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
serviceName: mongodb
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mongodb
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mongodb
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: mongodb
|
||||||
|
image: mongo:7
|
||||||
|
ports:
|
||||||
|
- containerPort: 27017
|
||||||
|
volumeMounts:
|
||||||
|
- name: mongodb-data
|
||||||
|
mountPath: /data/db
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- mongosh
|
||||||
|
- --eval
|
||||||
|
- "db.adminCommand('ping')"
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 6
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- mongosh
|
||||||
|
- --eval
|
||||||
|
- "db.adminCommand('ping')"
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
volumes:
|
||||||
|
- name: mongodb-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: mongodb-pvc
|
||||||
27
k8s/database/nginx-tcp-configmap.yaml
Normal file
27
k8s/database/nginx-tcp-configmap.yaml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: tcp-services
|
||||||
|
namespace: ingress-nginx
|
||||||
|
data:
|
||||||
|
"5432": "database/postgres:5432"
|
||||||
|
|
||||||
|
# ─── Manual one-time steps after applying this ConfigMap ─────────────────────
|
||||||
|
#
|
||||||
|
# 1. Expose port 5432 on the ingress-nginx-controller Service:
|
||||||
|
#
|
||||||
|
# kubectl patch svc ingress-nginx-controller -n ingress-nginx \
|
||||||
|
# --type='json' \
|
||||||
|
# -p='[{"op":"add","path":"/spec/ports/-","value":{"name":"postgres","port":5432,"targetPort":5432,"protocol":"TCP"}}]'
|
||||||
|
#
|
||||||
|
# 2. Add --tcp-services-configmap arg to the ingress-nginx-controller Deployment:
|
||||||
|
#
|
||||||
|
# kubectl patch deployment ingress-nginx-controller -n ingress-nginx \
|
||||||
|
# --type='json' \
|
||||||
|
# -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--tcp-services-configmap=ingress-nginx/tcp-services"}]'
|
||||||
|
#
|
||||||
|
# 3. Add to /etc/hosts on your host machine:
|
||||||
|
#
|
||||||
|
# 192.168.49.2 postgres.local
|
||||||
|
#
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
11
k8s/database/postgres-pvc.yaml
Normal file
11
k8s/database/postgres-pvc.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: postgres-pvc
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
11
k8s/database/postgres-secret.yaml
Normal file
11
k8s/database/postgres-secret.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: postgres-secret
|
||||||
|
namespace: database
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
POSTGRES_DB: dmFpc2huYXZpX2Ri # vaishnavi_db
|
||||||
|
POSTGRES_USER: dmFpc2huYXZp # vaishnavi
|
||||||
|
POSTGRES_PASSWORD: YWRtaW4= # admin
|
||||||
|
DATABASE_URL: cG9zdGdyZXNxbDovL3ZhaXNobmF2aTphZG1pbkBwb3N0Z3Jlcy5kYXRhYmFzZS5zdmMuY2x1c3Rlci5sb2NhbDo1NDMyL3ZhaXNobmF2aV9kYj9zY2hlbWE9cHVibGlj
|
||||||
13
k8s/database/postgres-service.yaml
Normal file
13
k8s/database/postgres-service.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: postgres
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
port: 5432
|
||||||
|
targetPort: 5432
|
||||||
67
k8s/database/postgres-statefulset.yaml
Normal file
67
k8s/database/postgres-statefulset.yaml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
serviceName: postgres
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: postgres
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: postgres
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
image: postgres:16
|
||||||
|
ports:
|
||||||
|
- containerPort: 5432
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgres-secret
|
||||||
|
key: POSTGRES_DB
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgres-secret
|
||||||
|
key: POSTGRES_USER
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgres-secret
|
||||||
|
key: POSTGRES_PASSWORD
|
||||||
|
- name: PGDATA
|
||||||
|
value: /var/lib/postgresql/data/pgdata
|
||||||
|
volumeMounts:
|
||||||
|
- name: postgres-data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- pg_isready
|
||||||
|
- -U
|
||||||
|
- $(POSTGRES_USER)
|
||||||
|
- -d
|
||||||
|
- $(POSTGRES_DB)
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 6
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- pg_isready
|
||||||
|
- -U
|
||||||
|
- $(POSTGRES_USER)
|
||||||
|
- -d
|
||||||
|
- $(POSTGRES_DB)
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
volumes:
|
||||||
|
- name: postgres-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: postgres-pvc
|
||||||
11
k8s/database/redis-pvc.yaml
Normal file
11
k8s/database/redis-pvc.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: redis-pvc
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Gi
|
||||||
12
k8s/database/redis-service.yaml
Normal file
12
k8s/database/redis-service.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: redis
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: redis
|
||||||
|
ports:
|
||||||
|
- port: 6379
|
||||||
|
targetPort: 6379
|
||||||
47
k8s/database/redis-statefulset.yaml
Normal file
47
k8s/database/redis-statefulset.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: redis
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
serviceName: redis
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: redis
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: redis
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: redis:7-alpine
|
||||||
|
command:
|
||||||
|
- redis-server
|
||||||
|
- --appendonly
|
||||||
|
- "yes"
|
||||||
|
ports:
|
||||||
|
- containerPort: 6379
|
||||||
|
volumeMounts:
|
||||||
|
- name: redis-data
|
||||||
|
mountPath: /data
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- redis-cli
|
||||||
|
- ping
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 6
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- redis-cli
|
||||||
|
- ping
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
volumes:
|
||||||
|
- name: redis-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: redis-pvc
|
||||||
Reference in New Issue
Block a user