Skip to main content

Kubernetes Deployment

This guide explains how to deploy GeoPulse to a Kubernetes cluster using the provided helper scripts and Helm.

For advanced configuration and a full list of tunable parameters, please refer to the Helm Deployment Guide.

Prerequisites​

  • You have cloned this repository locally.
  • Kubernetes cluster (1.19+)
  • kubectl configured to access your cluster.
  • helm version 3.2.0+ installed.

Installation from helm repository​

helm repo add geopulse https://geopulse.cc/charts
helm repo update
helm install my-geopulse geopulse/geopulse

Installation from OCI registry (GHCR)​

Each release also publishes the chart as an OCI artifact to GitHub Container Registry. Helm 3.8+ can install it without helm repo add:

helm install my-geopulse oci://ghcr.io/tess1o/charts/geopulse

Add --version <version> to pin a release. Upgrades use the same reference:

helm upgrade my-geopulse oci://ghcr.io/tess1o/charts/geopulse -f your-values.yaml

Verifying the chart signature​

The OCI chart is signed with cosign keyless signing from the GeoPulse release workflow. To verify it:

cosign verify ghcr.io/tess1o/charts/geopulse:<version> \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/tess1o/geopulse/.github/workflows/release.yml@refs/tags/v'

GitOps with Flux​

Flux can pull the chart as an OCIRepository and check the signature before reconciling:

apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
name: geopulse
namespace: geopulse
spec:
interval: 1h
url: oci://ghcr.io/tess1o/charts/geopulse
layerSelector:
mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip
operation: copy
ref:
semver: ">=1.0.0"
verify:
provider: cosign
matchOIDCIdentity:
- issuer: "^https://token.actions.githubusercontent.com$"
subject: "^https://github.com/tess1o/geopulse/.github/workflows/release.yml@refs/tags/v.*$"
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: geopulse
namespace: geopulse
spec:
interval: 1h
chartRef:
kind: OCIRepository
name: geopulse
values: {}

Installation from source code​

1. Clone the Repository​

First, ensure you have a local copy of the GeoPulse repository.

git clone https://github.com/tess1o/GeoPulse.git
cd GeoPulse

2. Make Scripts Executable​

The repository includes helper scripts to manage the deployment. You need to make them executable first.

