网络研讨会系列:在Kubernetes中部署有状态服务

在本教程系列的最后一部分中,您将使用Helm(一种广受欢迎的Kubernetes开放源代码包管理器)作为StatefulSet在Kubernetes中部署高可用性MongoDB副本集。

本文补充了关于在云中部署和管理容器化工作负载网络研讨会系列 该系列涵盖容器的基本要素,包括管理容器生命周期,部署多容器应用程序,扩展工作负载以及使用Kubernetes。 它还突出显示了运行有状态应用程序的最佳实践。

本教程包括系列第5部分中的概念和命令,即在Kubernetes中部署状态服务。

介绍

Kubernetes是一款用于管理容器化应用程序的开源容器编排工具。 在本系列的前几部分中,您学习了Kubernetes和打包容器的构建块,作为Kubernetes ReplicaSets。 虽然ReplicaSets确保无状态Pod的可用性,但它们不能用于数据库集群等有状态工作负载。

虽然在Kubernetes中打包,部署,管理和扩展现代云本地应用程序可能很容易,但在容器化环境中部署和管理传统工作负载(如数据库和内容管理系统)需要采用不同的方法。 StatefulSets将Kubernetes ReplicaSet的灵活性带入有状态的工作负载。

在本教程系列的最后一部分中,您将使用Helm (一种广受欢迎的Kubernetes开放源代码包管理器)作为StatefulSet在Kubernetes中部署高可用性MongoDB副本集。

先决条件

要完成本教程,您需要:

第1步 - 在开发机器上安装Helm Client

借助Helm,管理员可以使用单个命令部署复杂的Kubernetes应用程序。 应用程序打包为定义,安装和升级Kubernetes应用程序的图表 图表提供了对Kubernetes对象(如Pods,Deployments和Services)的抽象。

Helm有两个组件 - 服务器和客户端。 Helm的服务器端作为名为Tiller的服务在Kubernetes中运行。 客户端是一个与Tiller交互的命令行工具。

由于您要部署MongoDB副本集头盔图表,因此您需要与Helm的服务器端组件Tiller交谈的CLI。 StackPointCloud,您曾用于在DigitalOcean上设置Kubernetes,预装了Tiller。

注意 :这些说明适用于macOS。 如果您正在使用其他操作系统,请参阅Helm安装指南

假设你在Mac上安装并配置了Homebrew,运行以下命令安装Helm:

brew install kubernetes-helm
==> Downloading https://homebrew.bintray.com/bottles/kubernetes-helm-2.8.2.high_sierra.bottle.tar.gz
...
==> Summary
????  /usr/local/Cellar/kubernetes-helm/2.8.2: 50 files, 121.7MB

一旦安装了Helm,请验证您是否可以通过检查其当前版本来运行它。

