diff --git a/content/zh/docs/tutorials/stateful-application/cassandra.md b/content/zh/docs/tutorials/stateful-application/cassandra.md index 98d0d6ab44..461e3d1632 100644 --- a/content/zh/docs/tutorials/stateful-application/cassandra.md +++ b/content/zh/docs/tutorials/stateful-application/cassandra.md @@ -1,807 +1,439 @@ --- -title: "示例:使用 Stateful Sets 部署 Cassandra" +title: "示例:使用 StatefulSet 部署 Cassandra" +content_type: tutorial +weight: 30 --- -## 目录 + + +本教程描述拉如何在 Kubernetes 上运行 [Apache Cassandra](https://cassandra.apache.org/)。 +数据库 Cassandra 需要永久性存储提供数据持久性(应用 _状态_)。 +在此示例中,自定义 Cassandra seed provider 使数据库在加入 Cassandra 集群时发现新的 Cassandra 实例。 - - [准备工作](#prerequisites) - - [Cassandra docker 镜像](#cassandra-docker) - - [快速入门](#quickstart) - - [步骤1:创建 Cassandra Headless Service](#step-1-create-a-cassandra-headless-service) - - [步骤2:使用 StatefulSet 创建 Cassandra Ring 环](#step-2-use-a-statefulset-to-create-cassandra-ring) - - [步骤3:验证并修改 Cassandra StatefulSet](#step-3-validate-and-modify-the-cassandra-statefulset) - - [步骤4:删除 Cassandra StatefulSet](#step-4-delete-cassandra-statefulset) - - [步骤5:使用 Replication Controller 创建 Cassandra 节点 pods](#step-5-use-a-replication-controller-to-create-cassandra-node-pods) - - [步骤6:Cassandra 集群扩容](#step-6-scale-up-the-cassandra-cluster) - - [步骤7:删除 Replication Controller](#step-7-delete-the-replication-controller) - - [步骤8:使用 DaemonSet 替换 Replication Controller](#step-8-use-a-daemonset-instead-of-a-replication-controller) - - [步骤9:资源清理](#step-9-resource-cleanup) - - [Seed Provider Source](#seed-provider-source) + +使用 *StatefulSets* 可以更轻松地将有状态的应用程序部署到你的 Kubernetes 集群中。 +有关本教程中使用的功能的更多信息, +参阅 [StatefulSet](/zh/docs/concepts/workloads/controllers/statefulset/)。 + + +{{< note >}} +Cassandra 和 Kubernetes 都使用术语 _node_ 来表示集群的成员。 +在本教程中,属于 StatefulSet 的 Pod 是 Cassandra 节点,并且是 Cassandra 集群的成员(称为 _ring_)。 +当这些 Pod 在你的 Kubernetes 集群中运行时,Kubernetes 控制平面会将这些 Pod 调度到 Kubernetes 的 +{{< glossary_tooltip text="节点" term_id="node" >}}上。 + + +当 Cassandra 节点启动时,使用 _seed列表_ 来引导发现 ring 中其他节点。 +本教程部署了一个自定义的 Cassandra seed provider,使数据库可以发现新的 Cassandra Pod 出现在 Kubernetes 集群中。 +{{< /note >}} + +## {{% heading "objectives" %}} + + +* 创建并验证 Cassandra 无头(headless){{< glossary_tooltip text="Service" term_id="service" >}}.. +* 使用 {{< glossary_tooltip term_id="StatefulSet" >}} 创建一个 Cassandra ring。 +* 验证 StatefulSet。 +* 修改 StatefulSet。 +* 删除 StatefulSet 及其 {{< glossary_tooltip text="Pod" term_id="pod" >}}. -下文描述了在 Kubernetes 上部署一个_云原生_ [Cassandra](http://cassandra.apache.org/) 的过程。当我们说_云原生_时,指的是一个应用能够理解它运行在一个集群管理器内部,并且使用这个集群的管理基础设施来帮助实现这个应用。特别的,本例使用了一个自定义的 Cassandra `SeedProvider` 帮助 Cassandra 发现新加入集群 Cassandra 节点。 +## {{% heading "prerequisites" %}} + +{{< include "task-tutorial-prereqs.md" >}} + + +要完成本教程,你应该已经熟悉 {{< glossary_tooltip text="Pod" term_id="pod" >}}, +{{< glossary_tooltip text="Service" term_id="service" >}}和 {{< glossary_tooltip text="StatefulSet" term_id="StatefulSet" >}}。 + + +### 额外的 Minikube 设置说明 + +{{< caution >}} +[Minikube](https://minikube.sigs.k8s.io/docs/)默认为 1024MiB 内存和 1 个 CPU。 +在本教程中,使用默认资源配置运行 Minikube 会导致资源不足的错误。为避免这些错误,请使用以下设置启动 Minikube: + +```shell +minikube start --memory 5120 --cpus=4 +``` +{{< /caution >}} -本示例也使用了Kubernetes的一些核心组件: + + +## 为 Cassandra 创建无头(headless) Services {#creating-a-cassandra-headless-service} -## 准备工作 - - -本示例假设你已经安装运行了一个 Kubernetes集群(版本 >=1.2),并且还在某个路径下安装了 [`kubectl`](/zh/docs/tasks/tools/install-kubectl/) 命令行工具。请查看 [getting started guides](/zh/docs/getting-started-guides/) 获取关于你的平台的安装说明。 - - -本示例还需要一些代码和配置文件。为了避免手动输入,你可以 `git clone` Kubernetes 源到你本地。 - - -## Cassandra Docker 镜像 - - -Pod 使用来自 Google [容器仓库](https://cloud.google.com/container-registry/docs/) 的 [```gcr.io/google-samples/cassandra:v12```](https://github.com/kubernetes/examples/blob/master/cassandra/image/Dockerfile) 镜像。这个 docker 镜像基于 `debian:jessie` 并包含 OpenJDK 8。该镜像包含一个从 Apache Debian 源中安装的标准 Cassandra。你可以通过使用环境变量改变插入到 `cassandra.yaml` 文件中的参数值。 - -| ENV VAR | DEFAULT VALUE | -| ---------------------- | :------------: | -| CASSANDRA_CLUSTER_NAME | 'Test Cluster' | -| CASSANDRA_NUM_TOKENS | 32 | -| CASSANDRA_RPC_ADDRESS | 0.0.0.0 | - - -## 快速入门 +在 Kubernetes 中,一个 {{< glossary_tooltip text="Service" term_id="service" >}} +描述了一组执行相同任务的 {{< glossary_tooltip text="Pod" term_id="pod" >}}。 +以下 Service 用于在 Cassandra Pod 和集群中的客户端之间进行 DNS 查找: {{< codenew file="application/cassandra/cassandra-service.yaml" >}} -如果你希望直接跳到我们使用的命令,以下是全部步骤: - - - -```sh +创建一个 Service 来跟踪 `cassandra-service.yaml` 文件中的所有 Cassandra StatefulSet: +```shell kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-service.yaml ``` + +### 验证(可选) {#validating} + +获取 Cassandra Service。 + +```shell +kubectl get svc cassandra +``` + + +响应是: + +``` +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +cassandra ClusterIP None 9042/TCP 45s +``` + + +如果没有看到名为 `cassandra` 的服务,则表示创建失败。 +请阅读[Debug Services](/zh/docs/tasks/debug-application-cluster/debug-service/),以解决常见问题。 + + +## 使用 StatefulSet 创建 Cassandra Ring + +下面包含的 StatefulSet 清单创建了一个由三个 Pod 组成的 Cassandra ring。 + +{{< note >}} +本示例使用 Minikube 的默认配置程序。 +请为正在使用的云更新以下 StatefulSet。 +{{< /note >}} + {{< codenew file="application/cassandra/cassandra-statefulset.yaml" >}} -``` -# 创建 statefulset + +使用 `cassandra-statefulset.yaml` 文件创建 Cassandra StatefulSet : + +```shell +# 如果你能未经修改地 apply cassandra-statefulset.yaml,请使用此命令 kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml - -# 验证 Cassandra 集群。替换一个 pod 的名称。 -kubectl exec -ti cassandra-0 -- nodetool status - -# 清理 -grace=$(kubectl get po cassandra-0 -o=jsonpath='{.spec.terminationGracePeriodSeconds}') \ - && kubectl delete statefulset,po -l app=cassandra \ - && echo "Sleeping $grace" \ - && sleep $grace \ - && kubectl delete pvc -l app=cassandra - -# -# 资源控制器示例 -# - -# 创建一个副本控制器来复制 cassandra 节点 -kubectl create -f cassandra/cassandra-controller.yaml - -# 验证 Cassandra 集群。替换一个 pod 的名称。 -kubectl exec -ti cassandra-xxxxx -- nodetool status - -# 扩大 Cassandra 集群 -kubectl scale rc cassandra --replicas=4 - -# 删除副本控制器 -kubectl delete rc cassandra - -# -# 创建一个 DaemonSet,在每个 kubernetes 节点上放置一个 cassandra 节点 -# - -kubectl create -f cassandra/cassandra-daemonset.yaml --validate=false - -# 资源清理 -kubectl delete service -l app=cassandra -kubectl delete daemonset cassandra ``` +如果你为了适合你的集群需要修改 `cassandra-statefulset.yaml`, +下载 https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml, +然后 apply 修改后的清单。 -## 步骤 1:创建 Cassandra Headless Service - - -Kubernetes _[Service](/zh/docs/user-guide/services)_ 描述一组执行同样任务的 [_Pod_](/zh/docs/user-guide/pods)。在 Kubernetes 中,一个应用的原子调度单位是一个 Pod:一个或多个_必须_调度到相同主机上的容器。 - -这个 Service 用于在 Kubernetes 集群内部进行 Cassandra 客户端和 Cassandra Pod 之间的 DNS 查找。 - -以下为这个 service 的描述: - -```yaml -apiVersion: v1 -kind: Service -metadata: - labels: - app: cassandra - name: cassandra -spec: - clusterIP: None - ports: - - port: 9042 - selector: - app: cassandra +```shell +# 如果使用本地的 cassandra-statefulset.yaml ,请使用此命令 +kubectl apply -f cassandra-statefulset.yaml ``` + +## 验证 Cassandra StatefulSet -为 StatefulSet 创建 service +1.获取 Cassandra StatefulSet: -```console -kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-service.yaml -``` + ```shell + kubectl get statefulset cassandra + ``` + + + 响应应该与此类似: -以下命令显示了 service 是否被成功创建。 + ``` + NAME DESIRED CURRENT AGE + cassandra 3 0 13s + ``` -```console -$ kubectl get svc cassandra -``` + + `StatefulSet` 资源会按顺序部署 Pod。 -命令的响应应该像这样: +2.获取 Pod 查看已排序的创建状态: + + ```shell + kubectl get pods -l="app=cassandra" + ``` -```console -NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE -cassandra None 9042/TCP 45s -``` + + 响应应该与此类似: -如果返回错误则表示 service 创建失败。 + ```shell + NAME READY STATUS RESTARTS AGE + cassandra-0 1/1 Running 0 1m + cassandra-1 0/1 ContainerCreating 0 8s + ``` -## 步骤 2:使用 StatefulSet 创建 Cassandra Ring环 + + 这三个 Pod 要花几分钟的时间才能部署。部署之后,相同的命令将返回类似于以下的输出: -StatefulSets(以前叫做 PetSets)特性在 Kubernetes 1.5 中升级为一个 Beta 组件。在集群环境中部署类似于 Cassandra 的有状态分布式应用是一项具有挑战性的工作。我们实现了 StatefulSet,极大的简化了这个过程。本示例使用了 StatefulSet 的多个特性,但其本身超出了本文的范围。[请参考 StatefulSet 文档](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)。 + ``` + NAME READY STATUS RESTARTS AGE + cassandra-0 1/1 Running 0 10m + cassandra-1 1/1 Running 0 9m + cassandra-2 1/1 Running 0 8m + ``` + +3.运行第一个 Pod 中的 Cassandra [nodetool](https://cwiki.apache.org/confluence/display/CASSANDRA2/NodeTool),以显示 ring 的状态。 -以下是 StatefulSet 的清单文件,用于创建一个由三个 pod 组成的 Cassandra ring 环。 + ```shell + kubectl exec -it cassandra-0 -- nodetool status + ``` + + 响应应该与此类似: -本示例使用了 GCE Storage Class,请根据你运行的云平台做适当的修改。 + ``` + Datacenter: DC1-K8Demo + ====================== + Status=Up/Down + |/ State=Normal/Leaving/Joining/Moving + -- Address Load Tokens Owns (effective) Host ID Rack + UN 172.17.0.5 83.57 KiB 32 74.0% e2dd09e6-d9d3-477e-96c5-45094c08db0f Rack1-K8Demo + UN 172.17.0.4 101.04 KiB 32 58.8% f89d6835-3a42-4419-92b3-0e62cae1479c Rack1-K8Demo + UN 172.17.0.6 84.74 KiB 32 67.1% a6a1e8c2-3dc5-4417-b1a0-26507af2aaad Rack1-K8Demo + ``` -```yaml -apiVersion: "apps/v1beta1" -kind: StatefulSet -metadata: - name: cassandra -spec: - serviceName: cassandra - replicas: 3 - template: + +## 修改 Cassandra StatefulSet + +使用 `kubectl edit` 修改 Cassandra StatefulSet 的大小。 + +1.运行以下命令: + + ```shell + kubectl edit statefulset cassandra + ``` + + + 此命令你的终端中打开一个编辑器。需要更改的是 `replicas` 字段。下面是 StatefulSet 文件的片段示例: + + ```yaml + # Please edit the object below. Lines beginning with a '#' will be ignored, + # and an empty file will abort the edit. If an error occurs while saving this file will be + # reopened with the relevant failures. + # + apiVersion: apps/v1 + kind: StatefulSet metadata: + creationTimestamp: 2016-08-13T18:40:58Z + generation: 1 labels: - app: cassandra - spec: - containers: - - name: cassandra - image: gcr.io/google-samples/cassandra:v12 - imagePullPolicy: Always - ports: - - containerPort: 7000 - name: intra-node - - containerPort: 7001 - name: tls-intra-node - - containerPort: 7199 - name: jmx - - containerPort: 9042 - name: cql - resources: - limits: - cpu: "500m" - memory: 1Gi - requests: - cpu: "500m" - memory: 1Gi - securityContext: - capabilities: - add: - - IPC_LOCK - lifecycle: - preStop: - exec: - command: ["/bin/sh", "-c", "PID=$(pidof java) && kill $PID && while ps -p $PID > /dev/null; do sleep 1; done"] - env: - - name: MAX_HEAP_SIZE - value: 512M - - name: HEAP_NEWSIZE - value: 100M - - name: CASSANDRA_SEEDS - value: "cassandra-0.cassandra.default.svc.cluster.local" - - name: CASSANDRA_CLUSTER_NAME - value: "K8Demo" - - name: CASSANDRA_DC - value: "DC1-K8Demo" - - name: CASSANDRA_RACK - value: "Rack1-K8Demo" - - name: CASSANDRA_AUTO_BOOTSTRAP - value: "false" - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - readinessProbe: - exec: - command: - - /bin/bash - - -c - - /ready-probe.sh - initialDelaySeconds: 15 - timeoutSeconds: 5 - # These volume mounts are persistent. They are like inline claims, - # but not exactly because the names need to match exactly one of - # the stateful pod volumes. - volumeMounts: - - name: cassandra-data - mountPath: /cassandra_data - # These are converted to volume claims by the controller - # and mounted at the paths mentioned above. - # do not use these in production until ssd GCEPersistentDisk or other ssd pd - volumeClaimTemplates: - - metadata: - name: cassandra-data - annotations: - volume.beta.kubernetes.io/storage-class: fast - spec: - accessModes: [ "ReadWriteOnce" ] - resources: - requests: - storage: 1Gi ---- -kind: StorageClass -apiVersion: storage.k8s.io/v1beta1 -metadata: - name: fast -provisioner: kubernetes.io/gce-pd -parameters: - type: pd-ssd -``` - -创建 Cassandra StatefulSet 如下: - -```console -kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml -``` - -## 步骤 3:验证和修改 Cassandra StatefulSet - -这个 StatefulSet 的部署展示了 StatefulSets 提供的两个新特性: - -1. Pod 的名称已知 -2. Pod 以递增顺序部署 - - -首先,运行下面的 `kubectl` 命令,验证 StatefulSet 已经被成功部署。 - -```console -$ kubectl get statefulset cassandra -``` - -这个命令的响应应该像这样: - -```console -NAME DESIRED CURRENT AGE -cassandra 3 3 13s -``` - -接下来观察 Cassandra pod 以一个接一个的形式部署。StatefulSet 资源按照数字序号的模式部署 pod:1, 2, 3 等。如果在 pod 部署前执行下面的命令,你就能够看到这种顺序的创建过程。 - -```console -$ kubectl get pods -l="app=cassandra" -NAME READY STATUS RESTARTS AGE -cassandra-0 1/1 Running 0 1m -cassandra-1 0/1 ContainerCreating 0 8s -``` - -上面的示例显示了三个 Cassandra StatefulSet pod 中的两个已经部署。一旦所有的 pod 都部署成功,相同的命令会显示一个完整的 StatefulSet。 - -```console -$ kubectl get pods -l="app=cassandra" -NAME READY STATUS RESTARTS AGE -cassandra-0 1/1 Running 0 10m -cassandra-1 1/1 Running 0 9m -cassandra-2 1/1 Running 0 8m -``` - -运行 Cassandra 工具 `nodetool` 将显示 ring 环的状态。 - -```console -$ kubectl exec cassandra-0 -- nodetool status -Datacenter: DC1-K8Demo -====================== -Status=Up/Down -|/ State=Normal/Leaving/Joining/Moving --- Address Load Tokens Owns (effective) Host ID Rack -UN 10.4.2.4 65.26 KiB 32 63.7% a9d27f81-6783-461d-8583-87de2589133e Rack1-K8Demo -UN 10.4.0.4 102.04 KiB 32 66.7% 5559a58c-8b03-47ad-bc32-c621708dc2e4 Rack1-K8Demo -UN 10.4.1.4 83.06 KiB 32 69.6% 9dce943c-581d-4c0e-9543-f519969cc805 Rack1-K8Demo -``` - -你也可以运行 `cqlsh` 来显示集群的 keyspaces。 - -```console -$ kubectl exec cassandra-0 -- cqlsh -e 'desc keyspaces' - -system_traces system_schema system_auth system system_distributed -``` - -你需要使用 `kubectl edit` 来增加或减小 Cassandra StatefulSet 的大小。你可以在[文档](/zh/docs/user-guide/kubectl/kubectl_edit) 中找到更多关于 `edit` 命令的信息。 - -使用以下命令编辑 StatefulSet。 - -```console -$ kubectl edit statefulset cassandra -``` - -这会在你的命令行中创建一个编辑器。你需要修改的行是 `replicas`。这个例子没有包含终端窗口的所有内容,下面示例中的最后一行就是你希望改变的 replicas 行。 - -```console -# Please edit the object below. Lines beginning with a '#' will be ignored, -# and an empty file will abort the edit. If an error occurs while saving this file will be -# reopened with the relevant failures. -# -apiVersion: apps/v1beta1 -kind: StatefulSet -metadata: - creationTimestamp: 2016-08-13T18:40:58Z - generation: 1 - labels: - app: cassandra - name: cassandra - namespace: default - resourceVersion: "323" - uid: 7a219483-6185-11e6-a910-42010a8a0fc0 -spec: - replicas: 3 -``` - - -按下面的示例修改清单文件并保存。 - -```console -spec: - replicas: 4 -``` - -这个 StatefulSet 现在将包含四个 pod。 - -```console -$ kubectl get statefulset cassandra -``` - -这个command的响应应该像这样: - -```console -NAME DESIRED CURRENT AGE -cassandra 4 4 36m -``` - - -对于 Kubernetes 1.5 发布版,beta StatefulSet 资源没有像 Deployment, ReplicaSet, Replication Controller 或者 Job 一样,包含 `kubectl scale` 功能, - - -## 步骤 4:删除 Cassandra StatefulSet - - -删除或者缩容 StatefulSet 时不会删除与之关联的 volumes。这样做是为了优先保证安全。你的数据比其它会被自动清除的 StatefulSet 关联资源更宝贵。删除 Persistent Volume Claims 可能会导致关联的 volumes 被删除,这种行为依赖 storage class 和 reclaim policy。永远不要期望能在 claim 删除后访问一个 volume。 - - -使用如下命令删除 StatefulSet。 - -```console -$ grace=$(kubectl get po cassandra-0 -o=jsonpath='{.spec.terminationGracePeriodSeconds}') \ - && kubectl delete statefulset -l app=cassandra \ - && echo "Sleeping $grace" \ - && sleep $grace \ - && kubectl delete pvc -l app=cassandra -``` - - -## 步骤 5:使用 Replication Controller 创建 Cassandra 节点 pod - - -Kubernetes _[Replication Controller](/zh/docs/user-guide/replication-controller)_ 负责复制一个完全相同的 pod 集合。像 Service 一样,它具有一个 selector query,用来识别它的集合成员。和 Service 不一样的是,它还具有一个期望的副本数,并且会通过创建或删除 Pod 来保证 Pod 的数量满足它期望的状态。 - -和我们刚才定义的 Service 一起,Replication Controller 能够让我们轻松的构建一个复制的、可扩展的 Cassandra 集群。 - -让我们创建一个具有两个初始副本的 replication controller。 - -```yaml -apiVersion: v1 -kind: ReplicationController -metadata: - name: cassandra - # The labels will be applied automatically - # from the labels in the pod template, if not set - # labels: - # app: cassandra -spec: - replicas: 2 - # The selector will be applied automatically - # from the labels in the pod template, if not set. - # selector: - # app: cassandra - template: - metadata: - labels: - app: cassandra - spec: - containers: - - command: - - /run.sh - resources: - limits: - cpu: 0.5 - env: - - name: MAX_HEAP_SIZE - value: 512M - - name: HEAP_NEWSIZE - value: 100M - - name: CASSANDRA_SEED_PROVIDER - value: "io.k8s.cassandra.KubernetesSeedProvider" - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - image: gcr.io/google-samples/cassandra:v12 - name: cassandra - ports: - - containerPort: 7000 - name: intra-node - - containerPort: 7001 - name: tls-intra-node - - containerPort: 7199 - name: jmx - - containerPort: 9042 - name: cql - volumeMounts: - - mountPath: /cassandra_data - name: data - volumes: - - name: data - emptyDir: {} -``` - -[下载示例](https://raw.githubusercontent.com/kubernetes/examples/master/cassandra-controller.yaml) - -在这个描述中需要注意几件事情。 - -`selector` 属性包含了控制器的 selector query。它能够被显式指定,或者在没有设置时,像此处一样从 pod 模板中的 labels 中自动应用。 - -Pod 模板的标签 `app:cassandra` 匹配步骤1中的 Service selector。这就是 Service 如何选择 replication controller 创建的 pod 的原理。 - -`replicas` 属性指明了期望的副本数量,在本例中最开始为 2。我们很快将要扩容更多数量。 - -创建 Replication Controller: - -```console - -$ kubectl create -f cassandra/cassandra-controller.yaml - -``` - -你可以列出新建的 controller: - -```console - -$ kubectl get rc -o wide -NAME DESIRED CURRENT AGE CONTAINER(S) IMAGE(S) SELECTOR -cassandra 2 2 11s cassandra gcr.io/google-samples/cassandra:v12 app=cassandra - -``` - -现在,如果你列出集群中的 pod,并且使用 `app=cassandra` 标签过滤,你应该能够看到两个 Cassandra pod。(`wide` 参数使你能够看到 pod 被调度到了哪个 Kubernetes 节点上) - -```console -$ kubectl get pods -l="app=cassandra" -o wide -NAME READY STATUS RESTARTS AGE NODE -cassandra-21qyy 1/1 Running 0 1m kubernetes-minion-b286 -cassandra-q6sz7 1/1 Running 0 1m kubernetes-minion-9ye5 -``` - - -因为这些 pod 拥有 `app=cassandra` 标签,它们被映射给了我们在步骤 1 中创建的 service。 - -你可以使用下面的 service endpoint 查询命令来检查 Pod 是否对 Service 可用。 - -```console - -$ kubectl get endpoints cassandra -o yaml -apiVersion: v1 -kind: Endpoints -metadata: - creationTimestamp: 2015-06-21T22:34:12Z - labels: - app: cassandra - name: cassandra - namespace: default - resourceVersion: "944373" - uid: a3d6c25f-1865-11e5-a34e-42010af01bcc -subsets: -- addresses: - - ip: 10.244.3.15 - targetRef: - kind: Pod + app: cassandra name: cassandra namespace: default - resourceVersion: "944372" - uid: 9ef9895d-1865-11e5-a34e-42010af01bcc - ports: - - port: 9042 - protocol: TCP - -``` - - -为了显示 `SeedProvider` 逻辑是按设想在运行,你可以使用 `nodetool` 命令来检查 Cassandra 集群的状态。为此,请使用 `kubectl exec` 命令,这样你就能在一个 Cassandra pod 上运行 `nodetool`。同样的,请替换 `cassandra-xxxxx` 为任意一个 pods的真实名字。 - -```console - -$ kubectl exec -ti cassandra-xxxxx -- 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.3.3 51.28 KB 256 100.0% dafe3154-1d67-42e1-ac1d-78e7e80dce2b rack1 - -``` - - -## 步骤 6:Cassandra 集群扩容 - - -现在,让我们把 Cassandra 集群扩展到 4 个 pod。我们通过告诉 Replication Controller 现在我们需要 4 个副本来完成。 - -```sh - -$ kubectl scale rc cassandra --replicas=4 - -``` - -你可以看到列出了新的 pod: - -```console - -$ kubectl get pods -l="app=cassandra" -o wide -NAME READY STATUS RESTARTS AGE NODE -cassandra-21qyy 1/1 Running 0 6m kubernetes-minion-b286 -cassandra-81m2l 1/1 Running 0 47s kubernetes-minion-b286 -cassandra-8qoyp 1/1 Running 0 47s kubernetes-minion-9ye5 -cassandra-q6sz7 1/1 Running 0 6m kubernetes-minion-9ye5 - -``` - - -一会儿你就能再次检查 Cassandra 集群的状态,你可以看到新的 pod 已经被自定义的 `SeedProvider` 检测到: - -```console - -$ kubectl exec -ti cassandra-xxxxx -- nodetool status -Datacenter: datacenter1 -======================= -Status=Up/Down -|/ State=Normal/Leaving/Joining/Moving --- Address Load Tokens Owns (effective) Host ID Rack -UN 10.244.0.6 51.67 KB 256 48.9% d07b23a5-56a1-4b0b-952d-68ab95869163 rack1 -UN 10.244.1.5 84.71 KB 256 50.7% e060df1f-faa2-470c-923d-ca049b0f3f38 rack1 -UN 10.244.1.6 84.71 KB 256 47.0% 83ca1580-4f3c-4ec5-9b38-75036b7a297f rack1 -UN 10.244.0.5 68.2 KB 256 53.4% 72ca27e2-c72c-402a-9313-1e4b61c2f839 rack1 - -``` - - -## 步骤 7:删除 Replication Controller - - -在你开始步骤 5 之前, __删除__你在上面创建的 __replication controller__。 - -```sh - -$ kubectl delete rc cassandra - -``` - -## 步骤 8:使用 DaemonSet 替换 Replication Controller - - -在 Kubernetes中,[_DaemonSet_](/zh/docs/admin/daemons) 能够将 pod 一对一的分布到 Kubernetes 节点上。和 _ReplicationController_ 相同的是它也有一个用于识别它的集合成员的 selector query。但和 _ReplicationController_ 不同的是,它拥有一个节点 selector,用于限制基于模板的 pod 可以调度的节点。并且 pod 的复制不是基于一个设置的数量,而是为每一个节点分配一个 pod。 - -示范用例:当部署到云平台时,预期情况是实例是短暂的并且随时可能终止。Cassandra 被搭建成为在各个节点间复制数据以便于实现数据冗余。这样的话,即使一个实例终止了,存储在它上面的数据却没有,并且集群会通过重新复制数据到其它运行节点来作为响应。 - -`DaemonSet` 设计为在 Kubernetes 集群中的每个节点上放置一个 pod。那样就会给我们带来数据冗余度。让我们创建一个 DaemonSet 来启动我们的存储集群: - - -```yaml -apiVersion: extensions/v1beta1 -kind: DaemonSet -metadata: - labels: - name: cassandra - name: cassandra -spec: - template: - metadata: - labels: - app: cassandra + resourceVersion: "323" + uid: 7a219483-6185-11e6-a910-42010a8a0fc0 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: CASSANDRA_SEED_PROVIDER - value: "io.k8s.cassandra.KubernetesSeedProvider" - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - image: gcr.io/google-samples/cassandra:v12 - name: cassandra - ports: - - containerPort: 7000 - name: intra-node - - containerPort: 7001 - name: tls-intra-node - - containerPort: 7199 - name: jmx - - containerPort: 9042 - name: cql - # If you need it, it will go away in C* 4.0. - #- containerPort: 9160 - # name: thrift - resources: - requests: - cpu: 0.5 - volumeMounts: - - mountPath: /cassandra_data - name: data - volumes: - - name: data - emptyDir: {} -``` + replicas: 3 + ``` + + +2.将副本数 (replicas) 更改为 4,然后保存清单。 + + StatefulSet 现在可以扩展到运行 4 个 Pod。 + +3.获取 Cassandra StatefulSet 验证更改: + + ```shell + kubectl get statefulset cassandra + ``` + + + 响应应该与此类似: + + ``` + NAME DESIRED CURRENT AGE + cassandra 4 4 36m + ``` + +## {{% heading "cleanup" %}} + + +删除或缩小 StatefulSet 不会删除与 StatefulSet 关联的卷。 +这个设置是出于安全考虑,因为你的数据比自动清除所有相关的 StatefulSet 资源更有价值。 + +{{< warning >}} +根据存储类和回收策略,删除 *PersistentVolumeClaims* 可能导致关联的卷也被删除。 +千万不要认为其容量声明被删除,你就能访问数据。 +{{< /warning >}} + +1.运行以下命令(连在一起成为一个单独的命令)删除 Cassandra StatefulSet 中的所有内容: + + ```shell + grace=$(kubectl get pod cassandra-0 -o=jsonpath='{.spec.terminationGracePeriodSeconds}') \ + && kubectl delete statefulset -l app=cassandra \ + && echo "Sleeping ${grace} seconds" 1>&2 \ + && sleep $grace \ + && kubectl delete persistentvolumeclaim -l app=cassandra + ``` + + +2.运行以下命令,删除你为 Cassandra 设置的 Service: + + ```shell + kubectl delete service -l app=cassandra + ``` + + +## Cassandra 容器环境变量 +本教程中的 Pod 使用来自 Google [container registry](https://cloud.google.com/container-registry/docs/) +的 [`gcr.io/google-samples/cassandra:v13`](https://github.com/kubernetes/examples/blob/master/cassandra/image/Dockerfile) 镜像。 +上面的 Docker 镜像基于 [debian-base](https://github.com/kubernetes/kubernetes/tree/master/build/debian-base),并且包含 OpenJDK 8。 + +该映像包括来自 Apache Debian 存储库的标准 Cassandra 安装。 +通过使用环境变量,您可以更改插入到 `cassandra.yaml` 中的值。 + +| Environment variable | Default value | +| ------------------------ |:---------------: | +| `CASSANDRA_CLUSTER_NAME` | `'Test Cluster'` | +| `CASSANDRA_NUM_TOKENS` | `32` | +| `CASSANDRA_RPC_ADDRESS` | `0.0.0.0` | -[下载示例](https://raw.githubusercontent.com/kubernetes/examples/master/cassandra-daemonset.yaml) +## {{% heading "whatsnext" %}} -这个 DaemonSet 绝大部分的定义和上面的 ReplicationController 完全相同;它只是简单的给 daemonset 一个创建新的 Cassandra pod 的方法,并且以集群中所有的 Cassandra 节点为目标。 - - -不同之处在于 `nodeSelector` 属性,它允许 DaemonSet 以全部节点的一个子集为目标(你可以向其他资源一样标记节点),并且没有 `replicas` 属性,因为它使用1对1的 node-pod 关系。 - - -创建这个 DaemonSet: - -```console - -$ kubectl create -f cassandra/cassandra-daemonset.yaml - -``` - - -你可能需要禁用配置文件检查,像这样: - -```console - -$ kubectl create -f cassandra/cassandra-daemonset.yaml --validate=false - -``` - - -你可以看到 DaemonSet 已经在运行: - -```console - -$ kubectl get daemonset -NAME DESIRED CURRENT NODE-SELECTOR -cassandra 3 3 - -``` - - -现在,如果你列出集群中的 pods,并且使用 `app=cassandra` 标签过滤,你应该能够看到你的网络中的每一个节点上都有一个(且只有一个)新的 cassandra pod。 - -```console - -$ kubectl get pods -l="app=cassandra" -o wide -NAME READY STATUS RESTARTS AGE NODE -cassandra-ico4r 1/1 Running 0 4s kubernetes-minion-rpo1 -cassandra-kitfh 1/1 Running 0 1s kubernetes-minion-9ye5 -cassandra-tzw89 1/1 Running 0 2s kubernetes-minion-b286 - -``` - - -为了证明这是按设想的在工作,你可以再次使用 `nodetool` 命令来检查集群的状态。为此,请使用 `kubectl exec` 命令在任何一个新建的 cassandra pod 上运行 `nodetool`。 - -```console - -$ kubectl exec -ti cassandra-xxxxx -- 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 - -``` - - -**注意**:这个示例让你在创建 DaemonSet 前删除了 cassandra 的 Replication Controller。这是因为为了保持示例的简单,RC 和 DaemonSet 使用了相同的 `app=cassandra` 标签(如此它们的 pod 映射到了我们创建的 service,这样 SeedProvider 就能识别它们)。 - - -如果我们没有预先删除 RC,这两个资源在需要运行多少 pod 上将会发生冲突。如果希望的话,我们可以使用额外的标签和 selectors 来支持同时运行它们。 - - -## 步骤 9:资源清理 - - -当你准备删除你的资源时,按以下执行: - -```console - -$ kubectl delete service -l app=cassandra -$ kubectl delete daemonset cassandra - -``` - - -### Seed Provider Source - - -我们使用了一个自定义的 [`SeedProvider`](https://gitbox.apache.org/repos/asf?p=cassandra.git;a=blob;f=src/java/org/apache/cassandra/locator/SeedProvider.java;h=7efa9e050a4604c2cffcb953c3c023a2095524fe;hb=c2e11bd4224b2110abe6aa84c8882e85980e3491) 来在 Kubernetes 之上运行 Cassandra。仅当你通过 replication control 或者 daemonset 部署 Cassandra 时才需要使用自定义的 seed provider。在 Cassandra 中,`SeedProvider` 引导 Cassandra 使用 gossip 协议来查找其它 Cassandra 节点。Seed 地址是被视为连接端点的主机。Cassandra 实例使用 seed 列表来查找彼此并学习 ring 环拓扑。[`KubernetesSeedProvider`](https://github.com/kubernetes/examples/blob/master/cassandra/java/src/main/java/io/k8s/cassandra/KubernetesSeedProvider.java) 通过 Kubernetes API 发现 Cassandra seeds IP 地址,那些 Cassandra 实例在 Cassandra Service 中定义。 - -请查阅自定义 seed provider 的 [README](https://git.k8s.io/examples/cassandra/java/README.md) 文档,获取 `KubernetesSeedProvider` 进阶配置。对于本示例来说,你应该不需要自定义 Seed Provider 的配置。 - -查看本示例的 [image](https://github.com/kubernetes/examples/tree/master/cassandra/image) 目录,了解如何构建容器的 docker 镜像及其内容。 - -你可能还注意到我们设置了一些 Cassandra 参数(`MAX_HEAP_SIZE`和`HEAP_NEWSIZE`),并且增加了关于 [namespace](/zh/docs/user-guide/namespaces) 的信息。我们还告诉 Kubernetes 容器暴露了 `CQL` 和 `Thrift` API 端口。最后,我们告诉集群管理器我们需要 0.1 cpu(0.1 核)。 - -[!Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/cassandra/README.md?pixel)]() + +* 了解如何[扩缩 StatefulSet](/docs/tasks/run-application/scale-stateful-set/)。 +* 了解有关 [*KubernetesSeedProvider*](https://github.com/kubernetes/examples/blob/master/cassandra/java/src/main/java/io/k8s/cassandra/KubernetesSeedProvider.java) 的更多信息 +* 查看更多自定义 [Seed Provider Configurations](https://git.k8s.io/examples/cassandra/java/README.md) diff --git a/content/zh/docs/tutorials/stateless-application/guestbook.md b/content/zh/docs/tutorials/stateless-application/guestbook.md index b7ef978490..cae93e2ff9 100644 --- a/content/zh/docs/tutorials/stateless-application/guestbook.md +++ b/content/zh/docs/tutorials/stateless-application/guestbook.md @@ -100,16 +100,15 @@ The manifest file, included below, specifies a Deployment controller that runs a 1. 在下载清单文件的目录中启动终端窗口。 2. 从 `mongo-deployment.yaml` 文件中应用 MongoDB Deployment: + + ```shell kubectl apply -f https://k8s.io/examples/application/guestbook/mongo-deployment.yaml ``` - - - @@ -156,15 +155,15 @@ The guestbook application needs to communicate to the MongoDB to write its data. --> 1. 使用下面的 `mongo-service.yaml` 文件创建 MongoDB 的服务: + + ```shell kubectl apply -f https://k8s.io/examples/application/guestbook/mongo-service.yaml ``` - - @@ -182,7 +181,7 @@ kubectl apply -f ./content/en/examples/application/guestbook/mongo-service.yaml ```shell NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 443/TCP 1m - mongo ClusterIP 10.0.0.151 6379/TCP 8s + mongo ClusterIP 10.0.0.151 27017/TCP 8s ``` 1. 从 `frontend-deployment.yaml` 应用前端 Deployment 文件: + + ```shell kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-deployment.yaml ``` - - @@ -253,10 +252,11 @@ kubectl apply -f ./content/en/examples/application/guestbook/frontend-deployment ### 创建前端服务 应用的 `mongo` 服务只能在 Kubernetes 集群中访问,因为服务的默认类型是 -[ClusterIP](/zh/docs/concepts/services-networking/service/#publishing-services---service-types)。`ClusterIP` 为服务指向的 Pod 集提供一个 IP 地址。这个 IP 地址只能在集群中访问。 +[ClusterIP](/zh/docs/concepts/services-networking/service/#publishing-services-service-types)。 +`ClusterIP` 为服务指向的 Pod 集提供一个 IP 地址。这个 IP 地址只能在集群中访问。 1. 从 `frontend-service.yaml` 文件中应用前端服务: + + ```shell kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-service.yaml ``` - - @@ -303,7 +303,7 @@ kubectl apply -f ./content/en/examples/application/guestbook/frontend-service.ya ``` NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - frontend ClusterIP 10.0.0.112 80/TCP 6s + frontend ClusterIP 10.0.0.112 80/TCP 6s kubernetes ClusterIP 10.0.0.1 443/TCP 4m mongo ClusterIP 10.0.0.151 6379/TCP 2m ``` @@ -364,8 +364,8 @@ If you deployed the `frontend-service.yaml` manifest with type: `LoadBalancer` y 响应应该与此类似: ``` - NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - frontend ClusterIP 10.51.242.136 109.197.92.229 80:32372/TCP 1m + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + frontend LoadBalancer 10.51.242.136 109.197.92.229 80:32372/TCP 1m ```