DEV Community

Cover image for Deploying Apache Cassandra on Kubernetes
Sanskriti Harmukh for Vultr

Posted on with Aashish Chaurasiya • Originally published at docs.vultr.com

Deploying Apache Cassandra on Kubernetes

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Note the name of a CSI-backed block storage class — you'll reference it below.

2. Create the cluster manifest:

$ nano cluster.yaml
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode
$ kubectl apply -n k8ssandra-operator -f service.yaml
$ kubectl get svc/cassandra -n k8ssandra-operator
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
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;
Enter fullscreen mode Exit fullscreen mode
 id | country | name
----+---------+-----------
 43 |      US | Joe Smith
 42 |      UK |  John Doe

(2 rows)
Enter fullscreen mode Exit fullscreen mode

Next Steps

Cassandra is running as a 3-node cluster with persistent storage and a Stargate data gateway. From here:

  • Scale size in 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)