本文已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已不正确。

使用 Kubernetes Pet Set 的 Cassandra 的 1000 个实例

编者注: 这篇文章是关于 Kubernetes 1.3 新功能的 系列深度文章 的一部分

运行希腊宠物怪兽比赛

为了 Kubernetes 1.3 的发布,我们想对新的 Pet Set 进行测试。 通过测试 Cassandra 的 1000 个实例,我们可以确保 Kubernetes 1.3 已准备好投入生产。 继续阅读,了解我们如何使 Cassandra 适应 Kubernetes,以及我们有史以来最大的部署。

今天,使用容器处理基本有状态的应用程序相当简单。 使用持久卷,可以在 pod 中挂载磁盘,并确保数据在 pod 生命周期之外仍然存在。 然而,对于分布式有状态应用程序的部署,情况可能会变得更加棘手。 使用 Kubernetes 1.3,新的 Pet Set 组件使一切变得更加容易。 为了大规模测试这项新功能,我们决定举办希腊宠物怪兽比赛! 我们在多个可用区进行了数十万次半人马和其他古希腊怪兽的比赛。

File:Cassandra1.jpeg
众所周知,Kubernetes 源自古希腊语:κυβερνήτης。 这意味着舵手、飞行员、舵手或船长。 因此,为了跟踪比赛结果,我们需要一个数据存储,我们选择了 Cassandra。 Κασσάνδρα,Cassandra 是特洛伊国王普里阿摩斯和王后赫卡柏的女儿。 考虑到对古希腊语的多次引用,我们认为让古希腊怪兽比赛是合适的。

从那时起,这个故事就有点偏离了,因为 Cassandra 实际上也是宠物。 继续阅读,我们将解释。

Kubernetes 1.3 中令人兴奋的新功能之一是 Pet Set。 为了组织 Kubernetes 中容器的部署,提供了不同的部署机制。 这些组件的示例包括资源控制器和 Daemon Set。 Pet Set 是一项新功能,它提供了在 Kubernetes 中将容器部署为“宠物”的功能。 Pet Set 为宠物/pod 部署的各个方面提供了身份保证:DNS 名称、一致的存储和有序的 pod 索引。 以前,使用诸如 Deployment 和 Replication Controller 之类的组件只会部署一个具有弱解耦标识的应用程序。 弱标识非常适合管理诸如微服务之类的应用程序,其中服务发现非常重要,应用程序是无状态的,并且单个 pod 的命名无关紧要。 许多软件应用程序确实需要强标识,包括许多不同类型的分布式有状态系统。 Cassandra 是一个分布式应用程序的绝佳示例,它需要一致的网络标识和稳定的存储。

Pet Set 提供以下功能

  • 一个稳定的主机名,可在 DNS 中供其他人使用。 数字基于 Pet Set 名称,从零开始。 例如 cassandra-0。
  • 宠物的序号索引。 0、1、2、3 等。
  • 链接到宠物的序号和主机名的稳定存储。
  • 可以通过 DNS 进行对等发现。 使用 Cassandra,在创建 Pets 之前就知道对等点的名称。
  • 启动和关闭排序。 知道接下来要创建哪个编号的宠物,以及在减小 Pet Set 大小时将销毁哪个宠物。 此功能对于诸如从宠物中排空数据之类的管理任务非常有用,当减小集群大小时。

如果你的应用程序具有这些要求中的一个或多个,那么它可能是 Pet Set 的候选对象。
一个相关的类比是,Pet Set 由宠物狗组成。 如果你有一只白色、棕色或黑色的狗,而棕色的狗跑掉了,你可以用另一只棕色的狗代替它,没有人会注意到。 如果随着时间的推移,你只能用白色的狗来代替你的狗,那么有人会注意到。 Pet Set 允许你的应用程序保持宠物的唯一身份或毛色。

Pet Set 的示例工作负载

  • 诸如 Cassandra、Zookeeper、etcd 或 Elastic 之类的集群软件需要稳定的成员资格。
  • 诸如 MySQL 或 PostgreSQL 之类的数据库,需要随时将单个实例附加到持久卷。

仅当你的应用程序需要某些或所有这些属性时才使用 Pet Set。 将 pod 作为无状态副本进行管理要容易得多。

现在回到我们的比赛!

正如我们所提到的,Cassandra 是通过 Pet Set 部署的完美候选对象。 Pet Set 很像带有几个新功能的 Replica Controller。 这是一个 YAML 清单的示例

提供 DNS 查找的无头服务

apiVersion: v1

kind: Service

metadata:

  labels:

    app: cassandra

  name: cassandra

spec:

  clusterIP: None

  ports:

    - port: 9042

  selector:

    app: cassandra-data

----

# new API name

apiVersion: "apps/v1alpha1"

kind: PetSet

metadata:

  name: cassandra

