From d761c644475124916f62ac8b0fe317b1f2faafba Mon Sep 17 00:00:00 2001 From: Chao Xu Date: Thu, 23 Apr 2015 11:12:22 -0700 Subject: [PATCH] update examples/cassandra to api v1beta3 --- examples/cassandra/README.md | 203 +++++++++++------- examples/cassandra/cassandra-controller.yaml | 75 ++++--- examples/cassandra/cassandra-service.yaml | 17 +- examples/cassandra/cassandra.yaml | 63 +++--- .../k8s/cassandra/KubernetesSeedProvider.java | 2 +- examples/cassandra/v1beta3/README.md | 64 ------ .../v1beta3/cassandra-controller.yaml | 42 ---- .../cassandra/v1beta3/cassandra-service.yaml | 12 -- 8 files changed, 203 insertions(+), 275 deletions(-) delete mode 100644 examples/cassandra/v1beta3/README.md delete mode 100644 examples/cassandra/v1beta3/cassandra-controller.yaml delete mode 100644 examples/cassandra/v1beta3/cassandra-service.yaml diff --git a/examples/cassandra/README.md b/examples/cassandra/README.md index 90510e2758..cd76f2510f 100644 --- a/examples/cassandra/README.md +++ b/examples/cassandra/README.md @@ -14,36 +14,44 @@ This is a somewhat long tutorial. If you want to jump straight to the "do it no In Kubernetes, the atomic unit of an application is a [_Pod_](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/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. In this simple case, we define a single container running Cassandra for our pod: ```yaml -id: cassandra +apiVersion: v1beta3 kind: Pod -apiVersion: v1beta1 -desiredState: - manifest: - version: v1beta1 - id: cassandra - containers: - - name: cassandra - image: kubernetes/cassandra:v2 - command: - - /run.sh - cpu: 1000 - ports: - - name: cql - containerPort: 9042 - - name: thrift - containerPort: 9160 - env: - - key: MAX_HEAP_SIZE - value: 512M - - key: HEAP_NEWSIZE - value: 100M -labels: +metadata: + labels: + name: cassandra name: cassandra +spec: + containers: + - args: + - /run.sh + resources: + limits: + cpu: "1" + image: kubernetes/cassandra:v2 + 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: KUBERNETES_API_PROTOCOL + value: http + volumes: + - name: data + emptyDir: {} ``` There are a few things to note in this description. First is that we are running the ```kubernetes/cassandra``` image. 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``` 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) -You may also note that we are setting some Cassandra parameters (```MAX_HEAP_SIZE``` and ```HEAP_NEWSIZE```). We also tell Kubernetes that the container exposes both the ```CQL``` and ```Thrift``` API ports. Finally, we tell the cluster manager that we need 1000 milli-cpus (1 core). +You may also note that we are setting some Cassandra parameters (```MAX_HEAP_SIZE``` and ```HEAP_NEWSIZE```). We also tell Kubernetes that the container exposes both the ```CQL``` and ```Thrift``` API ports. Finally, we tell the cluster manager that we need 1 cpu (1 core). Given this configuration, we can create the pod as follows @@ -55,8 +63,9 @@ After a few moments, you should be able to see the pod running: ```sh $ kubectl get pods cassandra -POD CONTAINER(S) IMAGE(S) HOST LABELS STATUS -cassandra cassandra kubernetes/cassandra kubernetes-minion-1/1.2.3.4 name=cassandra Running +POD IP CONTAINER(S) IMAGE(S) HOST LABELS STATUS CREATED MESSAGE +cassandra 10.244.3.3 kubernetes-minion-sft2/104.197.42.181 name=cassandra Running 21 seconds + cassandra kubernetes/cassandra:v2 Running 3 seconds ``` @@ -65,13 +74,18 @@ In Kubernetes a _Service_ describes a set of Pods that perform the same task. F Here is the service description: ```yaml -id: cassandra +apiVersion: v1beta3 kind: Service -apiVersion: v1beta1 -port: 9042 -containerPort: 9042 -selector: +metadata: + labels: + name: cassandra name: cassandra +spec: + ports: + - port: 9042 + targetPort: 9042 + selector: + name: cassandra ``` 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 ```name=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. @@ -84,16 +98,28 @@ $ kubectl create -f cassandra-service.yaml Once the service is created, you can query it's endpoints: ```sh $ kubectl get endpoints cassandra -o yaml -apiVersion: v1beta1 -creationTimestamp: 2015-01-05T05:51:50Z -endpoints: -- 10.244.1.10:9042 -id: cassandra +apiVersion: v1beta3 kind: Endpoints -namespace: default -resourceVersion: 69130 -selfLink: /api/v1beta1/endpoints/cassandra?namespace=default -uid: f1937b47-949e-11e4-8a8b-42010af0e23e +metadata: + creationTimestamp: 2015-04-23T17:21:27Z + name: cassandra + namespace: default + resourceVersion: "857" + selfLink: /api/v1beta3/namespaces/default/endpoints/cassandra + uid: 2c7d36bf-e9dd-11e4-a7ed-42010af011dd +subsets: +- addresses: + - IP: 10.244.3.3 + targetRef: + kind: Pod + name: cassandra + namespace: default + resourceVersion: "769" + uid: d185872c-e9dc-11e4-a7ed-42010af011dd + ports: + - port: 9042 + protocol: TCP + ``` You can see that the _Service_ has found the pod we created in step one. @@ -106,37 +132,47 @@ In Kubernetes a _Replication Controller_ is responsible for replicating sets of 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. ```yaml -id: cassandra +apiVersion: v1beta3 kind: ReplicationController -apiVersion: v1beta1 -desiredState: - replicas: 1 - replicaSelector: +metadata: + labels: name: cassandra - # This is identical to the pod config above - podTemplate: - desiredState: - manifest: - version: v1beta1 - id: cassandra - containers: - - name: cassandra - image: kubernetes/cassandra:v2 - command: - - /run.sh - cpu: 1000 - ports: - - name: cql - containerPort: 9042 - - name: thrift - containerPort: 9160 - env: - - key: MAX_HEAP_SIZE - value: 512M - - key: HEAP_NEWSIZE - value: 100M - labels: - name: cassandra + name: cassandra +spec: + replicas: 1 + selector: + name: cassandra + template: + metadata: + labels: + name: cassandra + spec: + containers: + - command: + - /run.sh + resources: + limits: + cpu: 1 + env: + - name: MAX_HEAP_SIZE + key: MAX_HEAP_SIZE + value: 512M + - name: HEAP_NEWSIZE + key: HEAP_NEWSIZE + value: 100M + image: "kubernetes/cassandra:v2" + name: cassandra + ports: + - containerPort: 9042 + name: cql + - containerPort: 9160 + name: thrift + volumeMounts: + - mountPath: /cassandra_data + name: data + volumes: + - name: data + emptyDir: {} ``` The bulk of the replication controller config is actually identical to the Cassandra pod declaration above, it simply gives the controller a recipe to use when creating new pods. The other parts are the ```replicaSelector``` which contains the controller's selector query, and the ```replicas``` parameter which specifies the desired number of replicas, in this case 1. @@ -158,9 +194,12 @@ Now if you list the pods in your cluster, you should see two cassandra pods: ```sh $ kubectl get pods -POD CONTAINER(S) IMAGE(S) HOST LABELS STATUS -cassandra cassandra kubernetes/cassandra kubernetes-minion-1.c.my-cloud-code.internal/1.2.3.4 name=cassandra Running -16b2beab-94a1-11e4-8a8b-42010af0e23e cassandra kubernetes/cassandra kubernetes-minion-3.c.my-cloud-code.internal/2.3.4.5 name=cassandra Running +POD IP CONTAINER(S) IMAGE(S) HOST LABELS STATUS CREATED MESSAGE +cassandra 10.244.3.3 kubernetes-minion-sft2/104.197.42.181 name=cassandra Running 7 minutes + cassandra kubernetes/cassandra:v2 Running 7 minutes +cassandra-gnhk8 10.244.0.5 kubernetes-minion-dqz3/104.197.2.71 name=cassandra Running About a minute + cassandra kubernetes/cassandra:v2 Running 51 seconds + ``` 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. @@ -168,15 +207,15 @@ Notice that one of the pods has the human readable name ```cassandra``` that you To prove that this all works, you can use the ```nodetool``` command to examine the status of the cluster, for example: ```sh -$ ssh 1.2.3.4 +$ ssh 104.197.42.181 $ docker exec nodetool status Datacenter: datacenter1 ======================= Status=Up/Down |/ State=Normal/Leaving/Joining/Moving --- Address Load Tokens Owns (effective) Host ID Rack -UN 10.244.3.29 72.07 KB 256 100.0% f736f0b5-bd1f-46f1-9b9d-7e8f22f37c9e rack1 -UN 10.244.1.10 41.14 KB 256 100.0% 42617acd-b16e-4ee3-9486-68a6743657b1 rack1 +-- 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 ``` Now let's resize our cluster to 4 nodes: @@ -191,11 +230,11 @@ Datacenter: datacenter1 ======================= Status=Up/Down |/ State=Normal/Leaving/Joining/Moving --- Address Load Tokens Owns (effective) Host ID Rack -UN 10.244.3.29 72.07 KB 256 49.5% f736f0b5-bd1f-46f1-9b9d-7e8f22f37c9e rack1 -UN 10.244.2.14 61.62 KB 256 52.6% 3e9981a6-6919-42c4-b2b8-af50f23a68f2 rack1 -UN 10.244.1.10 41.14 KB 256 49.5% 42617acd-b16e-4ee3-9486-68a6743657b1 rack1 -UN 10.244.4.8 63.83 KB 256 48.3% eeb73967-d1e6-43c1-bb54-512f8117d372 rack1 +-- 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 ``` ### tl; dr; @@ -289,7 +328,7 @@ public class KubernetesSeedProvider implements SeedProvider { String host = protocol + "://" + hostName + ":" + hostPort; String serviceName = getEnvOrDefault("CASSANDRA_SERVICE", "cassandra"); - String path = "/api/v1beta1/endpoints/"; + String path = "/api/v1beta3/endpoints/"; try { URL url = new URL(host + path + serviceName); ObjectMapper mapper = new ObjectMapper(); diff --git a/examples/cassandra/cassandra-controller.yaml b/examples/cassandra/cassandra-controller.yaml index e62979cfda..9b188640a5 100644 --- a/examples/cassandra/cassandra-controller.yaml +++ b/examples/cassandra/cassandra-controller.yaml @@ -1,37 +1,42 @@ -id: cassandra +apiVersion: v1beta3 kind: ReplicationController -apiVersion: v1beta1 -desiredState: - replicas: 1 - replicaSelector: +metadata: + labels: name: cassandra - podTemplate: - desiredState: - manifest: - version: v1beta1 - id: cassandra - containers: - - name: cassandra - image: kubernetes/cassandra:v2 - command: - - /run.sh - cpu: 1000 - ports: - - name: cql - containerPort: 9042 - - name: thrift - containerPort: 9160 - volumeMounts: - - name: data - mountPath: /cassandra_data - env: - - key: MAX_HEAP_SIZE - value: 512M - - key: HEAP_NEWSIZE - value: 100M - volumes: - - name: data - source: - emptyDir: {} - labels: - name: cassandra + name: cassandra +spec: + replicas: 1 + selector: + name: cassandra + template: + metadata: + labels: + name: cassandra + spec: + containers: + - command: + - /run.sh + resources: + limits: + cpu: 1 + env: + - name: MAX_HEAP_SIZE + key: MAX_HEAP_SIZE + value: 512M + - name: HEAP_NEWSIZE + key: HEAP_NEWSIZE + value: 100M + image: "kubernetes/cassandra:v2" + name: cassandra + ports: + - containerPort: 9042 + name: cql + - containerPort: 9160 + name: thrift + volumeMounts: + - mountPath: /cassandra_data + name: data + volumes: + - name: data + emptyDir: {} + diff --git a/examples/cassandra/cassandra-service.yaml b/examples/cassandra/cassandra-service.yaml index ad17bce72c..1811db7753 100644 --- a/examples/cassandra/cassandra-service.yaml +++ b/examples/cassandra/cassandra-service.yaml @@ -1,9 +1,12 @@ -id: cassandra +apiVersion: v1beta3 kind: Service -apiVersion: v1beta1 -port: 9042 -containerPort: 9042 -selector: - name: cassandra -labels: +metadata: + labels: + name: cassandra name: cassandra +spec: + ports: + - port: 9042 + targetPort: 9042 + selector: + name: cassandra diff --git a/examples/cassandra/cassandra.yaml b/examples/cassandra/cassandra.yaml index 23efd35e9a..ef1dc0fa21 100644 --- a/examples/cassandra/cassandra.yaml +++ b/examples/cassandra/cassandra.yaml @@ -1,36 +1,35 @@ -id: cassandra +apiVersion: v1beta3 kind: Pod -apiVersion: v1beta1 -desiredState: - manifest: - version: v1beta1 - id: cassandra - containers: - - name: cassandra - image: kubernetes/cassandra:v2 - command: - - /run.sh - cpu: 1000 - ports: - - name: cql - containerPort: 9042 - - name: thrift - containerPort: 9160 - volumeMounts: - - name: data - mountPath: /cassandra_data - env: - - key: MAX_HEAP_SIZE - value: 512M - - key: HEAP_NEWSIZE - value: 100M - - key: KUBERNETES_API_PROTOCOL - value: http - volumes: - - name: data - source: - emptyDir: {} -labels: +metadata: + labels: + name: cassandra name: cassandra +spec: + containers: + - args: + - /run.sh + resources: + limits: + cpu: "1" + image: kubernetes/cassandra:v2 + 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: KUBERNETES_API_PROTOCOL + value: http + volumes: + - name: data + emptyDir: {} diff --git a/examples/cassandra/java/src/io/k8s/cassandra/KubernetesSeedProvider.java b/examples/cassandra/java/src/io/k8s/cassandra/KubernetesSeedProvider.java index 8b8ad40bb9..5ad92b7a03 100644 --- a/examples/cassandra/java/src/io/k8s/cassandra/KubernetesSeedProvider.java +++ b/examples/cassandra/java/src/io/k8s/cassandra/KubernetesSeedProvider.java @@ -64,7 +64,7 @@ public class KubernetesSeedProvider implements SeedProvider { String host = protocol + "://" + hostName + ":" + hostPort; String serviceName = getEnvOrDefault("CASSANDRA_SERVICE", "cassandra"); - String path = "/api/v1beta1/endpoints/"; + String path = "/api/v1beta3/endpoints/"; try { URL url = new URL(host + path + serviceName); ObjectMapper mapper = new ObjectMapper(); diff --git a/examples/cassandra/v1beta3/README.md b/examples/cassandra/v1beta3/README.md deleted file mode 100644 index a62d1c30f2..0000000000 --- a/examples/cassandra/v1beta3/README.md +++ /dev/null @@ -1,64 +0,0 @@ -## Cloud Native Deployments of Cassandra using Kubernetes v1beta3 api - -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. - -This document also attempts to describe the core components of Kubernetes, _Pods_, _Services_ and _Replication Controllers_. - -### Prerequisites -This example assumes that you have a Kubernetes cluster installed and running, and that you have installed the ```kubectl``` command line tool somewhere in your path. Please see the [getting started](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs/getting-started-guides) for installation instructions for your platform. - - -The v1beta3 API is not enabled by default. The kube-apiserver process needs to run with the --runtime_config=api/v1beta3 argument. Use the following command to enable it: -```sh -$sudo sed -i 's|KUBE_API_ARGS="|KUBE_API_ARGS="--runtime_config=api/v1beta3|' /etc/kubernetes/apiserver - - -``` - - -### quickstart -For those of you who are impatient, here is the summary of the commands we ran in this tutorial. - -```sh -# create a single cassandra node -kubectl create -f cassandra-controller.yaml - -# create a service to track all cassandra nodes -kubectl create -f cassandra-service.yaml - -$ docker exec nodetool status -Datacenter: datacenter1 -======================= -Status=Up/Down -|/ State=Normal/Leaving/Joining/Moving --- Address Load Tokens Owns (effective) Host ID Rack -UN 10.244.3.29 72.07 KB 256 100.0% f736f0b5-bd1f-46f1-9b9d-7e8f22f37c9e rack1 - -# scale up to 2 nodes -kubectl resize rc cassandra --replicas=2 - -# validate the cluster -$ docker exec nodetool status -Datacenter: datacenter1 -======================= -Status=Up/Down -|/ State=Normal/Leaving/Joining/Moving --- Address Load Tokens Owns (effective) Host ID Rack -UN 10.244.3.29 72.07 KB 256 100.0% f736f0b5-bd1f-46f1-9b9d-7e8f22f37c9e rack1 -UN 10.244.1.10 41.14 KB 256 100.0% 42617acd-b16e-4ee3-9486-68a6743657b1 rack1 - -# scale up to 4 nodes -kubectl resize rc cassandra --replicas=4 - -# validate the cluster -$ docker exec nodetool status -Datacenter: datacenter1 -======================= -Status=Up/Down -|/ State=Normal/Leaving/Joining/Moving --- Address Load Tokens Owns (effective) Host ID Rack -UN 10.244.3.29 72.07 KB 256 49.5% f736f0b5-bd1f-46f1-9b9d-7e8f22f37c9e rack1 -UN 10.244.2.14 61.62 KB 256 52.6% 3e9981a6-6919-42c4-b2b8-af50f23a68f2 rack1 -UN 10.244.1.10 41.14 KB 256 49.5% 42617acd-b16e-4ee3-9486-68a6743657b1 rack1 -UN 10.244.4.8 63.83 KB 256 48.3% eeb73967-d1e6-43c1-bb54-512f8117d372 rack1 -``` diff --git a/examples/cassandra/v1beta3/cassandra-controller.yaml b/examples/cassandra/v1beta3/cassandra-controller.yaml deleted file mode 100644 index a860c96086..0000000000 --- a/examples/cassandra/v1beta3/cassandra-controller.yaml +++ /dev/null @@ -1,42 +0,0 @@ -apiVersion: v1beta3 -kind: ReplicationController -metadata: - labels: - name: cassandra - name: cassandra -spec: - replicas: 1 - selector: - name: cassandra - template: - metadata: - labels: - name: cassandra - spec: - containers: - - command: - - /run.sh - resources: - limits: - cpu: 1 - env: - - name: MAX_HEAP_SIZE - key: MAX_HEAP_SIZE - value: 512M - - name: HEAP_NEWSIZE - key: HEAP_NEWSIZE - value: 100M - image: "kubernetes/cassandra:v1" - name: cassandra - ports: - - containerPort: 9042 - name: cql - - containerPort: 9160 - name: thrift - volumeMounts: - - mountPath: /cassandra_data - name: data - volumes: - - name: data - emptyDir: {} - diff --git a/examples/cassandra/v1beta3/cassandra-service.yaml b/examples/cassandra/v1beta3/cassandra-service.yaml deleted file mode 100644 index 1811db7753..0000000000 --- a/examples/cassandra/v1beta3/cassandra-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1beta3 -kind: Service -metadata: - labels: - name: cassandra - name: cassandra -spec: - ports: - - port: 9042 - targetPort: 9042 - selector: - name: cassandra