Deploy ScyllaDB with Portworx
ScyllaDB is a NoSQL database that aims to provide low latency and high throughput. This article shows how you can create and run a ScyllaDB cluster on Kubernetes, which stores data on Portworx volumes.
To deploy ScyllaDB with Portworx Enterprise, complete the following collection of tasks:
Create a StorageClass
-
Use the following command to list the nodes in your cluster:
kubectl get nodes -o wideNAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIMExxxx-blr-dev-dour-shoulder-0 Ready master 103d v1.14.1 X.X.X.119 <none> CentOS Linux 7 (Core) 3.10.0-862.3.2.el7.x86_64 docker://18.9.6xxxx-blr-dev-dour-shoulder-1 Ready <none> 16d v1.14.1 X.X.X.82 <none> CentOS Linux 7 (Core) 3.10.0-862.3.2.el7.x86_64 docker://18.9.6xxxx-blr-dev-dour-shoulder-2 Ready <none> 103d v1.14.1 X.X.X.118 <none> CentOS Linux 7 (Core) 3.10.0-862.3.2.el7.x86_64 docker://18.9.6xxxx-blr-dev-dour-shoulder-3 Ready <none> 103d v1.14.1 X.X.X.120 <none> CentOS Linux 7 (Core) 3.10.0-862.3.2.el7.x86_64 docker://18.9.6 -
Define the following
portworx-sc.yamlStorageClass:kind: StorageClassapiVersion: storage.k8s.io/v1metadata:name: scylla-ssdprovisioner: pxd.portworx.comparameters:repl: "2"reclaimPolicy: DeletevolumeBindingMode: ImmediateallowVolumeExpansion: true -
Apply the StorageClass configuration:
kubectl apply -f portworx-sc.yml
Deploy ScyllaDB
-
Create a file called
scylla-configmap.yamlwith the following content:apiVersion: v1kind: ConfigMapmetadata:name: scylladata:ready-probe.sh: |#!/bin/bashif [[ $(nodetool status | grep $POD_IP) == *"UN"* ]]; thenif [[ $DEBUG ]]; thenecho "UN";fiexit 0;elseif [[ $DEBUG ]]; thenecho "Not Up";fiexit 1;fi -
Apply the ConfigMap:
kubectl apply -f scylla-configmap.yaml -
Create a file called
scylla-service.yamlwith the following content:apiVersion: v1kind: Servicemetadata:labels:app: scyllaname: scyllaspec:clusterIP: Noneports:- port: 9042selector:app: scylla -
Apply the Service:
kubectl apply -f scylla-service.yaml -
The spec below creates StatefulSet for ScyllaDB with 3 replicas and uses the Stork scheduler to place pods to closer to where their data is located. Create a file called
scylla-statefulset.yamlwith the following content:apiVersion: apps/v1kind: StatefulSetmetadata:name: scyllalabels:app: scyllaspec:serviceName: scyllareplicas: 3selector:matchLabels:app: scyllatemplate:metadata:labels:app: scyllaspec:schedulerName: storkcontainers:- name: scyllaimage: scylladb/scylla:2.0.0imagePullPolicy: IfNotPresentargs: ["--seeds", "scylla-0.scylla.default.svc.cluster.local"]ports:- containerPort: 7000name: intra-node- containerPort: 7001name: tls-intra-node- containerPort: 7199name: jmx- containerPort: 9042name: cqlresources:limits:cpu: 2memory: 4Girequests:cpu: 2memory: 4GisecurityContext:capabilities:add:- IPC_LOCKlifecycle:preStop:exec:command: ["/bin/sh", "-c", "PID=$(pidof scylla) && kill $PID && while ps -p $PID > /dev/null; do sleep 1; done"]env:- name: POD_IPvalueFrom:fieldRef:fieldPath: status.podIPreadinessProbe:exec:command:- /bin/bash- -c- exec- /opt/ready-probe.shinitialDelaySeconds: 15timeoutSeconds: 5volumeMounts:- name: scylla-datamountPath: /var/lib/scylla- name: scylla-ready-probemountPath: /opt/ready-probe.shsubPath: ready-probe.shvolumes:- name: scylla-ready-probeconfigMap:name: scyllavolumeClaimTemplates:- metadata:name: scylla-dataannotations:volume.beta.kubernetes.io/storage-class: scylla-ssdspec:accessModes: ["ReadWriteOnce"]resources:requests:storage: 60Gi -
Apply the
scylla-statefulset.yamlStatefulSet:kubectl apply -f scylla-statefulset.yaml
Verify ScyllaDB Deployment
-
Enter the
kubectl get pvccommand to verify that the PVCs are bound to a volume using the storage class. The PVC status shows asBoundif the operation succeeded:kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEscylla-data-scylla-0 Bound pvc-xxxxxxxx-xxxx-xxxx-xxxx-000c29886e3e 60Gi RWO scylla-ssd 3hscylla-data-scylla-1 Bound pvc-xxxxxxxx-xxxx-xxxx-xxxx-000c29886e3e 60Gi RWO scylla-ssd 3hscylla-data-scylla-2 Bound pvc-xxxxxxxx-xxxx-xxxx-xxxx-000c29886e3e 60Gi RWO scylla-ssd 3h -
Enter the
kubectl get podscommand to verify that the ScyllaDB pods have deployed successfully. The pod status shows asRunningif the operation succeeded:kubectl get podsNAME READY STATUS RESTARTS AGEscylla-0 1/1 Running 0 3hscylla-1 1/1 Running 0 3hscylla-2 1/1 Running 0 3h -
Run the
nodetool statuscommand in thescylla-0pod to verify that the ScyllaDB cluster was created:kubectl exec scylla-0 -- nodetool statusDatacenter: datacenter1=======================Status=Up/Down|/ State=Normal/Leaving/Joining/Moving-- Address Load Tokens Owns (effective) Host ID RackUN 10.233.127.67 356.04 KB 256 61.5% xxxxxxxx-xxxx-xxxx-xxxx-d9b928f1fc4a rack1UN 10.233.76.19 351.15 KB 256 70.5% xxxxxxxx-xxxx-xxxx-xxxx-c897c7441895 rack1UN 10.233.121.53 359.24 KB 256 68.0% xxxxxxxx-xxxx-xxxx-xxxx-640ce9ec9f6e rack1Note the pods placement and the hosts on which they are scheduled
-
Enter the
kubectl get podscommand, filtering the output using thejqcommand to display the following:
-
Pod name
-
Hostname
-
Host IP
-
Pod IP
kubectl get pods -l app=scylla -o json | jq '.items[] | {"name": .metadata.name,"hostname": .spec.nodeName, "hostIP": .status.hostIP, "PodIP": .status.podIP}'{"name": "scylla-0","hostname": "xxxx-blr-dev-dour-shoulder-3","hostIP": "X.X.X.120","PodIP": "10.233.121.53"}{"name": "scylla-1","hostname": "xxxx-blr-dev-dour-shoulder-1","hostIP": "X.X.X.82","PodIP": "10.233.76.19"}{"name": "scylla-2","hostname": "xxxx-blr-dev-dour-shoulder-2","hostIP": "X.X.X.118","PodIP": "10.233.127.67"}
-
Enter the
sshcommand to open a shell session into one of your nodes:ssh X.X.X.120 -
Enter the
pxctl volume listcommand to list your volume IDs. Save one of the node IDs for future reference:pxctl volume listID NAME SIZE HA SHARED ENCRYPTED IO_PRIORITY STATUS SNAP-ENABLED242236313329814877 pvc-xxxxxxxx-xxxx-xxxx-xxxx-000c29886e3e 60 GiB 2 no no LOW up - attached on X.X.X.120 no702215287887827398 pvc-xxxxxxxx-xxxx-xxxx-xxxx-000c29886e3e 60 GiB 2 no no LOW up - attached on X.X.X.82 no685261507172158119 pvc-xxxxxxxx-xxxx-xxxx-xxxx-000c29886e3e 60 GiB 2 no no LOW up - attached on X.X.X.118 no -
Enter the
pxctl volume inspectcommand to examine your volume. In the example output below, the Portworx volume contains 2 replica sets and is attached to node 3:pxctl volume inspect 242236313329814877Volume : 242236313329814877Name : pvc-xxxxxxxx-xxxx-xxxx-xxxx-000c29886e3eSize : 60 GiBFormat : ext4HA : 2IO Priority : LOWCreation time : Oct 4 05:14:10 UTC 2019Shared : noStatus : upState : Attached: xxxxxxxx-xxxx-xxxx-xxxx-fdb2c8379541 (X.X.X.120)Device Path : /dev/pxd/pxd242236313329814877Labels : pvc=scylla-data-scylla-0,repl=2,namespace=defaultReads : 887Reads MS : 553Bytes Read : 4526080Writes : 4086Writes MS : 27087Bytes Written : 1032036352IOs in progress : 0Bytes used : 24 MiBReplica sets on nodes:Set 0Node : X.X.X.120 (Pool 2)Node : X.X.X.82 (Pool 2)Replication Status : UpVolume consumers :- Name : scylla-0 (xxxxxxxx-xxxx-xxxx-xxxx-000c29886e3e) (Pod)Namespace : defaultRunning on : xxxx-blr-dev-dour-shoulder-3Controlled by : scylla (StatefulSet)
Verify Pod Failover works
Once you've created a ScyllaDB cluster on Kubernetes and Portworx, you can test how the cluster reacts to a failure. The following steps simulate a pod failure and demonstrate Portworx and Kubernetes' ability to recover from that failure.
-
List the pods on which ScyllaDB is running:
kubectl get pods -l "app=scylla"NAME READY STATUS RESTARTS AGEscylla-0 1/1 Running 0 4hscylla-1 1/1 Running 0 4hscylla-2 1/1 Running 0 4h -
Enter the following
kubectl execcommand to open abashsession with the worker node on which ScyllaDB is running:kubectl exec -it scylla-0 -- bash -
Enter the
cqlshcommand to open a Cassandra shell session:cqlshConnected to Test Cluster at 10.233.121.53:9042.[cqlsh 5.0.1 | Cassandra 3.0.8 | CQL spec 3.3.1 | Native protocol v4]Use HELP for help.cqlsh> -
Enter the following
CREATE KEYSPACEstatement to create a keyspace nameddemodb:CREATE KEYSPACE demodb WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 2 }; -
Enter the following commands to switch to the
demodbkeyspace and create a table calledempwithin it:cqlsh> use demodb;cqlsh:demodb> CREATE TABLE emp(emp_id int PRIMARY KEY, emp_name text, emp_city text, emp_sal varint,emp_phone varint); -
Enter the following
INSERT INTOstatement to insert a record into theemptable:cqlsh:demodb> INSERT INTO emp (emp_id, emp_name, emp_city, emp_phone, emp_sal) VALUES(123423445,'Steve', 'Denver', 5910234452, 50000); -
Exit the Cassandra shell session:
cqlsh> exit -
Enter the following
nodetool getendpointscommand to list the IP addresses of the nodes which are also hosting ScyllaDB information based on the partition key:nodetool getendpoints demodb emp 12342344510.233.76.1910.233.127.67 -
Enter the following
kubectl get podscommand to crosscheck the pod IP addresses with the IP addresses you just listed:kubectl get pods -l app=scylla -o json | jq '.items[] | {"name": .metadata.name,"hostname": .spec.nodeName, "hostIP": .status.hostIP, "PodIP": .status.podIP}'{"name": "scylla-0","hostname": "xxxx-blr-dev-dour-shoulder-3","hostIP": "X.X.X.120","PodIP": "10.233.121.53"}{"name": "scylla-1","hostname": "xxxx-blr-dev-dour-shoulder-1","hostIP": "X.X.X.82","PodIP": "10.233.76.19"}{"name": "scylla-2","hostname": "xxxx-blr-dev-dour-shoulder-2","hostIP": "X.X.X.118","PodIP": "10.233.127.67"} -
Enter the following
kubectl cordoncommand to mark thescylla-1node as unschedulable:kubectl cordon xxxx-blr-dev-dour-shoulder-1 -
Enter the following
kubectl deletecommand to delete thesyclla-1pod:kubectl delete pods scylla-1 -
Enter the following
kubectl get podscommand to see if Kubernetes scheduled thesyclla-1pod to a different node:kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESscylla-0 1/1 Running 0 4h 10.233.121.53 xxxx-blr-dev-dour-shoulder-3 <none> <none>scylla-1 1/1 Running 0 25s 10.233.127.68 xxxx-blr-dev-dour-shoulder-2 <none> <none>scylla-2 1/1 Running 0 4h 10.233.127.67 xxxx-blr-dev-dour-shoulder-2 <none> <none>Note that the
scyla-1pod is now scheduled to thexxxx-blr-dev-dour-shoulder-2node. -
Enter the
kubectl get podscommand, filtering the output using thejqcommand to display the following:
- Pod name
- Host name
- Host IP
- Pod IP
kubectl get pods -l app=scylla -o json | jq '.items[] | {"name": .metadata.name,"hostname": .spec.nodeName, "hostIP": .status.hostIP, "PodIP": .status.podIP}'
{
"name": "scylla-0",
"hostname": "xxxx-blr-dev-dour-shoulder-3",
"hostIP": "X.X.X.120",
"PodIP": "10.233.121.53"
}
{
"name": "scylla-1",
"hostname": "xxxx-blr-dev-dour-shoulder-2",
"hostIP": "X.X.X.118",
"PodIP": "10.233.127.68"
}
{
"name": "scylla-2",
"hostname": "xxxx-blr-dev-dour-shoulder-2",
"hostIP": "X.X.X.118",
"PodIP": "10.233.127.67"
}
-
Enter the following
SELECTstatement to read the columns from thedemodb.emptable:kubectl exec scylla-1 -- cqlsh -e 'select * from demodb.emp'emp_id | emp_city | emp_name | emp_phone | emp_sal-----------+----------+----------+------------+---------123423445 | Denver | Steve | 5910234452 | 50000(1 rows)