Cassandra Tutorial 3, Part 1: Deploy Cassandra with Ansible and SSH Keys - Modern DevOps Practices 2025

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

# 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


This tutorial has been updated for 2025 to reflect modern DevOps practices, cloud-native deployments, and current security standards.

                                                                           
comments powered by Disqus

Apache 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