Apache Cassandra is a highly scalable, distributed NoSQL database built for write-heavy workloads, horizontal scaling, and tunable consistency, with no single point of failure. K8ssandra is an open-source operator that automates Cassandra provisioning, scaling, backups, and repairs on Kubernetes. This guide deploys a multi-node Cassandra cluster via the K8ssandra Operator, with cert-manager, persistent block storage, and a LoadBalancer service for external access.
Prerequisites: a Kubernetes cluster with at least 4 nodes / 4GB RAM each, a workstation with kubectl and helm configured against the cluster.
Install cqlsh
cqlsh is the Python-based CLI for querying Cassandra.
$ sudo apt update
$ sudo apt install -y python3 python3-pip python3.12-venv
$ python3 -m venv cassandra
$ source cassandra/bin/activate
$ pip install -U cqlsh
$ cqlsh --version
Install cert-manager
K8ssandra uses cert-manager to generate the Java keystores/truststores Cassandra needs for internal TLS.
$ helm repo add jetstack https://charts.jetstack.io
$ helm repo update
$ helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true
$ kubectl get all -n cert-manager
Install the K8ssandra Operator
$ helm repo add k8ssandra https://helm.k8ssandra.io/stable
$ helm install k8ssandra-operator k8ssandra/k8ssandra-operator \
--namespace k8ssandra-operator \
--create-namespace
$ kubectl -n k8ssandra-operator get deployment
$ kubectl get pods -n k8ssandra-operator
You should see both k8ssandra-operator and k8ssandra-operator-cass-operator deployments ready.
Deploy a Multi-Node Cassandra Cluster
1. Check available StorageClasses in your cluster:
$ kubectl get storageclass
Note the name of a CSI-backed block storage class — you'll reference it below.
2. Create the cluster manifest:
$ nano cluster.yaml
apiVersion: k8ssandra.io/v1alpha1
kind: K8ssandraCluster
metadata:
name: demo
spec:
cassandra:
serverVersion: "4.0.1"
datacenters:
- metadata:
name: dc1
size: 3
storageConfig:
cassandraDataVolumeClaimSpec:
storageClassName: standard
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
config:
jvmOptions:
heapSize: 512M
stargate:
size: 1
heapSize: 256M
Replace standard with your cluster's actual StorageClass name. This provisions 3 Cassandra nodes with a 10GB volume each, 512MB JVM heap per Cassandra node, and a single Stargate node (REST/GraphQL/Document API gateway in front of Cassandra) with a 256MB heap. Confirm your cloud provider's CSI driver is installed and configured before applying — it's required for dynamic volume provisioning.
3. Apply and wait (cluster bring-up takes ~15 minutes):
$ kubectl apply -n k8ssandra-operator -f cluster.yaml
$ kubectl get pods -n k8ssandra-operator --watch
You're looking for 3 demo-dc1-default-sts-N pods and a demo-dc1-default-stargate-deployment-* pod, all Running.
Verify Persistent Storage
Cassandra nodes run as a StatefulSet, each backed by a PVC for durable storage.
$ kubectl get statefulset -n k8ssandra-operator
$ kubectl get sc standard
$ kubectl get pvc --all-namespaces
All three PVCs should show Bound.
Expose the Cluster
Create a LoadBalancer service to reach Cassandra over the native CQL protocol (port 9042):
$ nano service.yaml
apiVersion: v1
kind: Service
metadata:
name: cassandra
labels:
app: cassandra
spec:
type: LoadBalancer
externalTrafficPolicy: Local
ports:
- port: 9042
targetPort: 9042
selector:
app.kubernetes.io/name: cassandra
$ kubectl apply -n k8ssandra-operator -f service.yaml
$ kubectl get svc/cassandra -n k8ssandra-operator
Wait for EXTERNAL-IP to populate (a few minutes) — that's your connection address.
Test the Cluster
$ CASS_IP=$(kubectl get svc cassandra -n k8ssandra-operator -o jsonpath="{.status.loadBalancer.ingress[*].ip}")
$ CASS_USERNAME=$(kubectl get secret demo-superuser -n k8ssandra-operator -o=jsonpath='{.data.username}' | base64 --decode)
$ CASS_PASSWORD=$(kubectl get secret demo-superuser -n k8ssandra-operator -o=jsonpath='{.data.password}' | base64 --decode)
$ cqlsh -u $CASS_USERNAME -p $CASS_PASSWORD $CASS_IP 9042
demo-superuser@cqlsh> CREATE KEYSPACE demo WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
demo-superuser@cqlsh> CREATE TABLE demo.users (id text primary key, name text, country text);
demo-superuser@cqlsh> BEGIN BATCH
INSERT INTO demo.users (id, name, country) VALUES ('42', 'John Doe', 'UK');
INSERT INTO demo.users (id, name, country) VALUES ('43', 'Joe Smith', 'US');
APPLY BATCH;
demo-superuser@cqlsh> SELECT * FROM demo.users;
id | country | name
----+---------+-----------
43 | US | Joe Smith
42 | UK | John Doe
(2 rows)
Next Steps
Cassandra is running as a 3-node cluster with persistent storage and a Stargate data gateway. From here:
- Scale
sizein the datacenter spec and reapply to add nodes - Enable Stargate's REST/GraphQL APIs for app access without a native CQL driver
- Configure K8ssandra's Medusa integration for scheduled backups to object storage
For the full guide, visit the original article on Vultr Docs.
Top comments (0)