chmod +x ./helm/*.sh

3. Install GeoPulse​

The recommended way to install is with the interactive script, which will guide you through the available options.

./helm/install.sh

The script will present several installation types, from a minimal test setup to a full production deployment, and will run the necessary helm commands for you.

4. Manage Your Deployment​

You can easily start, stop, and uninstall your GeoPulse deployment using the provided scripts. This is useful for saving resources in a development environment.

Stop GeoPulse​

This command scales all components to zero, effectively pausing the application while preserving all data and configuration.

./helm/stop-geopulse.sh

Start GeoPulse​

This resumes the application by scaling the components back up.

./helm/start-geopulse.sh

Uninstall GeoPulse​

This will completely remove the GeoPulse deployment from your cluster.

Warning: By default, this will also delete the Persistent Volume Claims (PVCs), which means all your data will be permanently deleted.

./helm/uninstall-geopulse.sh

Advanced Customization​

If the interactive installer does not cover your needs, you can bypass it and use helm directly with a custom values file.

  1. Review Example Configurations: The helm/examples/ directory contains templates for different scenarios, including the new medium-deployment.yaml.
  2. Create my-values.yaml: Copy and modify an example to create your own configuration.
  3. Install Manually:
    helm install geopulse ./helm/geopulse -f my-values.yaml

For a complete list of all available parameters, consult the Helm Deployment Guide.

Encryption Key Generation Notes​

GeoPulse generates its installation encryption key in a backend initContainer and stores it in a PVC (geopulse-keys) by default. Sign-in sessions are stored in the database and need no signing keys.

  • Single backend pod: default ReadWriteOnce works out of the box.
  • Multiple backend replicas across nodes: use a storage class that supports ReadWriteMany, or pin backend pods to the same node.

GeoPulse Installation Troubleshooting​

This guide covers common issues during GeoPulse Helm installation on k3s and how to fix them.


1. Error: ✗ Cannot connect to Kubernetes cluster​

Symptom:

✗ Cannot connect to Kubernetes cluster

Cause: kubectl cannot access your k3s cluster from the current user environment.

Fix:

Ensure k3s is running:

sudo systemctl status k3s

Make kubeconfig available to your user:

mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $USER:$USER ~/.kube/config

Export KUBECONFIG (if not already set):

export KUBECONFIG=~/.kube/config

Test connectivity:

kubectl get nodes
kubectl cluster-info

Re-run the installer:

./helm/install.sh

Note: If you previously ran the script with sudo, try running it without sudo after setting KUBECONFIG.


2. Error: INSTALLATION FAILED: Kubernetes cluster unreachable​

Symptom:

Error: INSTALLATION FAILED: Kubernetes cluster unreachable: the server could not find the requested resource

Cause: Helm cannot find the cluster because $KUBECONFIG is missing or not passed to sudo.

Fix:

Option 1 — Run without sudo (recommended):

./helm/install.sh

Option 2 — Run with sudo and explicit KUBECONFIG:

sudo KUBECONFIG=/etc/rancher/k3s/k3s.yaml ./helm/install.sh

Option 3 — Patch the install script to automatically export kubeconfig:

if [ -z "$KUBECONFIG" ]; then
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
fi

3. Accessing GeoPulse UI​

The GeoPulse frontend service (geopulse-frontend) listens on port 80 in the cluster.

Option 1 — Port-forward (temporary)​

kubectl port-forward -n default svc/geopulse-frontend 5555:80 --address 0.0.0.0

Access from any machine on the network:

http://<server-ip>:5555

Replace <server-ip> with your k3s host LAN IP:

hostname -I | awk '{print $1}'

Option 2 — Use NodePort (persistent)​

Create a values file to switch the service type and (optionally) pin a fixed port:

cat > values-nodeport.yaml <<EOF
frontend:
service:
type: NodePort
nodePort: 30555 # Optional; omit to auto-assign
EOF

Apply it with Helm:

# If installed from source:
helm upgrade geopulse ./helm/geopulse -f values-nodeport.yaml

# If installed from Helm repository:
helm upgrade my-geopulse geopulse/geopulse -f values-nodeport.yaml

Access the UI from a network machine:

http://<server-ip>:30555

If you omitted nodePort, get the assigned port:

kubectl get svc -n default

4. Error: Backend pod crashes with CPU feature errors​

Symptom:

The current machine does not support all of the following CPU features that are required by the image:
[AVX2, BMI1, BMI2, FMA, F16C, LZCNT] (AMD64) or [FP, ASIMD, CRC32, LSE] (ARM64)

Cause: Your Kubernetes nodes have older CPUs that don't support the advanced instructions used by the default optimized native image.

Fix:

Create a values file with the compatible image tag:

cat > values-compat.yaml <<EOF
backend:
image:
tag: "1.4.3-native-compat"
EOF

Then upgrade your installation:

# If installed from source:
helm upgrade geopulse ./helm/geopulse -f values-compat.yaml

# If installed from Helm repository:
helm upgrade geopulse geopulse/geopulse -f values-compat.yaml

Who needs the compatible image?

  • Old x86 CPUs: Intel pre-Haswell (before 2013), AMD pre-Excavator (before 2015)
    • Examples: Intel Core i5-3470T (Ivy Bridge), Intel Xeon E5-2670 (Sandy Bridge)
  • Raspberry Pi 3/4 clusters: ARM Cortex-A53/A72 processors

Check your node's CPU capabilities:

# For x86/AMD64 nodes:
kubectl debug node/YOUR-NODE-NAME -it --image=ubuntu -- lscpu | grep -i flags
# Look for: avx2, bmi1, bmi2, fma, f16c

# For ARM64 nodes:
kubectl debug node/YOUR-NODE-NAME -it --image=ubuntu -- cat /proc/cpuinfo | grep Features
# Look for: asimd, crc32, atomics

Performance note: The compatible image uses x86-64-v2 (AMD64) or armv8-a+nolse (ARM64), which sacrifices some performance for broader compatibility. If your nodes have modern CPUs (2015+), use the default optimized image for best performance and lower memory usage.