helm version
Client: &version.Version{SemVer:"v2.7.2", GitCommit:"8478fb4fc723885b155c924d1c8c410b7a9444e6", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.8.2", GitCommit:"a80231648a1473929271764b920a8e346f6de844", GitTreeState:"clean"}

这证实客户端已正确安装,并且能够与Tiller交谈。

在下一步中,我们将使用Helm在Kubernetes中部署MongoDB副本集。

第2步 - 在Kubernetes中部署MongoDB副本集

Kubernetes中的StorageClass为管理员提供了描述他们提供的存储“类”的方法。 例如,当用户请求存储卷时,StorageClass将确定从它们供应什么类的存储后端。 这些课程可能包括标准HDD和更快的SSD。 在幕后,StorageClass与基础架构(如云提供商的API)进行交互,以调配存储。

由于需要持久性存储来存储MongoDB数据,因此您可能需要将DigitalOcean块存储卷附加到工作节点,并指向MongoDB Pod以使用存储卷进行持久性存储。

在这种情况下,StorageClass充当Pod和DigitalOcean块存储服务之间的接口。 当您请求一个块存储卷时,StorageClass会与知道如何分配块存储卷的预配置驱动程序通信。

在安装过程中,StackPointCloud安装DigitalOcean存储驱动程序并向Kubernetes注册StorageClass。 这节省了我们从安装和配置驱动程序和StorageClass所涉及的步骤。

在我们部署MongoDB集群之前,让我们确保配置StorageClass for DigitalOcean卷:

kubectl get storageclass

输出确认StorageClass已配置并准备就绪。

[secondary_label Output
NAME                     PROVISIONER                            AGE
digitalocean (default)   digitalocean/flex-volume-provisioner   1d

接下来,您将配置并部署基于DigitalOcean StorageClass的MongoDB副本集。

为您的项目创建一个新目录并切换到新目录:

mkdir ~/mongo-rs
cd ~/mongo-rs

从GitHub克隆Helm Chart存储库:

git clone https://github.com/kubernetes/charts.git

导航到MongoDB副本集目录( charts/stable/mongodb-replicaset/ )并验证文件values.yaml存在。

cd charts/stable/mongodb-replicaset/
ls values.yaml
values.yaml

该文件包含图表的参数和配置。 您需要修改此文件以配置MongoDB副本集以使用DigitalOcean StorageClass。

编辑values.yaml

nano values.yaml

查找并取消注释以下部分:

values.yaml
...
# storageClass: "-" 
...

"-"替换为"digitalocean" ,如下所示:

values.yaml
...
storageClass: "digitalocean"
...

保存文件并退出编辑器。

现在导航到~/mongo-rs文件夹。

cd ~/mongo-rs

您现在准备将MongoDB副本集部署到您的Kubernetes集群,由DigitalOcean的块存储提供支持。 运行以下命令启动数据库集群。

helm install --name=todo -f charts/stable/mongodb-replicaset/values.yaml stable/mongodb-replicaset

在前面的命令中,--name指的是Helm图表的名称。 开关-f指向存储在values.yaml的配置设置。

您将立即看到输出确认图表创建已经开始。

NAME:   todo
LAST DEPLOYED: Sat Mar 31 10:37:06 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Service
NAME                     TYPE       CLUSTER-IP  EXTERNAL-IP  PORT(S)    AGE
todo-mongodb-replicaset  ClusterIP  None        <none>       27017/TCP  1s

==> v1beta1/StatefulSet
NAME                     DESIRED  CURRENT  AGE
todo-mongodb-replicaset  3        1        0s

==> v1/Pod(related)
NAME                       READY  STATUS    RESTARTS  AGE
todo-mongodb-replicaset-0  0/1    Init:0/2  0         0s

==> v1/ConfigMap
NAME                           DATA  AGE
todo-mongodb-replicaset        1     1s
todo-mongodb-replicaset-tests  1     1s


NOTES:
1. After the statefulset is created completely, one can check which instance is primary by running:

    $ for ((i = 0; i < 3; ++i)); do kubectl exec --namespace default todo-mongodb-replicaset-$i -- sh -c 'mongo --eval="printjson(rs.isMaster())"'; done

2. One can insert a key into the primary instance of the mongodb replica set by running the following:
    MASTER_POD_NAME must be replaced with the name of the master found from the previous step.

    $ kubectl exec --namespace default MASTER_POD_NAME -- mongo --eval="printjson(db.test.insert({key1: 'value1'}))"

3. One can fetch the keys stored in the primary or any of the slave nodes in the following manner.
    POD_NAME must be replaced by the name of the pod being queried.

    $ kubectl exec --namespace default POD_NAME -- mongo --eval="rs.slaveOk(); db.test.find().forEach(printjson)"

现在让我们运行一系列命令来跟踪集群的状态。

首先,看看StatefulSet:

kubectl get statefulset

此命令确认MongoDB副本集是作为Kubernetes StatefulSet创建的。

NAME                      DESIRED   CURRENT   AGE
todo-mongodb-replicaset   3         2         2m

现在探索Pods:

kubectl get pods

Pod的数量及其命名约定表明MongoDB副本集已成功配置:

NAME                        READY     STATUS        RESTARTS   AGE
todo-mongodb-replicaset-0   1/1       Running       0          3m
todo-mongodb-replicaset-1   1/1       Running       0          1m
todo-mongodb-replicaset-2   1/1       Running       0          54s

请注意,每个Pod都有一个以序号结尾的Postfix,这是StatefulSet的一个独特功能。

现在让我们来看看MongoDB实例是否正在相互通信。 我们将通过在其中一个Pod中的MongoDB shell中运行命令来完成此操作。

使用kubectl在其中一台主机上启动mongo控制台:

kubectl exec -it todo-mongodb-replicaset-0 mongo

连接之后,您会发现自己在MongoDB外壳中:

MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
Welcome to the MongoDB shell.
For interactive help, type "help".
...

2018-03-31T05:08:20.239+0000 I CONTROL  [initandlisten]

使用以下命令检查副本集的配置:

rs.conf()

输出确认有三个作为副本集运行的MongoDB实例。

{
    "_id" : "rs0",
    "version" : 3,
    "protocolVersion" : NumberLong(1),
    "members" : [
        {
            "_id" : 0,
            "host" : "todo-mongodb-replicaset-0.todo-mongodb-replicaset.default.svc.cluster.local:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {

            },
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 1,
            "host" : "todo-mongodb-replicaset-1.todo-mongodb-replicaset.default.svc.cluster.local:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {

            },
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 2,
            "host" : "todo-mongodb-replicaset-2.todo-mongodb-replicaset.default.svc.cluster.local:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {

            },
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }
    ],
    "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : -1,
        "catchUpTakeoverDelayMillis" : 30000,
        "getLastErrorModes" : {

        },
        "getLastErrorDefaults" : {
            "w" : 1,
            "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("5abdb4f61d952afc4b0b8218")
    }
}

