2015-07-14 00:13:09 +00:00
|
|
|
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
|
|
|
|
|
|
|
<!-- BEGIN STRIP_FOR_RELEASE -->
|
|
|
|
|
2015-07-16 17:02:26 +00:00
|
|
|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
|
|
|
width="25" height="25">
|
|
|
|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
|
|
|
width="25" height="25">
|
|
|
|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
|
|
|
width="25" height="25">
|
|
|
|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
|
|
|
width="25" height="25">
|
|
|
|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
|
|
|
width="25" height="25">
|
|
|
|
|
|
|
|
<h2>PLEASE NOTE: This document applies to the HEAD of the source tree</h2>
|
|
|
|
|
|
|
|
If you are using a released version of Kubernetes, you should
|
|
|
|
refer to the docs that go with that version.
|
|
|
|
|
2015-12-14 18:37:38 +00:00
|
|
|
<!-- TAG RELEASE_LINK, added by the munger automatically -->
|
2015-07-16 17:02:26 +00:00
|
|
|
<strong>
|
2015-11-03 18:17:57 +00:00
|
|
|
The latest release of this document can be found
|
2016-03-09 02:06:40 +00:00
|
|
|
[here](http://releases.k8s.io/release-1.2/examples/cassandra/README.md).
|
2015-07-16 17:02:26 +00:00
|
|
|
|
|
|
|
Documentation for other releases can be found at
|
|
|
|
[releases.k8s.io](http://releases.k8s.io).
|
|
|
|
</strong>
|
|
|
|
--
|
2015-07-13 22:15:35 +00:00
|
|
|
|
2015-07-14 00:13:09 +00:00
|
|
|
<!-- END STRIP_FOR_RELEASE -->
|
|
|
|
|
|
|
|
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
2015-07-17 22:35:41 +00:00
|
|
|
|
2015-01-05 06:24:03 +00:00
|
|
|
## Cloud Native Deployments of Cassandra using Kubernetes
|
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
The following document describes the development of a _cloud native_
|
|
|
|
[Cassandra](http://cassandra.apache.org/) deployment on Kubernetes. When we say
|
|
|
|
_cloud native_, we mean an application which understands that it is running
|
|
|
|
within a cluster manager, and uses this cluster management infrastructure to
|
|
|
|
help implement the application. In particular, in this instance, a custom
|
|
|
|
Cassandra `SeedProvider` is used to enable Cassandra to dynamically discover
|
|
|
|
new Cassandra nodes as they join the cluster.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
This example also uses some of the core components of Kubernetes:
|
|
|
|
|
|
|
|
- [_Pods_](../../docs/user-guide/pods.md)
|
|
|
|
- [ _Services_](../../docs/user-guide/services.md)
|
|
|
|
- [_Replication Controllers_](../../docs/user-guide/replication-controller.md).
|
2015-01-05 06:24:03 +00:00
|
|
|
|
|
|
|
### Prerequisites
|
2015-07-17 22:35:41 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
This example assumes that you have a Kubernetes cluster installed and running,
|
|
|
|
and that you have installed the [`kubectl`](../../docs/user-guide/kubectl/kubectl.md)
|
|
|
|
command line tool somewhere in your path. Please see the
|
|
|
|
[getting started guides](../../docs/getting-started-guides/)
|
|
|
|
for installation instructions for your platform.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
This example also has a few code and configuration files needed. To avoid
|
|
|
|
typing these out, you can `git clone` the Kubernetes repository to you local
|
|
|
|
computer.
|
2015-06-08 23:28:42 +00:00
|
|
|
|
2015-01-05 06:24:03 +00:00
|
|
|
### A note for the impatient
|
2015-07-17 22:35:41 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
This is a somewhat long tutorial. If you want to jump straight to the "do it
|
|
|
|
now" commands, please see the [tl; dr](#tl-dr) at the end.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
|
|
|
### Simple Single Pod Cassandra Node
|
2015-07-17 22:35:41 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
In Kubernetes, the atomic unit of an application is a
|
|
|
|
[_Pod_](../../docs/user-guide/pods.md).
|
|
|
|
A Pod is one or more containers that _must_ be scheduled onto
|
|
|
|
the same host. All containers in a pod share a network namespace, and may
|
|
|
|
optionally share mounted volumes.
|
|
|
|
|
2015-06-30 14:42:28 +00:00
|
|
|
In this simple case, we define a single container running Cassandra for our pod:
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2016-02-05 21:55:22 +00:00
|
|
|
<!-- BEGIN MUNGE: EXAMPLE cassandra.yaml -->
|
2015-07-20 22:46:20 +00:00
|
|
|
|
2015-01-05 06:24:03 +00:00
|
|
|
```yaml
|
2015-06-18 14:04:08 +00:00
|
|
|
apiVersion: v1
|
2016-02-05 21:55:22 +00:00
|
|
|
kind: Pod
|
2015-04-23 18:12:22 +00:00
|
|
|
metadata:
|
|
|
|
labels:
|
2015-11-10 06:19:22 +00:00
|
|
|
app: cassandra
|
2015-01-05 06:24:03 +00:00
|
|
|
name: cassandra
|
2015-04-23 18:12:22 +00:00
|
|
|
spec:
|
2016-02-05 21:55:22 +00:00
|
|
|
containers:
|
|
|
|
- args:
|
|
|
|
- /run.sh
|
|
|
|
resources:
|
|
|
|
limits:
|
|
|
|
cpu: "0.1"
|
2016-02-21 16:36:22 +00:00
|
|
|
image: gcr.io/google-samples/cassandra:v8
|
2016-02-05 21:55:22 +00:00
|
|
|
name: cassandra
|
|
|
|
ports:
|
|
|
|
- name: cql
|
|
|
|
containerPort: 9042
|
|
|
|
- name: thrift
|
|
|
|
containerPort: 9160
|
|
|
|
volumeMounts:
|
|
|
|
- name: data
|
|
|
|
mountPath: /cassandra_data
|
|
|
|
env:
|
|
|
|
- name: MAX_HEAP_SIZE
|
|
|
|
value: 512M
|
|
|
|
- name: HEAP_NEWSIZE
|
|
|
|
value: 100M
|
|
|
|
- name: POD_NAMESPACE
|
|
|
|
valueFrom:
|
|
|
|
fieldRef:
|
|
|
|
fieldPath: metadata.namespace
|
|
|
|
volumes:
|
|
|
|
- name: data
|
|
|
|
emptyDir: {}
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
2016-02-05 21:55:22 +00:00
|
|
|
[Download example](cassandra.yaml?raw=true)
|
|
|
|
<!-- END MUNGE: EXAMPLE cassandra.yaml -->
|
2015-07-20 22:46:20 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
There are a few things to note in this description. First is that we are
|
|
|
|
running the [```gcr.io/google-samples/cassandra:v8```](image/Dockerfile)
|
|
|
|
image from Google's [container registry](https://cloud.google.com/container-registry/docs/).
|
|
|
|
|
|
|
|
This is a standard Cassandra installation on top of Debian. However it also
|
|
|
|
adds a custom
|
|
|
|
[`SeedProvider`](https://svn.apache.org/repos/asf/cassandra/trunk/src/java/org/apache/cassandra/locator/SeedProvider.java) to Cassandra. In
|
|
|
|
Cassandra, a ```SeedProvider``` bootstraps the gossip protocol that Cassandra
|
|
|
|
uses to find other nodes.
|
|
|
|
The [`KubernetesSeedProvider`](java/src/io/k8s/cassandra/KubernetesSeedProvider.java)
|
|
|
|
discovers the Kubernetes API Server using the built in Kubernetes
|
|
|
|
discovery service, and then uses the Kubernetes API to find new nodes (more on
|
|
|
|
this later). See the [image](image/) directory of this example for specifics on
|
|
|
|
how the container image was built and what it contains.
|
|
|
|
|
|
|
|
You may also note that we are setting some Cassandra parameters (`MAX_HEAP_SIZE`
|
|
|
|
and `HEAP_NEWSIZE`) and adding information about the
|
|
|
|
[namespace](../../docs/user-guide/namespaces.md).
|
|
|
|
We also tell Kubernetes that the container exposes
|
|
|
|
both the `CQL` and `Thrift` API ports. Finally, we tell the cluster
|
|
|
|
manager that we need 0.1 cpu (0.1 core).
|
|
|
|
|
|
|
|
In theory, we could create a single Cassandra pod right now, but since
|
|
|
|
`KubernetesSeedProvider` needs to learn what nodes are in the Cassandra
|
|
|
|
deployment we need to create a service first.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2015-06-30 14:42:28 +00:00
|
|
|
### Cassandra Service
|
2015-07-17 22:35:41 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
In Kubernetes, a _[Service](../../docs/user-guide/services.md)_ describes a set
|
|
|
|
of Pods that perform the same task. For example, the set of Pods in a Cassandra
|
|
|
|
cluster can be a Kubernetes Service, or even just the single Pod we created
|
|
|
|
above. An important use for a Service is to create a load balancer which
|
|
|
|
distributes traffic across members of the set of Pods. But a _Service_ can also
|
|
|
|
be used as a standing query which makes a dynamically changing set of Pods (or
|
|
|
|
the single Pod we've already created) available via the Kubernetes API. This is
|
|
|
|
the way that we use initially use Services with Cassandra.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
|
|
|
Here is the service description:
|
2015-07-17 02:01:02 +00:00
|
|
|
|
2015-07-20 22:46:20 +00:00
|
|
|
<!-- BEGIN MUNGE: EXAMPLE cassandra-service.yaml -->
|
|
|
|
|
2015-01-05 06:24:03 +00:00
|
|
|
```yaml
|
2015-06-18 14:04:08 +00:00
|
|
|
apiVersion: v1
|
2015-01-05 06:24:03 +00:00
|
|
|
kind: Service
|
2015-05-21 21:10:25 +00:00
|
|
|
metadata:
|
|
|
|
labels:
|
2015-11-10 06:19:22 +00:00
|
|
|
app: cassandra
|
2015-01-05 06:24:03 +00:00
|
|
|
name: cassandra
|
2015-05-21 21:10:25 +00:00
|
|
|
spec:
|
2015-04-23 18:12:22 +00:00
|
|
|
ports:
|
|
|
|
- port: 9042
|
2015-05-21 21:10:25 +00:00
|
|
|
selector:
|
2015-11-10 06:19:22 +00:00
|
|
|
app: cassandra
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
2015-09-08 00:43:09 +00:00
|
|
|
[Download example](cassandra-service.yaml?raw=true)
|
2015-07-20 17:45:12 +00:00
|
|
|
<!-- END MUNGE: EXAMPLE cassandra-service.yaml -->
|
2015-07-20 22:46:20 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
The important thing to note here is the `selector`. It is a query over
|
|
|
|
labels, that identifies the set of _Pods_ contained by the _Service_. In this
|
|
|
|
case the selector is `app=cassandra`. If you look back at the Pod
|
|
|
|
specification above, you'll see that the pod has the corresponding label, so it
|
|
|
|
will be selected for membership in this Service.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
|
|
|
Create this service as follows:
|
2015-07-17 02:01:02 +00:00
|
|
|
|
2015-07-24 19:38:26 +00:00
|
|
|
```console
|
2015-07-16 00:20:39 +00:00
|
|
|
$ kubectl create -f examples/cassandra/cassandra-service.yaml
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
2015-06-30 14:42:28 +00:00
|
|
|
Now, as the service is running, we can create the first Cassandra pod using the mentioned specification.
|
|
|
|
|
2015-07-24 19:38:26 +00:00
|
|
|
```console
|
2015-07-16 00:20:39 +00:00
|
|
|
$ kubectl create -f examples/cassandra/cassandra.yaml
|
2015-06-30 14:42:28 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
After a few moments, you should be able to see the pod running, plus its single container:
|
|
|
|
|
2015-07-24 19:38:26 +00:00
|
|
|
```console
|
2015-06-30 14:42:28 +00:00
|
|
|
$ kubectl get pods cassandra
|
2015-07-07 20:42:05 +00:00
|
|
|
NAME READY STATUS RESTARTS AGE
|
2015-06-30 14:42:28 +00:00
|
|
|
cassandra 1/1 Running 0 55s
|
|
|
|
```
|
|
|
|
|
|
|
|
You can also query the service endpoints to check if the pod has been correctly selected.
|
|
|
|
|
2015-07-24 19:38:26 +00:00
|
|
|
```console
|
2015-01-05 06:24:03 +00:00
|
|
|
$ kubectl get endpoints cassandra -o yaml
|
2015-06-21 22:38:53 +00:00
|
|
|
apiVersion: v1
|
2015-01-05 06:24:03 +00:00
|
|
|
kind: Endpoints
|
2015-04-23 18:12:22 +00:00
|
|
|
metadata:
|
2015-06-21 22:38:53 +00:00
|
|
|
creationTimestamp: 2015-06-21T22:34:12Z
|
|
|
|
labels:
|
2015-11-10 06:19:22 +00:00
|
|
|
app: cassandra
|
2015-04-23 18:12:22 +00:00
|
|
|
name: cassandra
|
|
|
|
namespace: default
|
2015-06-21 22:38:53 +00:00
|
|
|
resourceVersion: "944373"
|
|
|
|
selfLink: /api/v1/namespaces/default/endpoints/cassandra
|
|
|
|
uid: a3d6c25f-1865-11e5-a34e-42010af01bcc
|
2015-04-23 18:12:22 +00:00
|
|
|
subsets:
|
|
|
|
- addresses:
|
2015-06-21 22:38:53 +00:00
|
|
|
- ip: 10.244.3.15
|
2015-04-23 18:12:22 +00:00
|
|
|
targetRef:
|
|
|
|
kind: Pod
|
|
|
|
name: cassandra
|
|
|
|
namespace: default
|
2015-06-21 22:38:53 +00:00
|
|
|
resourceVersion: "944372"
|
|
|
|
uid: 9ef9895d-1865-11e5-a34e-42010af01bcc
|
2015-04-23 18:12:22 +00:00
|
|
|
ports:
|
|
|
|
- port: 9042
|
|
|
|
protocol: TCP
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
### Adding replicated nodes
|
2015-07-17 22:35:41 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
Of course, a single node cluster isn't particularly interesting. The real power
|
|
|
|
of Kubernetes and Cassandra lies in easily building a replicated, scalable
|
|
|
|
Cassandra cluster.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
In Kubernetes a
|
|
|
|
_[Replication Controller](../../docs/user-guide/replication-controller.md)_
|
|
|
|
is responsible for replicating sets of identical pods. Like a
|
|
|
|
_Service_, it has a selector query which identifies the members of its set.
|
|
|
|
Unlike a _Service_, it also has a desired number of replicas, and it will create
|
|
|
|
or delete _Pods_ to ensure that the number of _Pods_ matches up with its
|
|
|
|
desired state.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
Replication controllers will "adopt" existing pods that match their selector
|
|
|
|
query, so let's create a replication controller with a single replica to adopt
|
|
|
|
our existing Cassandra pod.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2015-07-20 22:46:20 +00:00
|
|
|
<!-- BEGIN MUNGE: EXAMPLE cassandra-controller.yaml -->
|
|
|
|
|
2015-01-05 06:24:03 +00:00
|
|
|
```yaml
|
2015-06-18 14:04:08 +00:00
|
|
|
apiVersion: v1
|
2015-01-05 06:24:03 +00:00
|
|
|
kind: ReplicationController
|
2015-05-21 21:10:25 +00:00
|
|
|
metadata:
|
|
|
|
labels:
|
2015-11-10 06:19:22 +00:00
|
|
|
app: cassandra
|
2015-04-23 18:12:22 +00:00
|
|
|
name: cassandra
|
2015-05-21 21:10:25 +00:00
|
|
|
spec:
|
2016-02-23 00:05:38 +00:00
|
|
|
replicas: 2
|
|
|
|
selector:
|
|
|
|
app: cassandra
|
2015-05-21 21:10:25 +00:00
|
|
|
template:
|
|
|
|
metadata:
|
|
|
|
labels:
|
2015-11-10 06:19:22 +00:00
|
|
|
app: cassandra
|
2015-05-21 21:10:25 +00:00
|
|
|
spec:
|
|
|
|
containers:
|
2015-07-20 22:46:20 +00:00
|
|
|
- command:
|
2015-04-23 18:12:22 +00:00
|
|
|
- /run.sh
|
|
|
|
resources:
|
|
|
|
limits:
|
2015-07-20 22:46:20 +00:00
|
|
|
cpu: 0.1
|
2015-05-21 21:10:25 +00:00
|
|
|
env:
|
2015-04-23 18:12:22 +00:00
|
|
|
- name: MAX_HEAP_SIZE
|
|
|
|
value: 512M
|
|
|
|
- name: HEAP_NEWSIZE
|
|
|
|
value: 100M
|
2015-06-23 15:52:06 +00:00
|
|
|
- name: POD_NAMESPACE
|
|
|
|
valueFrom:
|
|
|
|
fieldRef:
|
|
|
|
fieldPath: metadata.namespace
|
2016-02-21 16:36:22 +00:00
|
|
|
image: gcr.io/google-samples/cassandra:v8
|
2015-07-20 22:46:20 +00:00
|
|
|
name: cassandra
|
2015-05-21 21:10:25 +00:00
|
|
|
ports:
|
2015-04-23 18:12:22 +00:00
|
|
|
- containerPort: 9042
|
|
|
|
name: cql
|
|
|
|
- containerPort: 9160
|
|
|
|
name: thrift
|
2015-05-21 21:10:25 +00:00
|
|
|
volumeMounts:
|
2015-04-23 18:12:22 +00:00
|
|
|
- mountPath: /cassandra_data
|
|
|
|
name: data
|
2015-05-21 21:10:25 +00:00
|
|
|
volumes:
|
2015-04-23 18:12:22 +00:00
|
|
|
- name: data
|
|
|
|
emptyDir: {}
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
2015-09-08 00:43:09 +00:00
|
|
|
[Download example](cassandra-controller.yaml?raw=true)
|
2015-07-20 17:45:12 +00:00
|
|
|
<!-- END MUNGE: EXAMPLE cassandra-controller.yaml -->
|
2015-07-20 22:46:20 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
Most of this replication controller definition is identical to the Cassandra pod
|
|
|
|
definition above; it simply gives the replication controller a recipe to use
|
|
|
|
when it creates new Cassandra pods. The other differentiating parts are the
|
|
|
|
`selector` attribute which contains the controller's selector query, and the
|
|
|
|
`replicas` attribute which specifies the desired number of replicas, in this
|
|
|
|
case 1.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
|
|
|
Create this controller:
|
|
|
|
|
2015-07-24 19:38:26 +00:00
|
|
|
```console
|
2015-07-16 00:20:39 +00:00
|
|
|
$ kubectl create -f examples/cassandra/cassandra-controller.yaml
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
Now this is actually not that interesting, since we haven't actually done
|
|
|
|
anything new. Now it will get interesting.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2015-05-21 21:10:25 +00:00
|
|
|
Let's scale our cluster to 2:
|
2015-07-17 02:01:02 +00:00
|
|
|
|
2015-07-24 19:38:26 +00:00
|
|
|
```console
|
2015-05-21 21:10:25 +00:00
|
|
|
$ kubectl scale rc cassandra --replicas=2
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
Now if you list the pods in your cluster, and filter to the label `app=cassandra`, you should see two cassandra pods:
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
```console
|
|
|
|
$ kubectl get pods -l="app=cassandra"
|
2015-07-07 20:42:05 +00:00
|
|
|
NAME READY STATUS RESTARTS AGE
|
2015-06-21 22:38:53 +00:00
|
|
|
cassandra 1/1 Running 0 3m
|
|
|
|
cassandra-af6h5 1/1 Running 0 28s
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
Notice that one of the pods has the human-readable name `cassandra` that you
|
|
|
|
specified in your config before, and one has a random string, since it was named
|
|
|
|
by the replication controller.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
To prove that this all works, you can use the `nodetool` command to examine the
|
|
|
|
status of the cluster. To do this, use the `kubectl exec` command to run
|
|
|
|
`nodetool` in one of your Cassandra pods.
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2015-07-24 19:38:26 +00:00
|
|
|
```console
|
2015-06-08 23:28:42 +00:00
|
|
|
$ kubectl exec -ti cassandra -- nodetool status
|
2015-01-05 06:24:03 +00:00
|
|
|
Datacenter: datacenter1
|
|
|
|
=======================
|
|
|
|
Status=Up/Down
|
|
|
|
|/ State=Normal/Leaving/Joining/Moving
|
2015-04-23 18:12:22 +00:00
|
|
|
-- Address Load Tokens Owns (effective) Host ID Rack
|
|
|
|
UN 10.244.0.5 74.09 KB 256 100.0% 86feda0f-f070-4a5b-bda1-2eeb0ad08b77 rack1
|
|
|
|
UN 10.244.3.3 51.28 KB 256 100.0% dafe3154-1d67-42e1-ac1d-78e7e80dce2b rack1
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
2015-05-21 21:10:25 +00:00
|
|
|
Now let's scale our cluster to 4 nodes:
|
2015-07-17 02:01:02 +00:00
|
|
|
|
2015-01-05 06:24:03 +00:00
|
|
|
```sh
|
2015-05-21 21:10:25 +00:00
|
|
|
$ kubectl scale rc cassandra --replicas=4
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
2015-06-08 23:28:42 +00:00
|
|
|
In a few moments, you can examine the status again:
|
2015-07-17 02:01:02 +00:00
|
|
|
|
2015-01-05 06:24:03 +00:00
|
|
|
```sh
|
2015-06-08 23:28:42 +00:00
|
|
|
$ kubectl exec -ti cassandra -- nodetool status
|
2015-01-05 06:24:03 +00:00
|
|
|
Datacenter: datacenter1
|
|
|
|
=======================
|
|
|
|
Status=Up/Down
|
|
|
|
|/ State=Normal/Leaving/Joining/Moving
|
2015-04-23 18:12:22 +00:00
|
|
|
-- Address Load Tokens Owns (effective) Host ID Rack
|
|
|
|
UN 10.244.2.3 57.61 KB 256 49.1% 9d560d8e-dafb-4a88-8e2f-f554379c21c3 rack1
|
|
|
|
UN 10.244.1.7 41.1 KB 256 50.2% 68b8cc9c-2b76-44a4-b033-31402a77b839 rack1
|
|
|
|
UN 10.244.0.5 74.09 KB 256 49.7% 86feda0f-f070-4a5b-bda1-2eeb0ad08b77 rack1
|
|
|
|
UN 10.244.3.3 51.28 KB 256 51.0% dafe3154-1d67-42e1-ac1d-78e7e80dce2b rack1
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
2015-10-21 03:44:17 +00:00
|
|
|
### Using a DaemonSet
|
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
Before you start this section, __delete the replication controller__ you created above:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
$ kubectl delete rc cassandra
|
|
|
|
```
|
|
|
|
|
|
|
|
In Kubernetes a _[Daemon Set](../../docs/admin/daemons.md)_ can distribute pods
|
|
|
|
onto Kubernetes nodes, one-to-one. Like a _ReplicationController_, it has a
|
|
|
|
selector query which identifies the members of its set. Unlike a
|
|
|
|
_ReplicationController_, it has a node selector to limit which nodes are
|
|
|
|
scheduled with the templated pods, and replicates not based on a set target
|
|
|
|
number of pods, but rather assigns a single pod to each targeted node.
|
2015-10-21 03:44:17 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
An example use case: when deploying to the cloud, the expectation is that
|
|
|
|
instances are ephemeral and might die at any time. Cassandra is built to
|
|
|
|
replicate data across the cluster to facilitate data redundancy, so that in the
|
|
|
|
case that an instance dies, the data stored on the instance does not, and the
|
|
|
|
cluster can react by re-replicating the data to other running nodes.
|
2015-10-21 03:44:17 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
`DaemonSet` is designed to place a single pod on each node in the Kubernetes
|
|
|
|
cluster. If you're looking for data redundancy with Cassandra, let's create a
|
|
|
|
daemonset to start our storage cluster:
|
2015-10-21 03:44:17 +00:00
|
|
|
|
|
|
|
<!-- BEGIN MUNGE: EXAMPLE cassandra-daemonset.yaml -->
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
apiVersion: extensions/v1beta1
|
|
|
|
kind: DaemonSet
|
|
|
|
metadata:
|
|
|
|
labels:
|
|
|
|
name: cassandra
|
|
|
|
name: cassandra
|
|
|
|
spec:
|
|
|
|
template:
|
|
|
|
metadata:
|
|
|
|
labels:
|
2016-02-21 16:36:22 +00:00
|
|
|
app: cassandra
|
2015-10-21 03:44:17 +00:00
|
|
|
spec:
|
|
|
|
# Filter to specific nodes:
|
|
|
|
# nodeSelector:
|
|
|
|
# app: cassandra
|
|
|
|
containers:
|
|
|
|
- command:
|
|
|
|
- /run.sh
|
|
|
|
env:
|
|
|
|
- name: MAX_HEAP_SIZE
|
|
|
|
value: 512M
|
|
|
|
- name: HEAP_NEWSIZE
|
|
|
|
value: 100M
|
|
|
|
- name: POD_NAMESPACE
|
|
|
|
valueFrom:
|
|
|
|
fieldRef:
|
|
|
|
fieldPath: metadata.namespace
|
2016-02-21 16:36:22 +00:00
|
|
|
image: gcr.io/google-samples/cassandra:v8
|
2015-10-21 03:44:17 +00:00
|
|
|
name: cassandra
|
|
|
|
ports:
|
|
|
|
- containerPort: 9042
|
|
|
|
name: cql
|
|
|
|
- containerPort: 9160
|
|
|
|
name: thrift
|
|
|
|
resources:
|
|
|
|
request:
|
|
|
|
cpu: 0.1
|
|
|
|
volumeMounts:
|
|
|
|
- mountPath: /cassandra_data
|
|
|
|
name: data
|
|
|
|
volumes:
|
|
|
|
- name: data
|
2016-02-21 16:36:22 +00:00
|
|
|
emptyDir: {}
|
2015-10-21 03:44:17 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
[Download example](cassandra-daemonset.yaml?raw=true)
|
|
|
|
<!-- END MUNGE: EXAMPLE cassandra-daemonset.yaml -->
|
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
Most of this daemon set definition is identical to the Cassandra pod and
|
|
|
|
ReplicationController definitions above; it simply gives the daemon set a recipe
|
|
|
|
to use when it creates new Cassandra pods, and targets all Cassandra nodes in
|
|
|
|
the cluster. The other differentiating part from a Replication Controller is
|
|
|
|
the `nodeSelector` attribute which allows the daemonset to target a specific
|
|
|
|
subset of nodes, and the lack of a `replicas` attribute due to the 1 to 1 node-
|
|
|
|
pod relationship.
|
2015-10-21 03:44:17 +00:00
|
|
|
|
|
|
|
Create this daemonset:
|
|
|
|
|
|
|
|
```console
|
|
|
|
$ kubectl create -f examples/cassandra/cassandra-daemonset.yaml
|
|
|
|
```
|
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
You may need to disable config file validation, like so:
|
|
|
|
|
|
|
|
```console
|
|
|
|
$ kubectl create -f examples/cassandra/cassandra-daemonset.yaml --validate=false
|
|
|
|
```
|
|
|
|
|
|
|
|
Now, if you list the pods in your cluster, and filter to the label
|
|
|
|
`app=cassandra`, you should see one new cassandra pod for each node in your
|
|
|
|
network.
|
2015-10-21 03:44:17 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
```console
|
|
|
|
$ kubectl get pods -l="app=cassandra"
|
2015-10-21 03:44:17 +00:00
|
|
|
NAME READY STATUS RESTARTS AGE
|
|
|
|
cassandra-af6h5 1/1 Running 0 28s
|
|
|
|
cassandra-2jq1b 1/1 Running 0 32s
|
|
|
|
cassandra-34j2a 1/1 Running 0 29s
|
|
|
|
```
|
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
To prove that this all works, you can use the `nodetool` command to examine the
|
|
|
|
status of the cluster. To do this, use the `kubectl exec` command to run
|
|
|
|
`nodetool` in one of your Cassandra pods.
|
2015-10-21 03:44:17 +00:00
|
|
|
|
|
|
|
```console
|
|
|
|
$ kubectl exec -ti cassandra-af6h5 -- nodetool status
|
|
|
|
Datacenter: datacenter1
|
|
|
|
=======================
|
|
|
|
Status=Up/Down
|
|
|
|
|/ State=Normal/Leaving/Joining/Moving
|
|
|
|
-- Address Load Tokens Owns (effective) Host ID Rack
|
|
|
|
UN 10.244.0.5 74.09 KB 256 100.0% 86feda0f-f070-4a5b-bda1-2eeb0ad08b77 rack1
|
|
|
|
UN 10.244.4.2 32.45 KB 256 100.0% 0b1be71a-6ffb-4895-ac3e-b9791299c141 rack1
|
|
|
|
UN 10.244.3.3 51.28 KB 256 100.0% dafe3154-1d67-42e1-ac1d-78e7e80dce2b rack1
|
|
|
|
```
|
|
|
|
|
2015-01-05 06:24:03 +00:00
|
|
|
### tl; dr;
|
2015-07-17 22:35:41 +00:00
|
|
|
|
2015-01-05 06:24:03 +00:00
|
|
|
For those of you who are impatient, here is the summary of the commands we ran in this tutorial.
|
|
|
|
|
|
|
|
```sh
|
|
|
|
# create a service to track all cassandra nodes
|
2015-07-16 00:20:39 +00:00
|
|
|
kubectl create -f examples/cassandra/cassandra-service.yaml
|
2015-01-05 06:24:03 +00:00
|
|
|
|
2015-06-30 14:42:28 +00:00
|
|
|
# create a single cassandra node
|
2015-07-16 00:20:39 +00:00
|
|
|
kubectl create -f examples/cassandra/cassandra.yaml
|
2015-06-30 14:42:28 +00:00
|
|
|
|
2015-01-05 06:24:03 +00:00
|
|
|
# create a replication controller to replicate cassandra nodes
|
2015-07-16 00:20:39 +00:00
|
|
|
kubectl create -f examples/cassandra/cassandra-controller.yaml
|
2015-01-05 06:24:03 +00:00
|
|
|
|
|
|
|
# scale up to 2 nodes
|
2015-05-21 21:10:25 +00:00
|
|
|
kubectl scale rc cassandra --replicas=2
|
2015-01-05 06:24:03 +00:00
|
|
|
|
|
|
|
# validate the cluster
|
2015-06-08 23:28:42 +00:00
|
|
|
kubectl exec -ti cassandra -- nodetool status
|
2015-01-05 06:24:03 +00:00
|
|
|
|
|
|
|
# scale up to 4 nodes
|
2015-05-21 21:10:25 +00:00
|
|
|
kubectl scale rc cassandra --replicas=4
|
2015-10-21 03:44:17 +00:00
|
|
|
|
2016-02-21 16:36:22 +00:00
|
|
|
# delete the replication controller
|
|
|
|
kubectl delete rc cassandra
|
|
|
|
|
|
|
|
# then create a daemonset to place a cassandra node on each kubernetes node
|
2015-10-21 03:44:17 +00:00
|
|
|
kubectl create -f examples/cassandra/cassandra-daemonset.yaml
|
2015-01-05 06:24:03 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
### Seed Provider Source
|
2015-05-14 22:12:45 +00:00
|
|
|
|
2015-07-14 00:13:09 +00:00
|
|
|
See [here](java/src/io/k8s/cassandra/KubernetesSeedProvider.java).
|
|
|
|
|
2015-05-14 22:12:45 +00:00
|
|
|
|
2015-07-14 00:13:09 +00:00
|
|
|
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
2015-05-14 22:12:45 +00:00
|
|
|
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/examples/cassandra/README.md?pixel)]()
|
2015-07-14 00:13:09 +00:00
|
|
|
<!-- END MUNGE: GENERATED_ANALYTICS -->
|