Skip to main content

Kubernetes Deployment

Deploy EUDIPLO on Kubernetes with PostgreSQL and MinIO for production use.

Architecture

The Kubernetes deployment includes:

  • EUDIPLO Backend — Main application service (Node.js)
  • EUDIPLO Client — Web UI served by nginx
  • PostgreSQL — Relational database with persistent storage
  • MinIO — S3-compatible object storage
  • Ingress — HTTP routing with domain-based access

All components include:

  • ✅ Security contexts (non-root users)
  • ✅ Health probes (readiness, liveness, startup)
  • ✅ Resource limits (CPU/memory)
  • ✅ Persistent storage (StatefulSets with PVCs)

Prerequisites

Kubernetes Cluster

Enable Kubernetes in Docker Desktop:

  1. Open Docker Desktop → Settings → Kubernetes
  2. Check "Enable Kubernetes"
  3. Click "Apply & Restart"
  4. Wait for Kubernetes to start (green indicator)

Verify installation:

kubectl version --client
kubectl cluster-info

Install ingress-nginx Controller

Required for accessing services via domain names:

# Install ingress-nginx
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.1/deploy/static/provider/cloud/deploy.yaml

# Wait for it to be ready
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=120s

Configure Environment

cd deployment/k8s
cp .env.example .env

Edit .env:

# Public URL (for OAuth redirects and OIDC)
PUBLIC_URL=http://eudiplo.localtest.me

# PostgreSQL Configuration
DB_USERNAME=eudiplo
DB_PASSWORD=changeme123
DB_DATABASE=eudiplo

# MinIO Configuration
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin123
MINIO_BUCKET=uploads

# Application Secrets
MASTER_SECRET=your-secret-jwt-key-change-in-production
AUTH_CLIENT_ID=your-client-id
AUTH_CLIENT_SECRET=your-client-secret

# Logging
LOG_LEVEL=info
Security Alert

The demo credentials will trigger security warnings in the application logs. Always change these values for production deployments!

Deployment Steps

1. Create Namespace and Secret

# Create dedicated namespace
kubectl create namespace eudiplo

# Create Kubernetes secret from .env file
kubectl -n eudiplo create secret generic eudiplo-env --from-env-file=.env

2. Deploy All Resources

Using Kustomize (recommended):

kubectl apply -k .

Or apply individual manifests:

kubectl apply -f namespace.yaml
kubectl apply -f postgres-statefulset.yaml
kubectl apply -f postgres-service.yaml
kubectl apply -f minio-statefulset.yaml
kubectl apply -f minio-service.yaml
kubectl apply -f minio-bucket-job.yaml
kubectl apply -f eudiplo-deployment.yaml
kubectl apply -f eudiplo-service.yaml
kubectl apply -f eudiplo-client-deployment.yaml
kubectl apply -f eudiplo-client-service.yaml
kubectl apply -f ingress.yaml

3. Verify Deployment

Check all resources:

kubectl -n eudiplo get all

Watch pods until all are Running:

kubectl -n eudiplo get pods -w

Expected output (all Running/Completed):

NAME READY STATUS RESTARTS AGE
pod/eudiplo-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
pod/eudiplo-client-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
pod/postgres-0 1/1 Running 0 3m
pod/minio-0 1/1 Running 0 3m
pod/minio-mc-bootstrap-xxxxx 0/1 Completed 0 2m

Access the Application

Access via domain names (works automatically with localtest.me):

Why localtest.me?

The localtest.me domain automatically resolves to 127.0.0.1, eliminating the need to edit /etc/hosts.

Port Forwarding (Alternative)

If ingress isn't working, use port-forward:

# Backend API (port 3000)
kubectl -n eudiplo port-forward svc/eudiplo 3000:3000 &

# Client UI (port 4200 → 80)
kubectl -n eudiplo port-forward svc/eudiplo-client 4200:80 &

# MinIO Console (port 9001)
kubectl -n eudiplo port-forward svc/minio 9001:9001 &

Kill all port-forwards:

pkill -f "kubectl.*port-forward"

Testing & Verification

Health Checks

Verify the backend is healthy:

# Using ingress
curl http://eudiplo.localtest.me/health

# Using port-forward
curl http://localhost:3000/health

Expected response:

{
"status": "ok",
"info": {
"database": {
"status": "up"
}
},
"version": "main"
}

Application Logs

Follow backend logs:

kubectl -n eudiplo logs -f deployment/eudiplo

View all pod logs:

kubectl -n eudiplo logs -l app=eudiplo --tail=50

Troubleshooting

Pods Not Starting

Check pod status and events:

# Describe pod
kubectl -n eudiplo describe pod <pod-name>

# Check namespace events
kubectl -n eudiplo get events --sort-by='.lastTimestamp'

Ingress Not Working

Verify ingress-nginx controller:

# Check controller pods
kubectl -n ingress-nginx get pods

# Verify ingress resource
kubectl -n eudiplo describe ingress eudiplo-ingress

Fallback to port-forward (see above).

Database Connection Errors

Verify PostgreSQL is ready:

kubectl -n eudiplo exec statefulset/postgres -- pg_isready

Restart backend if credentials were updated:

kubectl -n eudiplo rollout restart deployment/eudiplo