Skip to main content

On-Premise Deployment

Deploy Optimal Platform to your own Kubernetes infrastructure for full control over your environment.

Prerequisites

Kubernetes Cluster

  • Kubernetes 1.27+
  • kubectl configured
  • Helm 3.x

Infrastructure Requirements

ComponentMinimumRecommended
Control Plane Nodes33
Worker Nodes35+
CPU per Worker4 cores8 cores
RAM per Worker16 GB32 GB
Storage per Worker100 GB SSD500 GB NVMe

Required Components

  • Ingress Controller: NGINX, Traefik, or HAProxy
  • Storage Provisioner: Local-path, NFS, Ceph, or Longhorn
  • Load Balancer: MetalLB or external load balancer
  • DNS: Internal DNS server or external DNS

Deployment Steps

1. Prepare Cluster

# Verify cluster is ready
kubectl cluster-info
kubectl get nodes

# Create namespace
kubectl create namespace optimal-system

2. Install Ingress Controller

If not already installed:

# NGINX Ingress
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace

3. Install Storage Provisioner

If not already installed:

# Longhorn (recommended for bare metal)
helm repo add longhorn https://charts.longhorn.io
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--create-namespace

4. Configure Values

Create a custom values file:

# values-onprem.yaml
global:
domain: optimal.internal
storageClass: longhorn # or your storage class

ingress:
enabled: true
className: nginx
annotations:
# Remove cert-manager if using internal certificates
# cert-manager.io/cluster-issuer: letsencrypt-prod
tls:
- secretName: optimal-tls
hosts:
- portal.optimal.internal
- api.optimal.internal

# Use in-cluster databases
postgresql:
enabled: true
auth:
database: optimal
username: optimal
primary:
persistence:
storageClass: longhorn
size: 50Gi

redis:
enabled: true
architecture: standalone # or replication
master:
persistence:
storageClass: longhorn
size: 10Gi

# Observability
prometheus:
enabled: true
persistence:
storageClass: longhorn
size: 100Gi

grafana:
enabled: true
persistence:
storageClass: longhorn
size: 10Gi

loki:
enabled: true
persistence:
storageClass: longhorn
size: 50Gi

# Security
kyverno:
enabled: true

# Backup (configure with local storage or NFS)
velero:
enabled: true
provider: local
configuration:
backupStorageLocation:
bucket: optimal-backups
config:
path: /backups

5. Deploy Platform

# Add Helm repositories
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

# Deploy
helm upgrade --install optimal-platform k8s/helm-charts/optimal-platform \
--namespace optimal-system \
--create-namespace \
-f values-onprem.yaml

6. Configure DNS

Add DNS entries for your services:

# Internal DNS or /etc/hosts
192.168.1.100 portal.optimal.internal
192.168.1.100 api.optimal.internal
192.168.1.100 keycloak.optimal.internal
192.168.1.100 grafana.optimal.internal

7. Configure TLS

Option 1: Self-signed certificates

# Generate self-signed cert
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=*.optimal.internal"

# Create secret
kubectl create secret tls optimal-tls \
--cert=tls.crt \
--key=tls.key \
-n optimal-system

Option 2: Internal CA

# Create certificate from internal CA
# ... your CA process ...

kubectl create secret tls optimal-tls \
--cert=signed.crt \
--key=private.key \
-n optimal-system

High Availability

Database HA

postgresql:
architecture: replication
readReplicas:
replicaCount: 2

Pod Distribution

portal:
replicas: 3
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: optimal-portal
topologyKey: kubernetes.io/hostname

External Load Balancer

If using an external load balancer (F5, HAProxy, etc.):

ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: external
# Configure backend servers to point to node ports

Network Configuration

Network Policies

networkPolicies:
enabled: true
defaultDeny: true

# Define allowed traffic
allowedNamespaces:
- kube-system
- ingress-nginx

Proxy Configuration

If behind a corporate proxy:

global:
proxy:
httpProxy: http://proxy.internal:8080
httpsProxy: http://proxy.internal:8080
noProxy: "localhost,127.0.0.1,.internal,.svc"

Air-Gapped Installation

For completely isolated networks, use Outpost to package and deploy:

# On connected machine
outpost package create --config outpost.yaml --output optimal-bundle.tar.gz

# Transfer bundle to air-gapped network

# On air-gapped machine
outpost deploy init --bundle optimal-bundle.tar.gz --registry registry.internal:5000
outpost deploy run --bundle optimal-bundle.tar.gz

Maintenance

Backups

Configure backup location:

velero:
configuration:
backupStorageLocation:
bucket: optimal-backups
config:
path: /mnt/nfs/backups # NFS mount

Create manual backup:

velero backup create manual-backup --include-namespaces optimal-system

Updates

# Update Helm repositories
helm repo update

# Upgrade platform
helm upgrade optimal-platform k8s/helm-charts/optimal-platform \
--namespace optimal-system \
-f values-onprem.yaml

Troubleshooting

Storage Issues

# Check PVC status
kubectl get pvc -n optimal-system

# Check storage provisioner
kubectl get pods -n longhorn-system

Network Issues

# Test DNS resolution
kubectl run test --rm -it --image=busybox -- nslookup portal.optimal.internal

# Test service connectivity
kubectl run test --rm -it --image=busybox -- wget -O- http://optimal-portal.optimal-system.svc

Certificate Issues

# Check certificate
kubectl get secret optimal-tls -n optimal-system -o yaml

# Verify certificate
openssl s_client -connect portal.optimal.internal:443