本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

使用 Kubernetes Pet Set 實現千個 Cassandra 例項

編者按:這篇博文是關於 Kubernetes 1.3 新特性的系列深度文章之一

執行希臘神獸競賽

為了Kubernetes 1.3 釋出,我們想對新的 Pet Set 進行一番測試。透過測試上千個 Cassandra 例項,我們可以確保 Kubernetes 1.3 已為生產做好準備。請繼續閱讀,瞭解我們如何將 Cassandra 適配到 Kubernetes,並進行了有史以來最大規模的部署。

如今,將容器與基本有狀態應用程式一起使用相當簡單。使用持久卷,您可以在 Pod 中掛載磁碟,並確保您的資料在 Pod 生命週期結束後仍然存在。然而,對於分散式有狀態應用程式的部署,事情可能會變得更加棘手。透過 Kubernetes 1.3,新的 Pet Set 元件讓一切變得容易得多。為了大規模測試這項新功能,我們決定舉辦希臘神獸競賽!我們在數百個可用區內進行了數十萬場比賽,賽馬和許多其他古希臘怪物參加了比賽。

File:Cassandra1.jpeg
眾所周知,Kubernetes 一詞源於古希臘語:κυβερνήτης。這意味著舵手、領航員、船長或船主。因此,為了記錄比賽結果,我們需要一個數據儲存,我們選擇了 Cassandra。Κασσάνδρα,卡桑德拉,她是特洛伊國王普里阿摩斯和赫卡柏女王的女兒。鑑於多次提及古希臘語,我們認為舉辦古希臘怪物比賽是合適的。

從那時起,故事就有點偏離了,因為卡桑德拉實際上也是 Pet。請繼續閱讀,我們將進行解釋。

Kubernetes 1.3 中一項令人興奮的新功能是 Pet Set。為了組織 Kubernetes 內部容器的部署,提供了不同的部署機制。這些元件的例子包括 Resource Controller 和 Daemon Set。Pet Sets 是一項新功能,它提供了在 Kubernetes 內部部署容器作為 Pet 的能力。Pet Sets 保證了 Pet/Pod 部署的各個方面的身份:DNS 名稱、一致儲存和有序的 Pod 索引。以前,使用 Deployment 和 Replication Controller 等元件,只會部署一個具有弱解耦身份的應用程式。弱身份非常適合管理微服務等應用程式,在這種情況下,服務發現很重要,應用程式是無狀態的,並且單個 Pod 的命名無關緊要。許多軟體應用程式確實需要強身份,包括許多不同型別的分散式有狀態系統。Cassandra 是一個需要一致網路身份和穩定儲存的分散式應用程式的絕佳例子。

Pet Sets 提供以下功能

  • 一個穩定的主機名,可在 DNS 中供他人使用。編號基於 Pet Set 名稱,從零開始。例如 cassandra-0。
  • Pet 的序數索引。0、1、2、3 等。
  • 與 Pet 的序數和主機名相關聯的穩定儲存。
  • 透過 DNS 可以進行對等發現。對於 Cassandra,在建立 Pet 之前就知道對等體的名稱。
  • 啟動和拆除順序。知道下一個要建立的 Pet 的編號,以及在縮小 Pet Set 大小時將被銷燬的 Pet。此功能對於在縮小叢集大小時,從 Pet 中排出資料等管理任務非常有用。

如果您的應用程式具有其中一項或多項要求,則它可能是 Pet Set 的候選者。
一個相關的類比是,一個 Pet Set 由寵物狗組成。如果您有一隻白色、棕色或黑色的狗,而棕色的狗跑掉了,您可以換一隻棕色的狗,沒有人會注意到。如果隨著時間的推移,您只用白色的狗來替換您的狗,那麼有人就會注意到。Pet Set 允許您的應用程式保持 Pet 獨特的身份或毛色。

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 記憶體的 Cassandra 並不罕見。您會注意到上面有兩個關鍵的新功能:動態卷配置,當然還有 Pet Set。上面的清單將建立 5 個 Cassandra Pet/Pod,從數字 0 開始:cassandra-data-0、cassandra-data-1 等。

為了生成比賽資料,我們使用了 Kubernetes 的另一個功能,稱為 Jobs。編寫了簡單的 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既然我們談論的是怪物,就必須做得更大。我們向 Google Compute Engine (GCE) 部署了 1,009 個 Minion 節點,分佈在 4 個區域,執行自定義版本的 Kubernetes 1.3 beta。我們在 beta 程式碼上執行這個演示,因為演示是在 1.3 釋出日期之前設定的。對於 Minion 節點,選擇了 GCE 虛擬機器 n1-standard-8 機器尺寸,即具有 8 個虛擬 CPU 和 30GB 記憶體的虛擬機器。它允許在一個節點上執行單個 Cassandra 例項,這對於磁碟 I/O 是推薦的。

然後部署了 Pet!一千個 Pet,分佈在兩個不同的 Cassandra 資料中心。Cassandra 分散式架構是專門為多資料中心部署量身定製的。通常,為了分離工作負載,多個 Cassandra 資料中心部署在相同的物理或虛擬資料中心內。資料在所有資料中心之間複製,但資料中心之間工作負載可能不同,因此應用程式調優也可能不同。名為“DC1-Analytics”和“DC1-Data”的資料中心各部署了 500 個 Pet。比賽資料由連線到 DC1-Data 的 Python Batch Jobs 建立,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 Set 的限制

  • Pet Set 是一個 alpha 資源,在 Kubernetes 1.3 之前的任何版本中都不可用。
  • 給定 Pet 的儲存必須由基於所請求儲存類的動態儲存提供程式進行配置,或由管理員預先配置。
  • 刪除 Pet Set 不會刪除任何 Pet 或 Pet 儲存。您需要手動刪除您的 Pet 及其儲存。
  • 所有 Pet Set 目前都需要一個“管理服務”,即負責 Pet 網路身份的服務。使用者負責此服務。
  • 更新現有 Pet Set 目前是一個手動過程。您要麼需要部署一個具有新映象版本的新 Pet Set,要麼逐個孤立 Pet 並更新其映象,然後將其重新加入叢集。

資源和參考資料

  • 演示的原始碼可在 GitHub 上獲取:(Pet Set 示例將合併到 Kubernetes Cassandra 示例中)。
  • 有關 Jobs 的更多資訊
  • Pet Set 的文件
  • 圖片來源:Cassandra 圖片 和 Cyclops 圖片