退出MongoDB控制台:

exit

这也会使您与远程主机断开连接。

让我们切换齿轮并检查DigitalOcean控制面板以查找与群集关联的块存储卷。 登录到DigitalOcean帐户并选择标签:

显示卷的仪表板

您可以看到三个10GB的卷分别连接到Kubernetes工作节点。 MongoDB StatefulSet的每个Pod都将数据存储在一个块存储卷中。 10GB的大小在persistentVolume部分下的values.yaml定义。

values.yaml
persistentVolume:
  enabled: true
  ## mongodb-replicaset data Persistent Volume Storage Class
  ## If defined, storageClassName: <storageClass>
  ## If set to "-", storageClassName: "", which disables dynamic provisioning
  ## If undefined (the default) or set to null, no storageClassName spec is
  ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
  ##   GKE, AWS & OpenStack)
  ##
  storageClass: digitalocean
  accessModes:
    - ReadWriteOnce
  size: 10Gi
  annotations: {}

您已经成功配置了在Kubernetes中运行的高可用性MongoDB ReplicaSet。

现在让我们部署与MongoDB集群交谈的Web应用程序。

第3步 - 在Kubernetes中部署和扩展Web应用程序

让我们扩展本教程系列前面部分中使用的ToDo Node.js应用程序,以利用MongoDB集群。

注意 :您也可以从源代码构建容器图像,或者直接在Kubernetes文件中使用YAML文件。 有关构建映像和将应用程序部署到Kubernetes的步骤,请参阅教程在Kubernetes中部署和缩放微服务。

首先创建一个新的工作目录:

mkdir ~/web-app
cd ~/web-app

然后克隆包含代码和Kubernetes构件的ToDo应用程序的存储库。

git clone https://github.com/janakiramm/todo.git

切换到包含Kubernetes配置文件的todo-app/kubernetes目录。

cd todo-app/kubernetes

在您的编辑器中打开文件web-rs-ss.yaml

nano web-rs-ss.yaml

注意YAML文件中的env部分。

网络RS-ss.yaml
      containers:
      - name: web 
        image: janakiramm/todo
        env:
          - name: "DBHOST"
            value: "mongodb://todo-mongodb-replicaset-0.todo-mongodb-replicaset,todo-mongodb-replicaset-1.todo-mongodb-replicaset,todo-mongodb-replicaset-2.todo-mongodb-replicaset:27017"
        ports:
        - containerPort: 3000

