diff --git a/kubernetes/README.md b/kubernetes/README.md new file mode 100644 index 0000000..3cd5c0d --- /dev/null +++ b/kubernetes/README.md @@ -0,0 +1,46 @@ +# Rallly Kubernetes Manifests + +This directory contains base Kubernetes manifests to self-host Rallly. It separates configuration (ConfigMaps) from sensitive data (Secrets) and uses a StatefulSet for the PostgreSQL database. + +## Prerequisites + +- A Kubernetes cluster. +- `kubectl` configured to talk to your cluster. +- An Ingress Controller (e.g., NGINX) installed. + +## Configuration + +1. **Secrets (`secrets.yaml`):** + - **Important:** Do not commit the `secrets.yaml` file with real credentials to version control. + - Update `POSTGRES_PASSWORD` and `SECRET_PASSWORD` (use `openssl rand -hex 32` to generate). + - Update `DATABASE_URL` to match your postgres password. + +2. **Config (`rallly-config.yaml`):** + - Update `NEXT_PUBLIC_BASE_URL` to match your domain. + - Configure your SMTP settings for emails. + +3. **Ingress (`ingress.yaml`):** + - Change `host: rallly.example.com` to your actual domain. + - Ensure `ingressClassName` matches your cluster's controller (default is set to `nginx`). + +## Deployment Order + +Apply the manifests in the following order to ensure dependencies are met: + +```bash +# 1. Apply Secrets and Config first +kubectl apply -f secrets.yaml +kubectl apply -f rallly-config.yaml + +# 2. Apply Database (StatefulSet) +kubectl apply -f postgres.yaml + +# 3. Apply Application (Deployment) +kubectl apply -f rallly.yaml + +# 4. Apply Ingress +kubectl apply -f ingress.yaml + +# 5. Check that the pods are running - should show '1/1 Running' for each pod. +kubectl get pods +``` diff --git a/kubernetes/README.pdf b/kubernetes/README.pdf new file mode 100644 index 0000000..8e44d78 Binary files /dev/null and b/kubernetes/README.pdf differ diff --git a/kubernetes/ingress.yaml b/kubernetes/ingress.yaml index b58310c..da28f3b 100644 --- a/kubernetes/ingress.yaml +++ b/kubernetes/ingress.yaml @@ -6,23 +6,25 @@ metadata: annotations: # Example for cert-manager (uncomment if using) # cert-manager.io/cluster-issuer: letsencrypt-prod - + # Example for NGINX ingress controller size limit # nginx.ingress.kubernetes.io/proxy-body-size: "10m" spec: + # NOTE: Explicitly set to 'nginx'. Remove this line if using a different Ingress Controller + # or if you wish to use the cluster default. ingressClassName: nginx rules: - - host: rallly.example.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: rallly - port: - number: 80 + - host: rallly.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: rallly + port: + number: 80 tls: - - hosts: - - rallly.example.com - secretName: rallly-tls + - hosts: + - rallly.example.com + secretName: rallly-tls diff --git a/kubernetes/postgres.yaml b/kubernetes/postgres.yaml index 1961f16..f6bc0e7 100644 --- a/kubernetes/postgres.yaml +++ b/kubernetes/postgres.yaml @@ -1,4 +1,3 @@ -# kubernetes/postgres.yaml apiVersion: v1 kind: Service metadata: @@ -33,7 +32,8 @@ spec: runAsUser: 999 containers: - name: postgres - image: postgres:15-alpine + # Switched to 14-alpine to align with official docker-compose + image: postgres:14-alpine securityContext: allowPrivilegeEscalation: false capabilities: @@ -52,6 +52,9 @@ spec: key: POSTGRES_PASSWORD - name: POSTGRES_DB value: rallly + # Fix: Point PGDATA to a generic subpath to avoid mount errors (lost+found) + - name: PGDATA + value: /var/lib/postgresql/data/pgdata ports: - containerPort: 5432 name: postgres @@ -61,7 +64,8 @@ spec: command: - /bin/sh - -c - - pg_isready -U rallly + # Uses env var and adds timeout to prevent hanging + - pg_isready -U $POSTGRES_USER -t 5 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: @@ -69,7 +73,8 @@ spec: command: - /bin/sh - -c - - pg_isready -U rallly + # Uses env var and adds timeout to prevent hanging + - pg_isready -U $POSTGRES_USER -t 5 initialDelaySeconds: 10 periodSeconds: 5 volumeMounts: @@ -89,5 +94,4 @@ spec: accessModes: ["ReadWriteOnce"] resources: requests: - # Note: Adjust storage size based on your data retention needs. storage: 1Gi diff --git a/kubernetes/rallly.yaml b/kubernetes/rallly.yaml index af6fcd5..4f76352 100644 --- a/kubernetes/rallly.yaml +++ b/kubernetes/rallly.yaml @@ -1,4 +1,3 @@ -# kubernetes/rallly.yaml apiVersion: v1 kind: Service metadata: @@ -38,7 +37,7 @@ spec: runAsUser: 1000 containers: - name: rallly - # Pinned version for stability (latest stable at time of refactoring) + # Pinned version for stability and reproducibility image: lukevella/rallly:v4.5.4 imagePullPolicy: IfNotPresent ports: @@ -87,7 +86,6 @@ spec: configMapKeyRef: name: rallly-config key: SMTP_SECURE - # 2. Secrets (from Secret) - name: DATABASE_URL valueFrom: @@ -104,19 +102,6 @@ spec: secretKeyRef: name: rallly-secrets key: INITIAL_ADMIN_EMAIL - - # SMTP User/Password (optional usage) - # - name: SMTP_USER - # valueFrom: - # secretKeyRef: - # name: rallly-secrets - # key: SMTP_USER - # - name: SMTP_PASSWORD - # valueFrom: - # secretKeyRef: - # name: rallly-secrets - # key: SMTP_PASSWORD - resources: limits: cpu: "1" @@ -135,5 +120,6 @@ spec: httpGet: path: / port: 3000 - initialDelaySeconds: 30 + # Reduced delay so the pod becomes ready faster once running + initialDelaySeconds: 10 periodSeconds: 5 diff --git a/kubernetes/secrets.yaml b/kubernetes/secrets.yaml index eb49b48..193729f 100644 --- a/kubernetes/secrets.yaml +++ b/kubernetes/secrets.yaml @@ -1,4 +1,7 @@ # kubernetes/secrets.yaml +# WARNING: This file uses 'stringData' for demonstration. +# For production, DO NOT commit this file to Git. +# Use SealedSecrets, ExternalSecrets, or manually create the secret on the cluster. apiVersion: v1 kind: Secret metadata: