Installing Apache Cassandra
This guide provides comprehensive installation instructions for Apache Cassandra, covering development setups through production deployments. It explains not just how to install, but why certain configurations matter and what problems occur when steps are skipped.
Before Installing: Critical Decisions
Section titled “Before Installing: Critical Decisions”Before running any installation commands, certain decisions must be made that are difficult to change later:
1. Cassandra Version Selection
Section titled “1. Cassandra Version Selection”| Version | Java Required | Status | When to Use |
|---|---|---|---|
| 5.0.x | JDK 11 or 17 (Recommended) | Latest stable | New deployments, want latest features (SAI, Vector Search, Trie indexes) |
| 4.1.x | JDK 11 | LTS | Production systems needing stability, most tested version |
| 4.0.x | JDK 11 | Maintenance | Existing clusters, conservative environments |
| 3.11.x | JDK 8 | Legacy | Only for existing clusters that cannot upgrade |
Important version differences:
-
5.0: Storage Attached Indexes (SAI) are production-ready, vector search support, new Trie-based indexes, improved guardrails
-
4.1: Virtual tables for configuration, pluggable memtable implementations, faster streaming
-
4.0: Audit logging, full query logging, Java 11 support, improved compaction
-
3.11: Still runs Java 8, no audit logging, missing modern features
Apache Cassandra 5.0 is GA and suitable for production when running a recent 5.0.x release. Use it for new clusters, and upgrade existing ones after normal staging validation.
2. Hardware Requirements by Use Case
Section titled “2. Hardware Requirements by Use Case”Development/Testing
Section titled “Development/Testing”CPU: 2-4 coresRAM: 8 GB minimum (4GB heap + OS)Storage: 20 GB SSDNetwork: 100 Mbps
REALITY CHECK: Cassandra can run on less, but:- < 4GB RAM: Constant GC pressure, random crashes- HDD instead of SSD: 10x slower compaction, unusable for realistic testing- Single core: JVM threads starve each otherSmall Production (< 100GB data per node)
Section titled “Small Production (< 100GB data per node)”CPU: 8 cores (16 threads with hyperthreading)RAM: 32 GBStorage: 500 GB NVMe SSDNetwork: 1 Gbps dedicated
WHY THESE NUMBERS:- 8 cores: 4 for compaction, 4 for request handling under load- 32 GB: 8GB heap + 24GB for OS page cache (critical for read performance)- NVMe: Compaction is I/O bound; SATA SSD adds 2-5x latency- 1 Gbps: Streaming during repairs/bootstrapping saturates lesser linksStandard Production (100GB-500GB data per node)
Section titled “Standard Production (100GB-500GB data per node)”CPU: 16 coresRAM: 64 GBStorage: 2 TB NVMe SSDNetwork: 10 Gbps
WHY THESE NUMBERS:- 16 cores: Handles 10K+ ops/sec comfortably- 64 GB: 16-24GB heap + 40GB page cache- 2 TB: 500GB data + 500GB for compaction headroom + growth- 10 Gbps: Multi-DC replication and repairs without throttlingHigh-Performance Production (> 500GB per node)
Section titled “High-Performance Production (> 500GB per node)”CPU: 32+ coresRAM: 128 GBStorage: 4+ TB NVMe (multiple drives in JBOD)Network: 25 Gbps
CRITICAL CONSIDERATIONS:- Never exceed 31GB heap (compressed OOPs limit)- Multiple smaller drives outperform single large drive- CPU becomes bottleneck before other resources at this scale3. JDK Selection
Section titled “3. JDK Selection”Cassandra is extremely sensitive to JDK choice. Wrong JDK = production incidents.
# Check Java versionjava -version
# MUST see output like:# openjdk version "11.0.x" or "17.0.x"# OpenJDK Runtime EnvironmentSupported JDK Matrix:
| Cassandra | JDK 8 | JDK 11 | JDK 17 | JDK 21 |
|---|---|---|---|---|
| 5.0 | ❌ | ✅ | ✅ | ❌ |
| 4.1 | ❌ | ✅ | ✅ (4.1.3+) | ❌ |
| 4.0 | ❌ | ✅ | ❌ | ❌ |
| 3.11 | ✅ | ❌ | ❌ | ❌ |
JDK Vendor Recommendations:
- Eclipse Temurin (Adoptium) - Recommended for most deployments
- Amazon Corretto - Best for AWS deployments
- Azul Zulu - Free with optional commercial support
- Oracle JDK - Requires license for production
Never use these JDKs with Cassandra
- GraalVM - Incompatible bytecode optimizations
- OpenJ9/IBM J9 - Different memory model causes data corruption
- Any JDK < 11.0.11 - Critical GC bugs
Installation Methods Comparison
Section titled “Installation Methods Comparison”| Method | Complexity | Update Path | Best For |
|---|---|---|---|
| Package Manager | Low | apt upgrade | Production Linux servers, manual management |
| Tarball | Medium | Manual | Custom configurations, multiple versions |
| Docker | Low | Pull new image | Development, CI/CD |
| Kubernetes | High | Operator-managed | Cloud-native, auto-scaling |
| Ansible | Low | Re-run playbook | Production clusters, repeatable deployments |
Recommendation for Production Deployments
For production clusters, we recommend Method 5: Ansible Automation using the AxonOps Ansible Collection. It automates all OS tuning, security hardening, and Cassandra best practices, and works as a standalone Cassandra installer even without AxonOps monitoring.
Method 1: Package Manager Installation
Section titled “Method 1: Package Manager Installation”Ubuntu/Debian Installation
Section titled “Ubuntu/Debian Installation”Step 1: System Preparation
Section titled “Step 1: System Preparation”# Update system packagessudo apt-get update && sudo apt-get upgrade -y
# Install required dependenciessudo apt-get install -y \ apt-transport-https \ ca-certificates \ gnupg2 \ curl \ wget \ net-tools \ sysstat \ iotop \ htop
# Verify no existing Cassandra installationdpkg -l | grep cassandra# If found, remove completely:# sudo apt-get remove --purge cassandra# sudo rm -rf /var/lib/cassandra /var/log/cassandra /etc/cassandraStep 2: Install Java 11
Section titled “Step 2: Install Java 11”# Install OpenJDK 11sudo apt-get install -y openjdk-11-jdk
# Verify installationjava -version# Should output: openjdk version "11.0.x"
# Set JAVA_HOME (add to /etc/environment for persistence)echo 'JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64' | sudo tee -a /etc/environmentsource /etc/environment
# Verify JAVA_HOMEecho $JAVA_HOME# Should output: /usr/lib/jvm/java-11-openjdk-amd64
# TROUBLESHOOTING: If multiple Java versions exist:sudo update-alternatives --config java# Select the java-11-openjdk optionStep 3: Add Cassandra Repository
Section titled “Step 3: Add Cassandra Repository”# Download and add Apache Cassandra signing keyscurl -fsSL https://downloads.apache.org/cassandra/KEYS | sudo gpg --dearmor -o /usr/share/keyrings/cassandra-archive-keyring.gpg
# Verify the key was addedgpg --no-default-keyring --keyring /usr/share/keyrings/cassandra-archive-keyring.gpg --list-keys# Should show Apache Cassandra keys
# Add the repository for Cassandra 5.0echo "deb [signed-by=/usr/share/keyrings/cassandra-archive-keyring.gpg] https://debian.cassandra.apache.org 50x main" | \ sudo tee /etc/apt/sources.list.d/cassandra.sources.list
# For Cassandra 4.1 instead, use:# echo "deb [signed-by=/usr/share/keyrings/cassandra-archive-keyring.gpg] https://debian.cassandra.apache.org 41x main" | \# sudo tee /etc/apt/sources.list.d/cassandra.sources.list
# Update package listsudo apt-get update
# Verify repository is availableapt-cache policy cassandra# Should show available versions from debian.cassandra.apache.orgStep 4: Configure System Limits (BEFORE Installing)
Section titled “Step 4: Configure System Limits (BEFORE Installing)”Critical Step
Cassandra will fail or perform terribly without proper limits. Configure these before installing.
# Create limits configurationsudo tee /etc/security/limits.d/cassandra.conf << 'EOF'# Cassandra process limitscassandra - memlock unlimitedcassandra - nofile 100000cassandra - nproc 32768cassandra - as unlimited
# Also set for root (for manual testing)root - memlock unlimitedroot - nofile 100000root - nproc 32768EOF
# Verify PAM is configured to read limits.dgrep -q "pam_limits.so" /etc/pam.d/common-session || \ echo "session required pam_limits.so" | sudo tee -a /etc/pam.d/common-session
grep -q "pam_limits.so" /etc/pam.d/common-session-noninteractive || \ echo "session required pam_limits.so" | sudo tee -a /etc/pam.d/common-session-noninteractiveStep 5: Disable Transparent Huge Pages
Section titled “Step 5: Disable Transparent Huge Pages”Mandatory Configuration
THP causes severe latency spikes with Cassandra. Disabling THP is mandatory for production.
# Check current THP statuscat /sys/kernel/mm/transparent_hugepage/enabled# [always] madvise never <- BAD: THP is enabled# always madvise [never] <- GOOD: THP is disabled
# Disable THP immediatelyecho never | sudo tee /sys/kernel/mm/transparent_hugepage/enabledecho never | sudo tee /sys/kernel/mm/transparent_hugepage/defrag
# Make persistent across reboots - create systemd servicesudo tee /etc/systemd/system/disable-thp.service << 'EOF'[Unit]Description=Disable Transparent Huge Pages (THP)DefaultDependencies=noAfter=sysinit.target local-fs.targetBefore=cassandra.service
[Service]Type=oneshotExecStart=/bin/sh -c 'echo never | tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null'ExecStart=/bin/sh -c 'echo never | tee /sys/kernel/mm/transparent_hugepage/defrag > /dev/null'
[Install]WantedBy=basic.targetEOF
sudo systemctl daemon-reloadsudo systemctl enable disable-thpsudo systemctl start disable-thp
# Verify it is disabledcat /sys/kernel/mm/transparent_hugepage/enabled# Should show: always madvise [never]Step 6: Configure Swap (Important for Stability)
Section titled “Step 6: Configure Swap (Important for Stability)”# Check current swapfree -hcat /proc/swaps
# Option A: Disable swap entirely (recommended for dedicated Cassandra servers)sudo swapoff -a# Remove swap entries from /etc/fstab to make permanentsudo sed -i '/swap/d' /etc/fstab
# Option B: Keep minimal swap but prevent Cassandra from using it# Set vm.swappiness to 1 (not 0, which can cause OOM killer issues)echo 'vm.swappiness = 1' | sudo tee -a /etc/sysctl.confsudo sysctl -p
# IMPORTANT:# - Cassandra manages its own memory via JVM heap# - If Cassandra swaps, latency goes from milliseconds to seconds# - OOM killer is preferable to swap-induced latency spiralsStep 7: Install Cassandra
Section titled “Step 7: Install Cassandra”# Install Cassandrasudo apt-get install -y cassandra
# Don't start it yet - configuration is required firstsudo systemctl stop cassandra
# Verify installationls -la /etc/cassandra/# Should see: cassandra.yaml, cassandra-env.sh, jvm11-server.options, etc.
ls -la /var/lib/cassandra/# Should see: data, commitlog, saved_caches, hints directoriesStep 8: Initial Configuration
Section titled “Step 8: Initial Configuration”# Backup original configurationsudo cp /etc/cassandra/cassandra.yaml /etc/cassandra/cassandra.yaml.original
# Edit configurationsudo nano /etc/cassandra/cassandra.yamlMinimum required changes for cassandra.yaml:
# CLUSTER IDENTIFICATION# Must be identical across all nodes in the cluster# Cannot be changed after data is written without wiping the clustercluster_name: 'Production Cluster'
# DIRECTORIES# Change these if using dedicated disks (recommended)data_file_directories: - /var/lib/cassandra/data # Best on fast SSDcommitlog_directory: /var/lib/cassandra/commitlog # Best on separate SSDsaved_caches_directory: /var/lib/cassandra/saved_cacheshints_directory: /var/lib/cassandra/hints
# NETWORK CONFIGURATION# listen_address: IP other Cassandra nodes will use to connect# rpc_address: IP clients will use to connect
# For single node development:listen_address: localhostrpc_address: localhost
# For production (replace with actual IP):# listen_address: 192.168.1.10# rpc_address: 192.168.1.10
# SEED NODES# Seeds are used for bootstrapping gossip - NOT special nodes# Use 2-3 seeds per datacenter, never more than 3seed_provider: - class_name: org.apache.cassandra.locator.SimpleSeedProvider parameters: - seeds: "127.0.0.1" # For production cluster: # - seeds: "192.168.1.10,192.168.1.11"
# ENDPOINT SNITCH# Determines how Cassandra locates nodes in the topology# SimpleSnitch: Single DC, no rack awareness - development only# GossipingPropertyFileSnitch: Production - reads from cassandra-rackdc.propertiesendpoint_snitch: SimpleSnitch# For production, change to:# endpoint_snitch: GossipingPropertyFileSnitchStep 9: Configure JVM Settings
Section titled “Step 9: Configure JVM Settings”For production systems, JVM settings must be tuned:
# Edit JVM optionssudo nano /etc/cassandra/jvm11-server.optionsKey settings to modify:
# HEAP SIZE# For 32GB RAM system, use 8GB heap (leaves 24GB for page cache)# Find these lines and modify:-Xms8G-Xmx8G
# HEAP SIZING FORMULA:# - Development (8GB RAM): -Xms2G -Xmx2G# - Small prod (16GB RAM): -Xms4G -Xmx4G# - Medium prod (32GB RAM): -Xms8G -Xmx8G# - Large prod (64GB RAM): -Xms16G -Xmx16G# - Max prod (128GB+ RAM): -Xms31G -Xmx31G (NEVER exceed 31G)
# GC LOGGING - essential for troubleshooting# Uncomment or add:-Xlog:gc*:file=/var/log/cassandra/gc.log:time,uptime:filecount=10,filesize=10MStep 10: Start Cassandra
Section titled “Step 10: Start Cassandra”# Start the servicesudo systemctl start cassandra
# Watch the logs for startup (takes 30-120 seconds)sudo tail -f /var/log/cassandra/system.log
# WHAT TO LOOK FOR IN LOGS:
# GOOD - startup is progressing:# "Listening for thrift clients..." (if enabled)# "Starting listening for CQL clients on /127.0.0.1:9042"# "Node /127.0.0.1 state jump to NORMAL"
# BAD - startup failed:# "Exception encountered during startup"# "OutOfMemoryError"# "Unable to bind to address"
# Check service statussudo systemctl status cassandra
# Verify node is upnodetool status
# EXPECTED OUTPUT:# Datacenter: datacenter1# =======================# Status=Up/Down# |/ State=Normal/Leaving/Joining/Moving# -- Address Load Tokens Owns Host ID Rack# UN 127.0.0.1 674.83 KiB 16 100.0% 550e8400-e29b-41d4-a716-446655440000 rack1## UN = Up and Normal (good)# DN = Down and Normal (bad)# UJ = Up and Joining (bootstrapping)# UL = Up and Leaving (decommissioning)Step 11: Enable Automatic Start
Section titled “Step 11: Enable Automatic Start”# Enable Cassandra to start on bootsudo systemctl enable cassandra
# Verify it is enabledsystemctl is-enabled cassandra# Should output: enabledStep 12: Verify Installation
Section titled “Step 12: Verify Installation”# Connect with cqlshcqlsh
# If connection is refused, wait 30 more seconds and retry
# Run basic verification queriescqlsh> DESCRIBE CLUSTER;# Shows cluster name and partitioner
cqlsh> SELECT cluster_name, listen_address, release_version FROM system.local;# Shows current node info
cqlsh> CREATE KEYSPACE test_install WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};cqlsh> USE test_install;cqlsh> CREATE TABLE test (id int PRIMARY KEY, value text);cqlsh> INSERT INTO test (id, value) VALUES (1, 'installation successful');cqlsh> SELECT * FROM test;# Should return the inserted row
# Cleanup test datacqlsh> DROP KEYSPACE test_install;cqlsh> exitRHEL/CentOS/Rocky Linux Installation
Section titled “RHEL/CentOS/Rocky Linux Installation”Step 1: System Preparation
Section titled “Step 1: System Preparation”# Update systemsudo yum update -y
# Install dependenciessudo yum install -y \ curl \ wget \ net-tools \ sysstat \ iotop \ htop \ yum-utils
# Disable SELinux (or configure it properly)# SELinux in enforcing mode blocks Cassandra file accesssudo setenforce 0sudo sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/configSELinux in High-Security Environments
For high-security environments, configure SELinux policies properly instead of disabling. See Red Hat SELinux documentation.
Step 2: Install Java 11
Section titled “Step 2: Install Java 11”# Install OpenJDK 11sudo yum install -y java-11-openjdk java-11-openjdk-devel
# Set as default (if multiple Java versions exist)sudo alternatives --set java /usr/lib/jvm/java-11-openjdk-*/bin/java
# Verifyjava -version
# Set JAVA_HOMEecho 'export JAVA_HOME=/usr/lib/jvm/java-11-openjdk' | sudo tee /etc/profile.d/java.shsource /etc/profile.d/java.shStep 3: Configure System Limits
Section titled “Step 3: Configure System Limits”# Create limits filesudo tee /etc/security/limits.d/cassandra.conf << 'EOF'cassandra - memlock unlimitedcassandra - nofile 100000cassandra - nproc 32768cassandra - as unlimitedEOF
# For RHEL 7+, also configure systemd limitssudo mkdir -p /etc/systemd/system/cassandra.service.d/sudo tee /etc/systemd/system/cassandra.service.d/limits.conf << 'EOF'[Service]LimitNOFILE=100000LimitNPROC=32768LimitMEMLOCK=infinityEOFStep 4: Disable THP and Configure Swap
Section titled “Step 4: Disable THP and Configure Swap”# Disable THP (same as Ubuntu)echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabledecho never | sudo tee /sys/kernel/mm/transparent_hugepage/defrag
# Create persistent service (same as Ubuntu section above)
# Disable swapsudo swapoff -asudo sed -i '/swap/d' /etc/fstabStep 5: Add Cassandra Repository
Section titled “Step 5: Add Cassandra Repository”# Create repo file for Cassandra 5.0sudo tee /etc/yum.repos.d/cassandra.repo << 'EOF'[cassandra]name=Apache Cassandrabaseurl=https://redhat.cassandra.apache.org/50x/gpgcheck=1repo_gpgcheck=1gpgkey=https://downloads.apache.org/cassandra/KEYSenabled=1EOF
# Clean yum cache and verifysudo yum clean allsudo yum makecacheyum list available | grep cassandraStep 6: Install and Configure
Section titled “Step 6: Install and Configure”# Install Cassandrasudo yum install -y cassandra
# Stop service for configurationsudo systemctl stop cassandra
# Configure cassandra.yaml (same settings as Ubuntu section)sudo nano /etc/cassandra/conf/cassandra.yaml
# Configure JVM optionssudo nano /etc/cassandra/conf/jvm11-server.options
# Note: RHEL/CentOS config path is /etc/cassandra/conf/# Ubuntu/Debian config path is /etc/cassandra/Step 7: Start and Verify
Section titled “Step 7: Start and Verify”# Reload systemd for limit changessudo systemctl daemon-reload
# Start Cassandrasudo systemctl start cassandrasudo systemctl enable cassandra
# Verifynodetool statuscqlshMethod 2: Tarball Installation
Section titled “Method 2: Tarball Installation”Use tarball installation when needing:
- Multiple Cassandra versions on one machine
- Installation in non-standard locations
- No root/sudo access
- Complete control over the installation
Complete Tarball Installation
Section titled “Complete Tarball Installation”# Define versionCASSANDRA_VERSION="5.0.2"
# Create cassandra user (as root)sudo useradd -r -m -d /opt/cassandra -s /bin/bash cassandra
# Download Cassandracd /tmpwget https://downloads.apache.org/cassandra/${CASSANDRA_VERSION}/apache-cassandra-${CASSANDRA_VERSION}-bin.tar.gz
# Verify download integritywget https://downloads.apache.org/cassandra/${CASSANDRA_VERSION}/apache-cassandra-${CASSANDRA_VERSION}-bin.tar.gz.sha256sha256sum -c apache-cassandra-${CASSANDRA_VERSION}-bin.tar.gz.sha256# MUST output: apache-cassandra-X.X.X-bin.tar.gz: OK# If verification fails, re-download - file may be corrupted or tampered
# Also verify GPG signature for productionwget https://downloads.apache.org/cassandra/${CASSANDRA_VERSION}/apache-cassandra-${CASSANDRA_VERSION}-bin.tar.gz.ascwget https://downloads.apache.org/cassandra/KEYSgpg --import KEYSgpg --verify apache-cassandra-${CASSANDRA_VERSION}-bin.tar.gz.asc apache-cassandra-${CASSANDRA_VERSION}-bin.tar.gz# Should show "Good signature from"
# Extract to installation directorysudo tar -xzf apache-cassandra-${CASSANDRA_VERSION}-bin.tar.gz -C /opt/sudo mv /opt/apache-cassandra-${CASSANDRA_VERSION} /opt/cassandra-${CASSANDRA_VERSION}sudo ln -s /opt/cassandra-${CASSANDRA_VERSION} /opt/cassandra/current
# Create data directories on appropriate filesystems# Ideally: data on one SSD, commitlog on another SSDsudo mkdir -p /var/lib/cassandra/{data,commitlog,saved_caches,hints}sudo mkdir -p /var/log/cassandra
# Set ownershipsudo chown -R cassandra:cassandra /opt/cassandra-${CASSANDRA_VERSION}sudo chown -R cassandra:cassandra /opt/cassandrasudo chown -R cassandra:cassandra /var/lib/cassandrasudo chown -R cassandra:cassandra /var/log/cassandra
# Set permissionssudo chmod 750 /var/lib/cassandrasudo chmod 750 /var/log/cassandraConfigure Environment
Section titled “Configure Environment”# Create environment filesudo tee /etc/profile.d/cassandra.sh << 'EOF'export CASSANDRA_HOME=/opt/cassandra/currentexport PATH=$PATH:$CASSANDRA_HOME/binEOF
# Apply to current sessionsource /etc/profile.d/cassandra.sh
# Also set in cassandra user's profilesudo -u cassandra bash -c 'echo "export CASSANDRA_HOME=/opt/cassandra/current" >> ~/.bashrc'sudo -u cassandra bash -c 'echo "export PATH=\$PATH:\$CASSANDRA_HOME/bin" >> ~/.bashrc'Configure Cassandra
Section titled “Configure Cassandra”# Edit main configurationsudo -u cassandra nano /opt/cassandra/current/conf/cassandra.yaml
# Key changes - update directory paths:# data_file_directories:# - /var/lib/cassandra/data# commitlog_directory: /var/lib/cassandra/commitlog# saved_caches_directory: /var/lib/cassandra/saved_caches# hints_directory: /var/lib/cassandra/hints
# Update cassandra-env.sh for loggingsudo -u cassandra nano /opt/cassandra/current/conf/cassandra-env.sh# Find and update:# export CASSANDRA_LOG_DIR=/var/log/cassandraCreate systemd Service
Section titled “Create systemd Service”sudo tee /etc/systemd/system/cassandra.service << 'EOF'[Unit]Description=Apache Cassandra DatabaseDocumentation=https://cassandra.apache.org/doc/latest/After=network-online.targetWants=network-online.target
[Service]Type=forkingUser=cassandraGroup=cassandraEnvironment="CASSANDRA_HOME=/opt/cassandra/current"Environment="CASSANDRA_CONF=/opt/cassandra/current/conf"Environment="CASSANDRA_LOG_DIR=/var/log/cassandra"PIDFile=/var/run/cassandra/cassandra.pidExecStartPre=/bin/mkdir -p /var/run/cassandraExecStartPre=/bin/chown cassandra:cassandra /var/run/cassandraExecStart=/opt/cassandra/current/bin/cassandra -p /var/run/cassandra/cassandra.pid -RExecStop=/opt/cassandra/current/bin/nodetool drainStandardOutput=journalStandardError=journal
# Resource limitsLimitNOFILE=100000LimitMEMLOCK=infinityLimitNPROC=32768LimitAS=infinity
# Restart behaviorRestart=on-failureRestartSec=30sTimeoutStartSec=180TimeoutStopSec=180
[Install]WantedBy=multi-user.targetEOF
# Reload and startsudo systemctl daemon-reloadsudo systemctl start cassandrasudo systemctl enable cassandra
# Verifysudo systemctl status cassandranodetool statusMethod 3: Docker Installation
Section titled “Method 3: Docker Installation”Docker Use Cases
Docker is excellent for development, CI/CD pipelines, and learning. For production, consider Kubernetes operators instead.
Development: Single Node
Section titled “Development: Single Node”# Basic single nodedocker run --name cassandra-dev \ -d \ -p 9042:9042 \ -e CASSANDRA_CLUSTER_NAME=DevCluster \ -e HEAP_NEWSIZE=256M \ -e MAX_HEAP_SIZE=1G \ cassandra:5.0
# With persistent data (survives container restarts)docker volume create cassandra-data
docker run --name cassandra-dev \ -d \ -p 9042:9042 \ -v cassandra-data:/var/lib/cassandra \ -e CASSANDRA_CLUSTER_NAME=DevCluster \ -e HEAP_NEWSIZE=256M \ -e MAX_HEAP_SIZE=1G \ cassandra:5.0
# Check logs for startup completiondocker logs -f cassandra-dev# Wait for: "Starting listening for CQL clients on /0.0.0.0:9042"
# Connectdocker exec -it cassandra-dev cqlsh
# Or use CQLAI from host (if installed)cqlai -h localhost -p 9042Development: Multi-Node Cluster
Section titled “Development: Multi-Node Cluster”docker-compose.yml for 3-node cluster:
version: '3.8'
# IMPORTANT: This is for development/testing only# Production deployments should use Kubernetes operators
services: cassandra-seed: image: cassandra:5.0 container_name: cassandra-seed hostname: cassandra-seed ports: - "9042:9042" # CQL - "7199:7199" # JMX environment: - CASSANDRA_CLUSTER_NAME=DockerCluster - CASSANDRA_DC=dc1 - CASSANDRA_RACK=rack1 - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch - CASSANDRA_NUM_TOKENS=16 - HEAP_NEWSIZE=256M - MAX_HEAP_SIZE=1G volumes: - cassandra-seed-data:/var/lib/cassandra networks: - cassandra-net healthcheck: test: ["CMD", "cqlsh", "-e", "describe cluster"] interval: 30s timeout: 10s retries: 10 start_period: 60s
cassandra-node1: image: cassandra:5.0 container_name: cassandra-node1 hostname: cassandra-node1 depends_on: cassandra-seed: condition: service_healthy environment: - CASSANDRA_CLUSTER_NAME=DockerCluster - CASSANDRA_DC=dc1 - CASSANDRA_RACK=rack1 - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch - CASSANDRA_SEEDS=cassandra-seed - CASSANDRA_NUM_TOKENS=16 - HEAP_NEWSIZE=256M - MAX_HEAP_SIZE=1G volumes: - cassandra-node1-data:/var/lib/cassandra networks: - cassandra-net healthcheck: test: ["CMD", "cqlsh", "-e", "describe cluster"] interval: 30s timeout: 10s retries: 10 start_period: 60s
cassandra-node2: image: cassandra:5.0 container_name: cassandra-node2 hostname: cassandra-node2 depends_on: cassandra-node1: condition: service_healthy environment: - CASSANDRA_CLUSTER_NAME=DockerCluster - CASSANDRA_DC=dc1 - CASSANDRA_RACK=rack1 - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch - CASSANDRA_SEEDS=cassandra-seed - CASSANDRA_NUM_TOKENS=16 - HEAP_NEWSIZE=256M - MAX_HEAP_SIZE=1G volumes: - cassandra-node2-data:/var/lib/cassandra networks: - cassandra-net
volumes: cassandra-seed-data: cassandra-node1-data: cassandra-node2-data:
networks: cassandra-net: driver: bridgeStart the cluster:
# Start seed node first (health check ensures it is ready)docker-compose up -d cassandra-seed
# Wait for seed to be healthy (watch for healthy status)docker-compose ps# Wait until cassandra-seed shows "healthy"
# Start remaining nodes (depends_on + health check handles ordering)docker-compose up -d
# Monitor startupdocker-compose logs -f
# Check cluster statusdocker exec -it cassandra-seed nodetool status# All nodes should show UN (Up Normal)Cleanup:
# Stop clusterdocker-compose down
# Stop and remove data (DESTROYS DATA)docker-compose down -vMethod 4: Kubernetes Installation
Section titled “Method 4: Kubernetes Installation”Use an Operator
For Kubernetes, use an operator rather than raw StatefulSets. Operators handle complex operations like scaling, repairs, and upgrades.
Option A: K8ssandra (Recommended)
Section titled “Option A: K8ssandra (Recommended)”K8ssandra is a production-ready distribution that includes Cassandra, Stargate (APIs), Reaper (repairs), Medusa (backups), and monitoring.
# Prerequisites# - Kubernetes 1.21+# - kubectl configured# - Helm 3.x# - cert-manager installed
# Install cert-manager (required)kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
# Wait for cert-managerkubectl wait --for=condition=Available deployment --all -n cert-manager --timeout=300s
# Add K8ssandra Helm repohelm repo add k8ssandra https://helm.k8ssandra.io/stablehelm repo update
# Install K8ssandra operatorhelm install k8ssandra-operator k8ssandra/k8ssandra-operator \ -n k8ssandra-operator \ --create-namespace \ --wait
# Verify operator is runningkubectl get pods -n k8ssandra-operatorCreate a Cassandra cluster:
apiVersion: k8ssandra.io/v1alpha1kind: K8ssandraClustermetadata: name: production namespace: k8ssandra-operatorspec: cassandra: serverVersion: "4.1.3" serverImage: "k8ssandra/cass-management-api:4.1.3"
# Cluster topology datacenters: - metadata: name: dc1 size: 3 # Number of nodes
# Storage configuration storageConfig: cassandraDataVolumeClaimSpec: storageClassName: fast-ssd # Use appropriate storage class accessModes: - ReadWriteOnce resources: requests: storage: 100Gi
# Resource allocation resources: requests: cpu: 2000m memory: 8Gi limits: cpu: 4000m memory: 16Gi
# JVM settings config: jvmOptions: heapSize: 4Gi heapNewGenSize: 1Gi
# Cassandra configuration overrides config: cassandraYaml: num_tokens: 16 allocate_tokens_for_local_replication_factor: 3 concurrent_reads: 32 concurrent_writes: 32 concurrent_counter_writes: 32
# Authentication superuserSecretRef: name: cassandra-superuser
# Reaper for repairs (optional but recommended) reaper: autoScheduling: enabled: true
# Medusa for backups (optional) medusa: storageProperties: storageProvider: s3 region: us-east-1 bucketName: my-cassandra-backups storageSecretRef: name: medusa-bucket-secretDeploy:
# Create superuser secretkubectl create secret generic cassandra-superuser \ -n k8ssandra-operator \ --from-literal=username=admin \ --from-literal=password='YourSecurePassword123!'
# Apply cluster configurationkubectl apply -f k8ssandra-cluster.yaml
# Watch pods come up (takes 5-10 minutes)kubectl get pods -n k8ssandra-operator -w
# Check cluster statuskubectl exec -it production-dc1-default-sts-0 -n k8ssandra-operator -- nodetool statusOption B: Cass-Operator (DataStax)
Section titled “Option B: Cass-Operator (DataStax)”# Install Cass-Operatorkubectl apply -f https://raw.githubusercontent.com/k8ssandra/cass-operator/v1.18.2/docs/user/cass-operator-manifests.yaml
# Create namespace for clusterkubectl create namespace cassandra
# Create clusterkubectl apply -f - <<EOFapiVersion: cassandra.datastax.com/v1beta1kind: CassandraDatacentermetadata: name: dc1 namespace: cassandraspec: clusterName: production serverType: cassandra serverVersion: "4.1.3" managementApiAuth: insecure: {} size: 3 storageConfig: cassandraDataVolumeClaimSpec: storageClassName: fast-ssd accessModes: - ReadWriteOnce resources: requests: storage: 100Gi resources: requests: memory: 8Gi cpu: 2000m limits: memory: 16Gi cpu: 4000m config: cassandra-yaml: num_tokens: 16 jvm-server-options: initial_heap_size: 4G max_heap_size: 4GEOFMethod 5: Ansible Automation (Recommended for Production)
Section titled “Method 5: Ansible Automation (Recommended for Production)”For automated, repeatable deployments across multiple environments, the AxonOps Ansible Collection provides production-grade installation of Apache Cassandra with optional AxonOps monitoring integration.
Standalone Cassandra Installation
The Cassandra role in this collection is fully standalone. You can deploy a production-ready Apache Cassandra cluster without using AxonOps. The collection handles all the complex configuration, OS tuning, and best practices automatically.
Ready-to-Use Reference Implementation
For a complete, production-grade example you can clone and adapt, see the AxonOps Cassandra Lab. This project demonstrates a multi-datacenter Cassandra 5.0 deployment with Terraform infrastructure provisioning and complete Ansible configuration, including SSL/TLS, authentication, audit logging, and AxonOps monitoring.
Why Use Ansible for Cassandra?
Section titled “Why Use Ansible for Cassandra?”| Benefit | Description |
|---|---|
| Production-Ready | Implements all OS tuning, limits, THP disabling, and Cassandra best practices automatically |
| Repeatable | Same playbook deploys identical clusters across dev, staging, and production |
| Multi-Version | Supports Cassandra 3.11, 4.x, and 5.x with version-specific configurations |
| Tarball-Based | Default tar installation simplifies upgrades and downgrades vs package managers |
| Optional Monitoring | Add axon-agent for monitoring (SaaS or self-hosted) only if needed |
| Idempotent | Run playbooks repeatedly without breaking existing installations |
| Multi-Environment | Hierarchical configuration supports dev, staging, and production from one codebase |
Prerequisites
Section titled “Prerequisites”- Ansible 2.9+ installed on control machine
- SSH access to target nodes (key-based authentication recommended)
- Target nodes running supported Linux (RHEL/CentOS 7+, Ubuntu 18.04+, Debian 10+)
- Python 3.x on target nodes
- (Optional) Pipenv for isolated Python environments
Quick Start: Install the Collection
Section titled “Quick Start: Install the Collection”# Download the latest releasecurl -L -o axonops-ansible.tar.gz \ https://github.com/axonops/axonops-ansible-collection/releases/latest/download/axonops-axonops-latest.tar.gz
# Install the collectionansible-galaxy collection install axonops-ansible.tar.gz
# Verify installationansible-galaxy collection list | grep axonopsAvailable Roles
Section titled “Available Roles”The collection provides roles for complete infrastructure deployment:
| Role | Purpose |
|---|---|
axonops.axonops.preflight | Pre-installation system checks and validation |
axonops.axonops.java | Install Java (OpenJDK or Azul Zulu) |
axonops.axonops.cassandra | Install and configure Apache Cassandra |
axonops.axonops.agent | Install AxonOps monitoring agent |
axonops.axonops.server | Install AxonOps Server (self-hosted) |
axonops.axonops.dash | Install AxonOps Dashboard (self-hosted) |
axonops.axonops.elastic | Install Elasticsearch for AxonOps |
axonops.axonops.configurations | Configure alerts, integrations, backups |
Option A: Simple Deployment (Single Environment)
Section titled “Option A: Simple Deployment (Single Environment)”For a straightforward deployment without multi-environment complexity:
inventory.yml:
all: children: cassandra: hosts: cass-node1: ansible_host: 192.168.1.10 cassandra_rack: rack1 cass-node2: ansible_host: 192.168.1.11 cassandra_rack: rack2 cass-node3: ansible_host: 192.168.1.12 cassandra_rack: rack3 vars: # Cassandra configuration cassandra_cluster_name: "ProductionCluster" cassandra_version: "5.0.5" cassandra_dc: "dc1"
# Installation method (tar recommended) cassandra_install_format: tar
# Java configuration java_pkg: "java-17-openjdk-headless"
# Seed nodes (first 2-3 nodes) cassandra_seeds: - 192.168.1.10 - 192.168.1.11
# Security settings cassandra_authenticator: PasswordAuthenticator cassandra_authorizer: CassandraAuthorizercassandra.yml playbook:
---- name: Deploy Apache Cassandra Cluster hosts: cassandra become: true
roles: - role: axonops.axonops.preflight - role: axonops.axonops.java - role: axonops.axonops.cassandraDeploy:
ansible-playbook -i inventory.yml cassandra.ymlOption B: Production Multi-Environment Structure
Section titled “Option B: Production Multi-Environment Structure”For production deployments, use hierarchical configuration with group_vars for environment-specific overrides. This structure is demonstrated in the full example.
Recommended project structure:
my-cassandra-deployment/├── ansible.cfg├── Makefile├── requirements.yml│├── inventories/│ ├── dev/hosts.ini│ ├── stg/hosts.ini│ └── prd/hosts.ini│├── group_vars/│ ├── all/ # Global defaults│ │ ├── cassandra.yml # Cassandra defaults│ │ ├── java.yml # Java configuration│ │ └── common.yml # OS settings│ ├── dev/ # Development overrides│ │ ├── cassandra.yml│ │ └── vault.yml # Encrypted secrets│ ├── stg/ # Staging overrides│ │ ├── cassandra.yml│ │ └── vault.yml│ └── prd/ # Production overrides│ ├── cassandra.yml│ └── vault.yml│├── files/│ ├── dev/ssl/ # Dev certificates│ ├── stg/ssl/ # Staging certificates│ └── prd/ssl/ # Production certificates│├── alerts-config/ # AxonOps monitoring (optional)│ └── my-org/│ ├── alert_endpoints.yml│ ├── metric_alert_rules.yml│ └── prd/ # Cluster-specific overrides│ └── alert_routes.yml│├── cassandra.yml # Main playbook├── common.yml # OS hardening playbook└── rolling-restart.yml # Safe restart playbookExample inventories/prd/hosts.ini:
[cassandra]cass-prd-1 ansible_host=10.0.1.10 cassandra_rack=rack1cass-prd-2 ansible_host=10.0.1.11 cassandra_rack=rack2cass-prd-3 ansible_host=10.0.1.12 cassandra_rack=rack3cass-prd-4 ansible_host=10.0.2.10 cassandra_rack=rack1 cassandra_dc=dc2cass-prd-5 ansible_host=10.0.2.11 cassandra_rack=rack2 cassandra_dc=dc2cass-prd-6 ansible_host=10.0.2.12 cassandra_rack=rack3 cassandra_dc=dc2
[cassandra:vars]cassandra_dc=dc1Example group_vars/all/cassandra.yml (global defaults):
# Cassandra version and installationcassandra_version: "5.0.5"cassandra_install_format: tar
# Cluster defaultscassandra_num_tokens: 16cassandra_endpoint_snitch: GossipingPropertyFileSnitch
# Performance tuningcassandra_concurrent_reads: 32cassandra_concurrent_writes: 32cassandra_concurrent_counter_writes: 32cassandra_memtable_flush_writers: 2
# Security defaultscassandra_authenticator: PasswordAuthenticatorcassandra_authorizer: CassandraAuthorizercassandra_role_manager: CassandraRoleManager
# Audit loggingcassandra_audit_logging_enabled: truecassandra_audit_logging_included_categories: DDL,DCL,AUTH,ERRORExample group_vars/prd/cassandra.yml (production overrides):
# Production cluster namecassandra_cluster_name: "Production-Cassandra"
# Production seedscassandra_seeds: - 10.0.1.10 - 10.0.1.11 - 10.0.2.10
# Production performance tuningcassandra_concurrent_reads: 64cassandra_concurrent_writes: 64
# Enable SSL in productioncassandra_ssl_enable: truecassandra_ssl_internode: truecassandra_ssl_client: trueSecrets Management with Ansible Vault
Section titled “Secrets Management with Ansible Vault”Encrypt sensitive configuration using Ansible Vault:
# Create vault password file (do not commit to Git)echo "your-secure-password" > ~/.ansible_vault_passchmod 600 ~/.ansible_vault_pass
# Create encrypted secrets fileansible-vault create group_vars/prd/vault.ymlExample vault.yml content:
# Cassandra credentialsvault_cassandra_admin_password: "SecurePassword123!"vault_cassandra_jmx_password: "JmxSecurePass456!"
# SSL keystore passwordsvault_cassandra_ssl_keystore_pass: "keystorepass"vault_cassandra_ssl_truststore_pass: "truststorepass"
# AxonOps credentials (if using)vault_axon_agent_key: "your-agent-key-from-axonops"vault_axon_agent_customer_name: "your-org-name"Reference vault variables in playbooks:
# In group_vars/prd/cassandra.ymlcassandra_admin_password: "{{ vault_cassandra_admin_password }}"cassandra_ssl_keystore_password: "{{ vault_cassandra_ssl_keystore_pass }}"Makefile Workflow
Section titled “Makefile Workflow”Use a Makefile for consistent deployment commands:
ENVIRONMENT ?= devANSIBLE_USER ?= rootANSIBLE_VAULT_PASSWORD_FILE ?= ~/.ansible_vault_passEXTRA ?=
.PHONY: prep common cassandra alerts rolling-restart
prep: ansible-galaxy collection install -r requirements.yml
common: ansible-playbook -i inventories/$(ENVIRONMENT)/hosts.ini \ -u $(ANSIBLE_USER) \ --vault-password-file $(ANSIBLE_VAULT_PASSWORD_FILE) \ common.yml $(EXTRA)
cassandra: ansible-playbook -i inventories/$(ENVIRONMENT)/hosts.ini \ -u $(ANSIBLE_USER) \ --vault-password-file $(ANSIBLE_VAULT_PASSWORD_FILE) \ cassandra.yml $(EXTRA)
alerts: ansible-playbook -i inventories/$(ENVIRONMENT)/hosts.ini \ -u $(ANSIBLE_USER) \ --vault-password-file $(ANSIBLE_VAULT_PASSWORD_FILE) \ alerts.yml $(EXTRA)
rolling-restart: ansible-playbook -i inventories/$(ENVIRONMENT)/hosts.ini \ -u $(ANSIBLE_USER) \ --vault-password-file $(ANSIBLE_VAULT_PASSWORD_FILE) \ rolling-restart.yml $(EXTRA)Deploy to different environments:
# Deploy to developmentmake cassandra ENVIRONMENT=dev
# Deploy to productionmake cassandra ENVIRONMENT=prd
# Dry-run to production (no changes)make cassandra ENVIRONMENT=prd EXTRA="--check --diff"
# Update configuration only (no reinstall)make cassandra ENVIRONMENT=prd EXTRA="--tags config"SSL/TLS Configuration
Section titled “SSL/TLS Configuration”Development (auto-generated self-signed certificates):
cassandra_ssl_enable: truecassandra_ssl_create: true # Auto-generate certificatesCertificates are stored in files/dev/ssl/ and SHOULD be committed to Git for development consistency.
Production (organization-managed certificates):
cassandra_ssl_enable: truecassandra_ssl_create: false # Use provided certificatescassandra_ssl_keystore_password: "{{ vault_cassandra_ssl_keystore_pass }}"cassandra_ssl_truststore_password: "{{ vault_cassandra_ssl_truststore_pass }}"Place CA-signed certificates in files/prd/ssl/ (encrypted or via external secrets management).
Adding AxonOps Monitoring
Section titled “Adding AxonOps Monitoring”Add the axon-agent role to enable monitoring:
cassandra.yml playbook with monitoring:
---- name: Deploy Apache Cassandra with AxonOps Monitoring hosts: cassandra become: true
roles: - role: axonops.axonops.preflight - role: axonops.axonops.java - role: axonops.axonops.cassandra - role: axonops.axonops.agentgroup_vars/prd/axonops.yml:
# AxonOps Cloudaxon_agent_server_host: "agents.axonops.cloud"axon_agent_customer_name: "{{ vault_axon_agent_customer_name }}"axon_agent_key: "{{ vault_axon_agent_key }}"axon_java_agent: "axon-cassandra5.0-agent"
# Or for self-hosted AxonOps:# axon_agent_server_host: "axonops.internal.example.com"AxonOps Configuration as Code
Section titled “AxonOps Configuration as Code”Configure monitoring, alerts, and backups via YAML files in alerts-config/:
alerts-config/└── my-org/ # Organization name ├── alert_endpoints.yml # Slack, PagerDuty, email ├── metric_alert_rules.yml # Default metric alerts ├── log_alert_rules.yml # Log-based alerts ├── service_checks.yml # Health checks └── prd/ # Cluster-specific overrides ├── alert_routes.yml # Route alerts to endpoints ├── backups.yml # Backup schedules └── dashboards.yml # Custom dashboardsExample alert_endpoints.yml:
endpoints: - name: slack-ops type: slack webhook_url: "{{ vault_slack_webhook_url }}" channel: "#cassandra-alerts"
- name: pagerduty-critical type: pagerduty routing_key: "{{ vault_pagerduty_routing_key }}"Apply monitoring configuration:
make alerts ENVIRONMENT=prdKey Configuration Variables
Section titled “Key Configuration Variables”| Variable | Default | Description |
|---|---|---|
cassandra_version | Latest | Cassandra version (e.g., 5.0.5, 4.1.6) |
cassandra_install_format | tar | Installation method: tar (recommended) or pkg |
cassandra_cluster_name | Test Cluster | Cluster name (MUST match all nodes) |
cassandra_dc | dc1 | Datacenter name |
cassandra_rack | rack1 | Rack name |
cassandra_seeds | [] | Seed node IPs |
cassandra_num_tokens | 16 | Number of virtual nodes |
cassandra_authenticator | AllowAllAuthenticator | Authentication class |
cassandra_authorizer | AllowAllAuthorizer | Authorization class |
cassandra_ssl_enable | false | Enable SSL/TLS |
cassandra_ssl_create | false | Auto-generate certificates |
cassandra_audit_logging_enabled | false | Enable audit logging |
java_pkg | java-11-openjdk-headless | Java package |
axon_java_agent | - | axon-agent version |
axon_agent_server_host | - | axon-server address |
What the Cassandra Role Configures
Section titled “What the Cassandra Role Configures”The role automatically handles all production requirements:
- OS Configuration: File descriptor limits (100,000+), nproc limits, memory locking
- Transparent Huge Pages: Disabled automatically
- Swap Configuration: Configured for Cassandra workloads
- Directory Structure: Creates data, commitlog, hints, saved_caches with correct permissions
- cassandra.yaml: Complete configuration including cluster settings, networking, snitch, tokens
- JVM Options: Heap sizing (auto-calculated or manual), GC settings, JMX configuration
- Security: Authentication, authorization, SSL/TLS, audit logging
- Systemd Service: Creates and enables the Cassandra service
- Firewall Rules: Opens required ports if firewalld is active
Common Operations
Section titled “Common Operations”Rolling restart (zero-downtime):
make rolling-restart ENVIRONMENT=prdThe rolling restart playbook:
- Checks cluster health before starting
- Drains each node before restart
- Waits for node to rejoin cluster
- Verifies cluster health before proceeding to next node
Configuration update (no reinstall):
# Edit configurationvim group_vars/prd/cassandra.yml
# Apply config changes onlymake cassandra ENVIRONMENT=prd EXTRA="--tags config"
# Restart to applymake rolling-restart ENVIRONMENT=prdUpgrade Cassandra version:
# Update version in group_varscassandra_version: "5.0.7"# Apply upgrademake cassandra ENVIRONMENT=prd -e "cassandra_upgrade=true"
# Rolling restart to complete upgrademake rolling-restart ENVIRONMENT=prdTroubleshooting
Section titled “Troubleshooting”# Test connectivity to all nodesansible -i inventories/prd/hosts.ini cassandra -m ping
# Run with verbose outputmake cassandra ENVIRONMENT=prd EXTRA="-vvv"
# Run only preflight checksmake cassandra ENVIRONMENT=prd EXTRA="--tags preflight"
# Check cluster status across all nodesansible -i inventories/prd/hosts.ini cassandra -a "nodetool status"
# View Cassandra logsansible -i inventories/prd/hosts.ini cassandra -a "tail -50 /var/log/cassandra/system.log"
# Check axon-agent statusansible -i inventories/prd/hosts.ini cassandra -a "systemctl status axon-agent"Reference Implementation: AxonOps Cassandra Lab
Section titled “Reference Implementation: AxonOps Cassandra Lab”For a complete, working example that you can clone and adapt, see the AxonOps Cassandra Lab:
- Multi-datacenter: 12 nodes across 2 DCs with 3 racks each
- Infrastructure as Code: Terraform for Hetzner Cloud (adaptable to other providers)
- Complete security: SSL/TLS, authentication, authorization, audit logging
- AxonOps integration: Full monitoring, alerting, and backup configuration
- Web terminal: Wetty-based browser access to cluster
- Workbench integration: AxonOps Workbench configuration included
# Clone the lab projectgit clone https://github.com/axonops/ansible-cassandra-lab.gitcd ansible-cassandra-lab
# Review and adapt configurationcat ansible/group_vars/all/cassandra.yml
# Deploy (after configuring infrastructure)cd ansiblemake cassandra ENVIRONMENT=labAdditional Resources
Section titled “Additional Resources”- Ansible Collection: axonops/axonops-ansible-collection
- Full Example: examples/full-example
- Cassandra Lab: axonops/ansible-cassandra-lab
- AxonOps Cloud Setup: Getting Started with AxonOps Cloud
- AxonOps Self-Hosted: Installing AxonOps Server
Prefer Chef?
If your organization uses Chef instead of Ansible, see the AxonOps Chef Cookbook for similar functionality.
Post-Installation Validation Checklist
Section titled “Post-Installation Validation Checklist”After any installation method, verify these items:
1. Cluster Health
Section titled “1. Cluster Health”# Check all nodes are upnodetool status# All nodes should show 'UN' (Up Normal)
# Check for schema agreementnodetool describecluster# Schema versions should show single version (all nodes agree)
# Check gossip informationnodetool gossipinfo# Should show status=NORMAL for all nodes2. Basic Functionality
Section titled “2. Basic Functionality”-- Connect and verifycqlsh
-- Check cluster infoDESCRIBE CLUSTER;
-- Test writeCREATE KEYSPACE IF NOT EXISTS system_check WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': 1};
USE system_check;
CREATE TABLE IF NOT EXISTS health_check ( check_id uuid PRIMARY KEY, check_time timestamp, status text);
INSERT INTO health_check (check_id, check_time, status)VALUES (uuid(), toTimestamp(now()), 'OK');
-- Test readSELECT * FROM health_check;
-- CleanupDROP KEYSPACE system_check;3. Resource Verification
Section titled “3. Resource Verification”# Check file descriptor limitscat /proc/$(pgrep -f CassandraDaemon)/limits | grep "open files"# Should show at least 100000
# Check THP is disabledcat /sys/kernel/mm/transparent_hugepage/enabled# Should show: always madvise [never]
# Check heap sizenodetool info | grep "Heap Memory"# Should match the configured heap size
# Check GC typenodetool gcstats# Shows GC statistics and type4. Performance Baseline
Section titled “4. Performance Baseline”# Run a quick benchmarkcassandra-stress write n=10000 -rate threads=4
# Expected output for healthy system:# Op rate: > 1000 ops/sec# Latency mean: < 10ms# Latency 99th: < 100msTroubleshooting Installation Issues
Section titled “Troubleshooting Installation Issues”Issue: Cassandra Won't Start
Section titled “Issue: Cassandra Won't Start”# Check the logs first - ALWAYSsudo tail -100 /var/log/cassandra/system.logsudo journalctl -u cassandra -n 100
# Common causes and solutions:
# 1. Java not found# Error: "Unable to find java executable"# Solution: Install JDK 11 and set JAVA_HOMEwhich javaecho $JAVA_HOME
# 2. Port already in use# Error: "java.net.BindException: Address already in use"# Solution: Find and stop conflicting processsudo lsof -i :9042sudo lsof -i :7000sudo lsof -i :7199
# 3. Out of memory# Error: "java.lang.OutOfMemoryError"# Solution: Reduce heap size or add more RAMfree -h # Check available memory
# 4. Permission denied# Error: "AccessDeniedException" or "Permission denied"# Solution: Fix ownershipsudo chown -R cassandra:cassandra /var/lib/cassandrasudo chown -R cassandra:cassandra /var/log/cassandra
# 5. Corrupt system tables (after crash)# Error: "CorruptSSTableException" on startup# Solution: Try removing corrupt files (DANGEROUS - last resort)# First try: nodetool scrub system# If that fails, examine which file is corrupt from logsIssue: cqlsh Connection Refused
Section titled “Issue: cqlsh Connection Refused”# Is Cassandra actually running?sudo systemctl status cassandraps aux | grep cassandra
# Is native transport enabled and listening?grep "native_transport_port" /etc/cassandra/cassandra.yamlsudo netstat -tlnp | grep 9042
# Check if startup completedsudo tail /var/log/cassandra/system.log | grep "Starting listening for CQL"
# Try connecting with explicit hostcqlsh 127.0.0.1 9042 --debug
# Check rpc_address settinggrep "rpc_address" /etc/cassandra/cassandra.yaml# If rpc_address: 0.0.0.0, also set broadcast_rpc_address to the node IPIssue: Node Won't Join Cluster
Section titled “Issue: Node Won't Join Cluster”# Check seeds are reachableping <seed_ip>telnet <seed_ip> 7000 # Gossip port
# Check cluster_name matches exactlygrep cluster_name /etc/cassandra/cassandra.yaml# Must be IDENTICAL on all nodes, including spaces and case
# Check tokens are not conflictingnodetool ring | head
# Look for gossip issuesgrep -i gossip /var/log/cassandra/system.log | tail -20
# Verify snitch is consistent across clustergrep endpoint_snitch /etc/cassandra/cassandra.yaml# All nodes should use same snitchIssue: Slow Performance After Installation
Section titled “Issue: Slow Performance After Installation”# Check THP is actually disabledcat /sys/kernel/mm/transparent_hugepage/enabled# Must show [never]
# Check swap usagefree -h# Swap used should be 0 or nearly 0
# Check GC behaviornodetool gcstats# G1 or ZGC should be in use, not CMS
# Check compaction is not backed upnodetool compactionstats# Pending tasks should be low (< 10)
# Check disk I/Oiostat -xm 2# await should be < 5ms for SSD# %util should be < 80%Next Steps After Installation
Section titled “Next Steps After Installation”- Configure the Cluster - Multi-node setup and networking
- Security Setup - Enable authentication and encryption
- Production Checklist - Complete production readiness
- Install CQLAI - Modern CQL shell with AI assistance
- Set Up Monitoring - Monitor the cluster with AxonOps