这将数据库连接字符串作为环境变量在运行时传递给应用程序。 这个版本的应用程序使用您创建的StatefulSet,而不是将应用程序指向简单的MongoDB Pod。 value部分中的每个条目都指向MongoDB StatefulSet的其中一个Pod。

使用kubectlweb ReplicaSet与web Service一起部署

kubectl create -f web-rs-ss.yaml -f web-service.yaml

你会看到两者都被创建:

replicaset "web" created
service "web" created

再次列出豆荚:

kubectl get pods

您现在可以看到属于MongoDB的所有Pod和Web应用程序。

NAME                        READY     STATUS    RESTARTS   AGE
todo-mongodb-replicaset-0   1/1       Running   0          26m
todo-mongodb-replicaset-1   1/1       Running   0          24m
todo-mongodb-replicaset-2   1/1       Running   0          23m
web-t5zzk                   1/1       Running   0          17s
web-x6dh8                   1/1       Running   0          17s

Let’s check out the Kubernetes services

​```command
kubectl get svc
NAME                      TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE
kubernetes                ClusterIP   10.3.0.1     <none>        443/TCP          1d
todo-mongodb-replicaset   ClusterIP   None         <none>        27017/TCP        27m
web                       NodePort    10.3.0.167   <none>        3000:31201/TCP   14s

web Pod通过todo-mongodb-replicaset Service与MongoDB集群进行通信。 Web应用程序可通过NodePort 31201上的web Service 31201

在任何工作节点上访问此端口都会显示Web应用程序。

现场Todo列表应用程序

您可以通过增加副本集中的窗格数来扩展Web应用程序。

kubectl scale rs/web --replicas=10
replicaset "web" scaled

然后,您可以将应用程序缩放到两个Pod。

kubectl scale rs/web --replicas=2
replicaset "web" scaled

现在让我们运行一些测试的可用性。

第4步 - 测试MongoDB副本集的高可用性

运行StatefulSet的优点之一是工作负载的高可用性。 让我们通过删除MongoDB StatefulSet中的一个Pod来测试它。

kubectl delete pod todo-mongodb-replicaset-2
pod "todo-mongodb-replicaset-2" deleted

检查豆荚的数量:

kubectl get pods

你会看到todo-mongodb-replicaset-2正在终止:

NAME                        READY     STATUS        RESTARTS   AGE
todo-mongodb-replicaset-0   1/1       Running       0          33m
todo-mongodb-replicaset-1   1/1       Running       0          32m
todo-mongodb-replicaset-2   0/1       Terminating   0          31m
web-t5zzk                   1/1       Running       0          8m
web-x6dh8                   1/1       Running       0          8m

在几分钟内,你会看到Kubernetes初始化另一个Pod以替换已删除的Pod。

kubectl get pods

你会看到todo-mongodb-replicaset-2正在初始化:

NAME                        READY     STATUS     RESTARTS   AGE
todo-mongodb-replicaset-0   1/1       Running    0          34m
todo-mongodb-replicaset-1   1/1       Running    0          33m
todo-mongodb-replicaset-2   0/1       Init:0/2   0          29s
web-t5zzk                   1/1       Running    0          8m
web-x6dh8                   1/1       Running    0          8m

既然你知道一切正常,你可以清理干净。

使用以下命令删除在本教程中创建的所有对象:

helm delete --purge todo
kubectl delete -f web-rs-ss.yaml -f web-service.yaml
replicaset "web" deleted
service "web" deleted

要删除Kubernetes集群本身,请访问StackPointCloud并通过他们的控制面板进行操作。

结论

在本教程中,您将持久,持久,高度可用的MonogDB ReplicaSet部署为Kubernetes StatefulSet。 您还学习了如何从部署在同一个Kubernetes集群中的其他应用程序访问StatefulSet。


分享按钮