Skip to content

Phase 05: MeghRaj Deployment

Duration: 1 week Goal: Deploy Legacy ERP WMS to NIC MeghRaj 2.0 cloud


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ MeghRaj NC-CaaS (Container Service) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Ingress (Load Balancer) β”‚
β”‚ β”‚ β”‚
β”‚ β”œβ”€β”€ /api/* ────▢ Legacy ERP-WMS API (3 replicas) β”‚
β”‚ β”œβ”€β”€ /book-keeper/* ──▢ Book-Keeper (2 replicas) β”‚
β”‚ └── /* ────▢ Frontend (Nginx, 2 replicas) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Internal Services β”‚
β”‚ β”œβ”€β”€ Redis (1 replica) β”‚
β”‚ └── NATS (3 replicas, if needed) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ MeghRaj Database Server (PaaS) β”‚
β”‚ └── PostgreSQL 15 β”‚
β”‚ β”œβ”€β”€ legacy_erp_wms (main database) β”‚
β”‚ └── book_keeper (ledger database) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Register for MeghRaj NC-CaaS
  • Request PostgreSQL Database Server
  • Request Container quota (vCPU, Memory, Storage)

Dockerfile.api
FROM python:3.12-slim AS builder
WORKDIR /app
# Install uv
RUN pip install uv
# Copy dependency files
COPY pyproject.toml uv.lock ./
COPY libs/framework-m ./libs/framework-m
COPY apps/legacy_erp_wms ./apps/legacy_erp_wms
# Install dependencies
RUN uv sync --no-dev
# Production image
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /app/.venv /app/.venv
COPY --from=builder /app/libs /app/libs
COPY --from=builder /app/apps /app/apps
ENV PATH="/app/.venv/bin:$PATH"
ENV PYTHONPATH="/app/apps/legacy_erp_wms/src:/app/libs/framework-m/src"
EXPOSE 8000
CMD ["uvicorn", "legacy_erp_wms.main:app", "--host", "0.0.0.0", "--port", "8000"]
Dockerfile.frontend
FROM node:20-alpine AS builder
WORKDIR /app
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
  • Build API image
  • Build Frontend image
  • Push to MeghRaj registry (git.cloud.gov.in)
  • Tag images with version

k8s/api-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: legacy_erp-wms-api
spec:
replicas: 3
selector:
matchLabels:
app: legacy_erp-wms-api
template:
metadata:
labels:
app: legacy_erp-wms-api
spec:
containers:
- name: api
image: git.cloud.gov.in/legacy_erp/wms-api:v1.0.0
ports:
- containerPort: 8000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: legacy_erp-wms-secrets
key: database-url
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: legacy_erp-wms-secrets
key: redis-url
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: legacy_erp-wms-secrets
key: secret-key
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 5
periodSeconds: 10
k8s/api-service.yaml
apiVersion: v1
kind: Service
metadata:
name: legacy_erp-wms-api
spec:
selector:
app: legacy_erp-wms-api
ports:
- port: 80
targetPort: 8000
---
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: legacy_erp-wms-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: legacy_erp-wms.cloud.gov.in
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: legacy_erp-wms-api
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: legacy_erp-wms-frontend
port:
number: 80
# k8s/secrets.yaml (template - use sealed secrets or vault in prod)
apiVersion: v1
kind: Secret
metadata:
name: legacy_erp-wms-secrets
type: Opaque
stringData:
database-url: "postgresql+asyncpg://legacy_erp:PASSWORD@db-server:5432/legacy_erp_wms"
redis-url: "redis://redis:6379"
secret-key: "CHANGE_ME_IN_PRODUCTION"
book-keeper-url: "http://book-keeper:8000"
  • Create deployment manifests
  • Create service manifests
  • Create ingress configuration
  • Create secrets (sealed)
  • Redis deployment manifest
  • Book-Keeper deployment manifest

-- Run on MeghRaj Database Server
-- Create databases
CREATE DATABASE legacy_erp_wms;
CREATE DATABASE book_keeper;
-- Create users
CREATE USER legacy_erp_app WITH PASSWORD 'secure_password';
CREATE USER book_keeper_app WITH PASSWORD 'secure_password';
-- Grant permissions
GRANT ALL PRIVILEGES ON DATABASE legacy_erp_wms TO legacy_erp_app;
GRANT ALL PRIVILEGES ON DATABASE book_keeper TO book_keeper_app;
-- Extensions
\c legacy_erp_wms
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
\c book_keeper
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
  • Request PostgreSQL instance from MeghRaj
  • Create databases
  • Run migrations
  • Seed initial data

.gitlab-ci.yml
stages:
- test
- build
- deploy
variables:
REGISTRY: git.cloud.gov.in
API_IMAGE: $REGISTRY/legacy_erp/wms-api
FRONTEND_IMAGE: $REGISTRY/legacy_erp/wms-frontend
test:
stage: test
image: python:3.12
script:
- pip install uv
- uv sync
- uv run pytest --cov
coverage: '/TOTAL.*\s+(\d+%)/'
build-api:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -f Dockerfile.api -t $API_IMAGE:$CI_COMMIT_SHA .
- docker push $API_IMAGE:$CI_COMMIT_SHA
only:
- main
- tags
build-frontend:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -f Dockerfile.frontend -t $FRONTEND_IMAGE:$CI_COMMIT_SHA .
- docker push $FRONTEND_IMAGE:$CI_COMMIT_SHA
only:
- main
- tags
deploy-staging:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/legacy_erp-wms-api api=$API_IMAGE:$CI_COMMIT_SHA
- kubectl rollout status deployment/legacy_erp-wms-api
environment:
name: staging
only:
- main
deploy-production:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/legacy_erp-wms-api api=$API_IMAGE:$CI_COMMIT_TAG
- kubectl rollout status deployment/legacy_erp-wms-api
environment:
name: production
when: manual
only:
- tags
  • Configure GitLab CI
  • Set up Docker registry access
  • Configure kubectl access to MeghRaj
  • Test pipeline end-to-end

# In main.py
@app.get("/health")
async def health_check():
"""Liveness probe."""
return {"status": "healthy"}
@app.get("/ready")
async def readiness_check(db: AsyncSession = Depends(get_session)):
"""Readiness probe - checks DB connection."""
try:
await db.execute(text("SELECT 1"))
return {"status": "ready"}
except Exception:
raise HTTPException(status_code=503, detail="Database not ready")
logging_config.py
import logging
import sys
def setup_logging():
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(sys.stdout)
]
)
  • Add health/ready endpoints
  • Configure structured logging
  • Set up MeghRaj APM (if available)
  • Configure alerts

  • All secrets in K8s secrets (not env vars in manifest)
  • Database credentials rotated
  • HTTPS enforced via ingress
  • Network policies restricting pod-to-pod traffic
  • No root containers
  • Image scanning enabled
  • CORS configured properly
  • Rate limiting on APIs

  • All pods running and healthy
  • Database migrations applied
  • API accessible via ingress
  • Frontend loads correctly
  • Login flow works
  • Stock operations work end-to-end
  • Book-Keeper integration working
  • Load test with 100 concurrent users
  • Rollback tested