By Rick Hightower | January 9, 2025
Cassandra Tutorial 3, Part 1: Modern Cassandra Deployment with Ansible - 2025 Edition
What’s New in 2025
This updated tutorial reflects the significant changes in DevOps practices since our original 2017 guide:
- Container-First Approach: Cassandra deployments now primarily use containers (Docker/Podman)
- Kubernetes Native: StatefulSets and operators for managing Cassandra clusters
- GitOps Workflows: Using ArgoCD or Flux for declarative cluster management
- Modern Ansible: Ansible 2.16+ with collections and execution environments
- Enhanced Security: Zero-trust networking, service mesh integration, and secrets management
- Cloud Provider Integration: Native support for AWS, GCP, and Azure Kubernetes services
- Observability: Built-in Prometheus metrics and distributed tracing
Overview
In this modernized tutorial, we’ll deploy a production-ready Cassandra cluster using:
- Ansible Automation Platform 2.4+
- Kubernetes 1.28+
- Container images (official Cassandra 5.0)
- GitOps with ArgoCD
- HashiCorp Vault for secrets management
Prerequisites
Required Tools
# Check versions
ansible --version # 2.16+
kubectl version # 1.28+
docker --version # 24.0+
helm version # 3.13+
Install Modern Ansible
# Using pip with virtual environment
python3 -m venv ansible-env
source ansible-env/bin/activate
pip install ansible-core>=2.16 ansible-runner ansible-builder
# Install required collections
ansible-galaxy collection install kubernetes.core
ansible-galaxy collection install community.general
ansible-galaxy collection install cloud.common
Modern SSH Key Management
1. Using SSH Certificates (Recommended for 2025)
# Generate CA key pair
ssh-keygen -t ed25519 -f cassandra-ca -C "Cassandra Cluster CA"
# Sign user keys with CA
ssh-keygen -s cassandra-ca -I cassandra-admin -n cassandra-admin \
-V +52w ~/.ssh/id_ed25519.pub
# Configure nodes to trust CA
echo "@cert-authority *.cassandra.local $(cat cassandra-ca.pub)" \
>> /etc/ssh/ssh_known_hosts
2. Using HashiCorp Vault for Dynamic SSH
# vault-ssh-role.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: vault-ssh-role
data:
role.json: |
{
"key_type": "ca",
"ttl": "30m",
"max_ttl": "1h",
"allowed_users": "cassandra-admin",
"default_extensions": [
{
"permit-pty": "",
"permit-port-forwarding": ""
}
]
}
Container-Based Cassandra Deployment
Dockerfile for Custom Cassandra Image
# Cassandra 5.0 with monitoring
FROM cassandra:5.0
# Add JMX exporter for Prometheus
ADD https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.19.0/jmx_prometheus_javaagent-0.19.0.jar \
/opt/jmx_prometheus_javaagent.jar
# Add configuration
COPY cassandra-env.sh /etc/cassandra/cassandra-env.sh
COPY jmx-exporter-config.yaml /etc/cassandra/jmx-exporter-config.yaml
# Health check script
COPY healthcheck.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/healthcheck.sh
HEALTHCHECK --interval=30s --timeout=10s --start-period=5m \
CMD /usr/local/bin/healthcheck.sh
Kubernetes StatefulSet Definition
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: cassandra
namespace: cassandra
spec:
serviceName: cassandra
replicas: 3
selector:
matchLabels:
app: cassandra
template:
metadata:
labels:
app: cassandra
spec:
terminationGracePeriodSeconds: 1800
containers:
- name: cassandra
image: your-registry/cassandra:5.0-custom
imagePullPolicy: Always
ports:
- containerPort: 7000
name: intra-node
- containerPort: 7001
name: tls-intra-node
- containerPort: 7199
name: jmx
- containerPort: 9042
name: cql
- containerPort: 9404
name: metrics
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "1"
memory: 2Gi
env:
- name: MAX_HEAP_SIZE
value: 2G
- name: HEAP_NEWSIZE
value: 512M
- name: CASSANDRA_SEEDS
value: "cassandra-0.cassandra.cassandra.svc.cluster.local"
- name: CASSANDRA_CLUSTER_NAME
value: "CassandraCluster2025"
- name: CASSANDRA_DC
value: "DC1"
- name: CASSANDRA_RACK
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
volumeMounts:
- name: cassandra-data
mountPath: /var/lib/cassandra
- name: cassandra-config
mountPath: /etc/cassandra/cassandra.yaml
subPath: cassandra.yaml
volumes:
- name: cassandra-config
configMap:
name: cassandra-config
volumeClaimTemplates:
- metadata:
name: cassandra-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
Modern Ansible Playbook Structure
Directory Layout (2025 Best Practices)
cassandra-automation/
├── ansible.cfg
├── requirements.yml
├── inventory/
│ ├── production/
│ │ ├── group_vars/
│ │ ├── host_vars/
│ │ └── hosts.yml
│ └── staging/
├── collections/
│ └── requirements.yml
├── execution-environments/
│ ├── execution-environment.yml
│ └── requirements.txt
├── playbooks/
│ ├── site.yml
│ ├── deploy-cassandra.yml
│ └── upgrade-cassandra.yml
├── roles/
│ ├── cassandra/
│ ├── monitoring/
│ └── security/
└── molecule/
└── default/
├── molecule.yml
└── verify.yml
Ansible Configuration (ansible.cfg)
[defaults]
inventory = inventory/production/hosts.yml
remote_user = cassandra-admin
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml
callback_whitelist = profile_tasks, timer
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible-facts-cache
fact_caching_timeout = 3600
[inventory]
enable_plugins = kubernetes.core.k8s, auto, yaml, ini
[ssh_connection]
pipelining = True
control_path = /tmp/ansible-%%h-%%p-%%r
ssh_args = -o ControlMaster=auto -o ControlPersist=30m
Main Deployment Playbook
---
# deploy-cassandra.yml
- name: Deploy Cassandra Cluster on Kubernetes
hosts: localhost
gather_facts: no
vars:
cassandra_namespace: cassandra
cassandra_version: "5.0"
cluster_size: 3
tasks:
- name: Create namespace
kubernetes.core.k8s:
name: "{{ cassandra_namespace }}"
api_version: v1
kind: Namespace
state: present
- name: Deploy Cassandra operator
kubernetes.core.helm:
name: cassandra-operator
chart_ref: cassandra-operator/cassandra-operator
release_namespace: "{{ cassandra_namespace }}"
values:
operator:
image: k8ssandra/cass-operator:1.17.0
webhook:
enabled: true
- name: Create Cassandra cluster
kubernetes.core.k8s:
state: present
definition:
apiVersion: cassandra.datastax.com/v1beta1
kind: CassandraDatacenter
metadata:
name: dc1
namespace: "{{ cassandra_namespace }}"
spec:
clusterName: CassandraCluster2025
serverVersion: "{{ cassandra_version }}"
size: "{{ cluster_size }}"
config:
cassandra-yaml:
authenticator: PasswordAuthenticator
authorizer: CassandraAuthorizer
jvm-options:
initial_heap_size: "2G"
max_heap_size: "2G"
storageConfig:
cassandraDataVolumeClaimSpec:
storageClassName: fast-ssd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "1"
memory: 2Gi
GitOps Integration
ArgoCD Application Manifest
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: cassandra-cluster
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/cassandra-gitops
targetRevision: main
path: environments/production
destination:
server: https://kubernetes.default.svc
namespace: cassandra
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
revisionHistoryLimit: 10
Kustomization for Environment-Specific Configs
# environments/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: cassandra
resources:
- ../../base
patchesStrategicMerge:
- cassandra-size-patch.yaml
- storage-class-patch.yaml
configMapGenerator:
- name: cassandra-config
files:
- cassandra.yaml=configs/cassandra-prod.yaml
secretGenerator:
- name: cassandra-auth
literals:
- username=cassandra
- password=changeme # Use sealed-secrets in production
replicas:
- name: cassandra
count: 5 # Production cluster size
Security Best Practices for 2025
1. Network Policies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: cassandra-network-policy
namespace: cassandra
spec:
podSelector:
matchLabels:
app: cassandra
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: cassandra
- podSelector:
matchLabels:
app: cassandra-client
ports:
- protocol: TCP
port: 7000 # Internode
- protocol: TCP
port: 9042 # CQL
2. Service Mesh Integration (Istio)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: cassandra-mtls
namespace: cassandra
spec:
selector:
matchLabels:
app: cassandra
mtls:
mode: STRICT
3. Secrets Management with Sealed Secrets
# Install sealed-secrets controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
# Create and seal secrets
echo -n mypassword | kubectl create secret generic cassandra-auth \
--dry-run=client --from-file=password=/dev/stdin -o yaml | \
kubeseal -o yaml > cassandra-auth-sealed.yaml
Monitoring and Observability
Prometheus ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: cassandra
namespace: cassandra
spec:
selector:
matchLabels:
app: cassandra
endpoints:
- port: metrics
interval: 30s
path: /metrics
Grafana Dashboard Configuration
{
"dashboard": {
"title": "Cassandra Cluster 2025",
"panels": [
{
"title": "Read/Write Latency",
"targets": [
{
"expr": "cassandra_read_latency_p99",
"legendFormat": "Read p99"
},
{
"expr": "cassandra_write_latency_p99",
"legendFormat": "Write p99"
}
]
}
]
}
}
Testing with Molecule
molecule.yml
---
dependency:
name: galaxy
driver:
name: delegated
platforms:
- name: k8s-cluster
groups:
- k8s
provisioner:
name: ansible
inventory:
host_vars:
k8s-cluster:
ansible_connection: local
kubeconfig: ~/.kube/config
verifier:
name: ansible
Next Steps
In Part 2, we’ll cover:
- Advanced Ansible automation patterns
- Multi-region Cassandra deployments
- Disaster recovery procedures
- Performance tuning for modern hardware
- Integration with cloud-native tools
Resources
- Cassandra 5.0 Documentation
- K8ssandra - Production-ready Cassandra on Kubernetes
- Ansible Collections for Kubernetes
- GitOps with ArgoCD
This tutorial has been updated for 2025 to reflect modern DevOps practices, cloud-native deployments, and current security standards.
TweetApache Spark Training
Kafka Tutorial
Akka Consulting
Cassandra Training
AWS Cassandra Database Support
Kafka Support Pricing
Cassandra Database Support Pricing
Non-stop Cassandra
Watchdog
Advantages of using Cloudurable™
Cassandra Consulting
Cloudurable™| Guide to AWS Cassandra Deploy
Cloudurable™| AWS Cassandra Guidelines and Notes
Free guide to deploying Cassandra on AWS
Kafka Training
Kafka Consulting
DynamoDB Training
DynamoDB Consulting
Kinesis Training
Kinesis Consulting
Kafka Tutorial PDF
Kubernetes Security Training
Redis Consulting
Redis Training
ElasticSearch / ELK Consulting
ElasticSearch Training
InfluxDB/TICK Training TICK Consulting