spec:

  serviceName: cassandra

  # replicas are the same as used by Replication Controllers

  # except pets are deployed in order 0, 1, 2, 3, etc

  replicas: 5

  template:

    metadata:

      annotations:

        pod.alpha.kubernetes.io/initialized: "true"

      labels:

        app: cassandra-data

    spec:

      # just as other component in Kubernetes one

      # or more containers are deployed

      containers:

      - name: cassandra

        image: "cassandra-debian:v1.1"

        imagePullPolicy: Always

        ports:

        - containerPort: 7000

          name: intra-node

        - containerPort: 7199

          name: jmx

        - containerPort: 9042

          name: cql

        resources:

          limits:

            cpu: "4"

            memory: 11Gi

          requests:

           cpu: "4"

           memory: 11Gi

        securityContext:

          privileged: true

        env:

          - name: MAX\_HEAP\_SIZE

            value: 8192M

          - name: HEAP\_NEWSIZE

            value: 2048M

          # this is relying on guaranteed network identity of Pet Sets, we

          # will know the name of the Pets / Pod before they are created

          - name: CASSANDRA\_SEEDS

            value: "cassandra-0.cassandra.default.svc.cluster.local,cassandra-1.cassandra.default.svc.cluster.local"

          - name: CASSANDRA\_CLUSTER\_NAME

            value: "OneKDemo"

          - name: CASSANDRA\_DC

            value: "DC1-Data"

          - name: CASSANDRA\_RACK

            value: "OneKDemo-Rack1-Data"

          - name: CASSANDRA\_AUTO\_BOOTSTRAP

            value: "false"

          # this variable is used by the read-probe looking

          # for the IP Address in a `nodetool status` command

          - 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 pet volumes.

        volumeMounts:

        - name: cassandra-data

          mountPath: /cassandra\_data

  # These are converted to volume claims by the controller

  # and mounted at the paths mentioned above.  Storage can be automatically

  # created for the Pets depending on the cloud environment.

  volumeClaimTemplates:

  - metadata:

      name: cassandra-data

      annotations:

        volume.alpha.kubernetes.io/storage-class: anything

    spec:

      accessModes: ["ReadWriteOnce"]

      resources:

        requests:
          storage: 380Gi

你可能会注意到这些容器的尺寸相当大,并且在生产环境中运行具有 8 个 CPU 和 16GB RAM 的 Cassandra 并不罕见。 你会在上面注意到两个主要的新功能; 动态卷配置,当然还有 Pet Set。 上面的清单将创建 5 个 Cassandra 宠物/Pod,从数字 0 开始:cassandra-data-0、cassandra-data-1 等。

为了生成比赛数据,我们使用了另一个名为 Jobs 的 Kubernetes 功能。 编写简单的 Python 代码以生成每秒比赛怪兽的随机速度。 然后将数据、位置信息、获胜者、其他数据点和指标存储在 Cassandra 中。 为了可视化数据,我们使用 JHipster 生成一个带有 Java 服务的 AngularJS UI,然后使用 D3 进行图形绘制。

一个 Job 的示例

apiVersion: batch/v1

kind: Job

metadata:

  name: pet-race-giants

  labels:

    name: pet-races

spec:

  parallelism: 2

  completions: 4

  template:

    metadata:

      name: pet-race-giants

      labels:

        name: pet-races

    spec:

      containers:

      - name: pet-race-giants

        image: py3numpy-job:v1.0

        command: ["pet-race-job", --length=100", "--pet=Giants", "--scale=3"]

        resources:

          limits:

            cpu: "2"

          requests:

            cpu: "2"

      restartPolicy: Never

File:Polyphemus.gif既然我们在谈论怪兽,就必须来个大的。我们部署了 1,009 个 minion 节点到 Google Compute Engine (GCE),分布在 4 个可用区,运行 Kubernetes 1.3 beta 的定制版本。 我们在 beta 代码上运行此演示,因为该演示是在 1.3 发布日期之前设置的。 对于 minion 节点,选择了 GCE 虚拟机 n1-standard-8 的机器大小,即具有 8 个虚拟 CPU 和 30GB 内存的虚拟机。 这将允许在单个节点上运行一个 Cassandra 实例,这对于磁盘 I/O 是推荐的。

然后部署了 pet! 总共一千个,分布在两个不同的 Cassandra 数据中心。 Cassandra 分布式架构是专门为多数据中心部署量身定制的。 通常,为了分离工作负载,在同一物理或虚拟数据中心内部署多个 Cassandra 数据中心。 数据在所有数据中心之间复制,但数据中心之间可以有不同的工作负载,因此应用程序调优也可能不同。 名为“DC1-Analytics”和“DC1-Data”的数据中心分别部署了 500 个 pet。 比赛数据由连接到 DC1-Data 的 python 批处理作业创建,而 JHipster UI 连接到 DC1-Analytics。

以下是最终的数字

  • 8,072 个核心。 master 使用了 24 个,minion 节点使用了其余的核心
  • 1,009 个 IP 地址
  • Kubernetes 在 Google Cloud Platform 上设置了 1,009 条路由
  • Minion 和 Master 使用了 100,510 GB 的持久磁盘
  • 380,020 GB 的 SSD 磁盘持久磁盘。 master 使用 20 GB,每个 Cassandra Pet 使用 340 GB。
  • 部署了 1,000 个 Cassandra 实例。是的,我们部署了 1,000 个 pet,但其中一个确实不想加入! 从技术上讲,使用 Cassandra 设置,我们可以丢失 333 个节点而不会丢失服务或数据。

1.3 版本中 Pet Sets 的限制

  • Pet Set 是一个 alpha 资源,在 1.3 之前的任何 Kubernetes 版本中都不可用。
  • 给定 pet 的存储必须由基于请求的存储类别的动态存储供应器提供,或者由管理员预先配置。
  • 删除 Pet Set 不会删除任何 pet 或 Pet 存储。 您将需要手动删除您的 Pet 及其存储(如果需要)。
  • 当前,所有 Pet Sets 都需要一个“管理服务”,或一个负责 pet 的网络身份的服务。 用户负责此服务。
  • 当前,更新现有的 Pet Set 是一个手动过程。 您要么需要使用新镜像版本部署一个新的 Pet Set,要么逐个孤立 Pet 并更新它们的镜像,这将使它们重新加入集群。

资源和参考

  • 该演示的源代码可在 GitHub 上找到:(Pet Set 示例将合并到 Kubernetes Cassandra 示例中)。
  • 有关 Jobs 的更多信息
  • Pet Set 的文档
  • 图片来源: Cassandra 图片 和 Cyclops 图片