Skip to content

Install the platform

ZEN-INTEL is installed by applying a set of Kubernetes manifests. Have your filled-in secrets from Configuration ready.

Install these cluster-wide controllers first:

  • CloudNativePG operator (provides PostgreSQL):
    Terminal window
    kubectl apply --server-side -f \
    https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.30/releases/cnpg-1.30.0.yaml
    kubectl rollout status deployment -n cnpg-system cnpg-controller-manager
  • ingress-nginx controller (provides the public load balancer and routing).
  • cert-manager (optional, for automatic TLS).
namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: zenintel
Terminal window
kubectl apply -f namespace.yaml

Apply the per-service secrets you prepared in Configuration.

Terminal window
kubectl apply -f configs/

PostgreSQL is a CloudNativePG Cluster. Redis and RabbitMQ follow in the same step.

data/postgres.yaml
# PostgreSQL provided by the CloudNativePG operator.
# The operator must be installed cluster-wide first (see README).
# CloudNativePG creates a read/write Service named postgres-rw, which the
# backend and workers reach via DATABASE_URL.
apiVersion: v1
kind: Secret
metadata:
name: zenintel-pg-app
namespace: zenintel
type: kubernetes.io/basic-auth
stringData:
# username must match spec.bootstrap.initdb.owner below
username: zenintel
password: CHANGEME
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgres
namespace: zenintel
spec:
instances: 2 # increase to 3 for production high availability
bootstrap:
initdb:
database: zenintel
owner: zenintel
secret:
name: zenintel-pg-app
storage:
size: 100Gi
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
Terminal window
kubectl apply -f data/
kubectl wait --for=condition=Ready cluster/postgres -n zenintel --timeout=300s

The backend and the three workers share the backend image and Secret. The ai-service and frontend have their own.

services/backend.yaml
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: zenintel
spec:
selector:
app: backend
ports:
- name: http
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: zenintel
spec:
replicas: 2
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: 337853574763.dkr.ecr.ap-southeast-3.amazonaws.com/zenintel/backend:v1.0.0
ports:
- containerPort: 8080
envFrom:
- secretRef:
name: zenintel-backend-secret
securityContext:
capabilities:
add: ["NET_RAW"]
readinessProbe:
httpGet:
path: /api/health
port: 8080
initialDelaySeconds: 15
periodSeconds: 15
livenessProbe:
httpGet:
path: /api/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 30
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
Terminal window
kubectl apply -f services/

Apply the schema migrations shipped with the release. The exact mechanism depends on how migrations are packaged (a Job, an init container, or a one-off command). Follow the release notes.

The ai-service is internal, so the ingress routes only to the frontend and backend.

ingress/ingress.yaml
# Requires the ingress-nginx controller. The controller provisions the public
# load balancer. This resource defines routing and TLS for the hostname.
# The ai-service is internal only and is not exposed through the ingress.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: zenintel
namespace: zenintel
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- zen-intel.example.com
secretName: zenintel-tls
rules:
- host: zen-intel.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: backend
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 3000
Terminal window
kubectl apply -f ingress/