--- sidebar_label: Kubernetes title: 在 Kubernetes 上部署 TDengine 集群 description: 利用 Kubernetes 部署 TDengine 集群的详细指南 --- ## 概述 作为面向云原生架构设计的时序数据库,TDengine 本身就支持 Kubernetes 部署。这里介绍如何使用 YAML 文件从头一步一步创建一个可用于生产使用的高可用 TDengine 集群,并重点介绍 Kubernetes 环境下 TDengine 的常用操作。 为了满足[高可用](https://docs.taosdata.com/tdinternal/high-availability/)的需求,集群需要满足如下要求: - 3个及以上 dnode :TDengine 的同一个 vgroup 中的多个 vnode ,不允许同时分布在一个 dnode ,所以如果创建3副本的数据库,则 dnode 数大于等于3 - 3个 mnode :mnode 负责整个集群的管理工作,TDengine 默认是一个 mnode。如果这个 mnode 所在的 dnode 掉线,则整个集群不可用。 - 数据库的3副本:TDengine 的副本配置是数据库级别,所以数据库3副本可满足在3个 dnode 的集群中,任意一个 dnode 下线,都不影响集群的正常使用。**如果下线** **dnode** **个数为2时,此时集群不可用,****因为****RAFT无法完成选举****。**(企业版:在灾难恢复场景,任一节点数据文件损坏,都可以通过重新拉起dnode进行恢复) ## 前置条件 要使用 Kubernetes 部署管理 TDengine 集群,需要做好如下准备工作。 - 本文适用 Kubernetes v1.19 以上版本 - 本文使用 kubectl 工具进行安装部署,请提前安装好相应软件 - Kubernetes 已经安装部署并能正常访问使用或更新必要的容器仓库或其他服务 以下配置文件也可以从 [GitHub 仓库](https://github.com/taosdata/TDengine-Operator/tree/3.0/src/tdengine) 下载。 ## 配置 Service 服务 创建一个 Service 配置文件:`taosd-service.yaml`,服务名称 `metadata.name` (此处为 "taosd") 将在下一步中使用到。首先添加 TDengine 所用到的端口,然后在选择器设置确定的标签 app (此处为 “tdengine”)。 ```YAML --- apiVersion: v1 kind: Service metadata: name: "taosd" labels: app: "tdengine" spec: ports: - name: tcp6030 protocol: "TCP" port: 6030 - name: tcp6041 protocol: "TCP" port: 6041 selector: app: "tdengine" ``` ## 有状态服务 StatefulSet 根据 Kubernetes 对各类部署的说明,我们将使用 StatefulSet 作为 TDengine 的部署资源类型。 创建文件 `tdengine.yaml`,其中 replicas 定义集群节点的数量为 3。节点时区为中国(Asia/Shanghai),每个节点分配 5G 标准(standard)存储(参考[Storage Classes](https://kubernetes.io/docs/concepts/storage/storage-classes/) 配置 storage class )。你也可以根据实际情况进行相应修改。 请特别注意startupProbe的配置,在 dnode 的 Pod 掉线一段时间后,再重新启动,这个时候新上线的 dnode 会短暂不可用。如果startupProbe配置过小,Kubernetes 会认为该 Pod 处于不正常的状态,并尝试重启该 Pod,该 dnode 的 Pod 会频繁重启,始终无法恢复到正常状态。参考 [Configure Liveness, Readiness and Startup Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) ```YAML --- apiVersion: apps/v1 kind: StatefulSet metadata: name: "tdengine" labels: app: "tdengine" spec: serviceName: "taosd" replicas: 3 updateStrategy: type: RollingUpdate selector: matchLabels: app: "tdengine" template: metadata: name: "tdengine" labels: app: "tdengine" spec: containers: - name: "tdengine" image: "tdengine/tdengine:3.0.7.1" imagePullPolicy: "IfNotPresent" ports: - name: tcp6030 protocol: "TCP" containerPort: 6030 - name: tcp6041 protocol: "TCP" containerPort: 6041 env: # POD_NAME for FQDN config - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name # SERVICE_NAME and NAMESPACE for fqdn resolve - name: SERVICE_NAME value: "taosd" - name: STS_NAME value: "tdengine" - name: STS_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace # TZ for timezone settings, we recommend to always set it. - name: TZ value: "Asia/Shanghai" # TAOS_ prefix will configured in taos.cfg, strip prefix and camelCase. - name: TAOS_SERVER_PORT value: "6030" # Must set if you want a cluster. - name: TAOS_FIRST_EP value: "$(STS_NAME)-0.$(SERVICE_NAME).$(STS_NAMESPACE).svc.cluster.local:$(TAOS_SERVER_PORT)" # TAOS_FQND should always be set in k8s env. - name: TAOS_FQDN value: "$(POD_NAME).$(SERVICE_NAME).$(STS_NAMESPACE).svc.cluster.local" volumeMounts: - name: taosdata mountPath: /var/lib/taos startupProbe: exec: command: - taos-check failureThreshold: 360 periodSeconds: 10 readinessProbe: exec: command: - taos-check initialDelaySeconds: 5 timeoutSeconds: 5000 livenessProbe: exec: command: - taos-check initialDelaySeconds: 15 periodSeconds: 20 volumeClaimTemplates: - metadata: name: taosdata spec: accessModes: - "ReadWriteOnce" storageClassName: "standard" resources: requests: storage: "5Gi" ``` ## 使用 kubectl 命令部署 TDengine 集群 首先创建对应的 namespace,然后顺序执行以下命令: ```Bash kubectl apply -f taosd-service.yaml -n tdengine-test kubectl apply -f tdengine.yaml -n tdengine-test ``` 上面的配置将生成一个三节点的 TDengine 集群,dnode 为自动配置,可以使用 show dnodes 命令查看当前集群的节点: ```Bash kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "show dnodes" kubectl exec -it tdengine-1 -n tdengine-test -- taos -s "show dnodes" kubectl exec -it tdengine-2 -n tdengine-test -- taos -s "show dnodes" ``` 输出如下: ```Bash taos> show dnodes id | endpoint | vnodes | support_vnodes | status | create_time | reboot_time | note | active_code | c_active_code | ============================================================================================================================================================================================================================================= 1 | tdengine-0.ta... | 0 | 16 | ready | 2023-07-19 17:54:18.552 | 2023-07-19 17:54:18.469 | | | | 2 | tdengine-1.ta... | 0 | 16 | ready | 2023-07-19 17:54:37.828 | 2023-07-19 17:54:38.698 | | | | 3 | tdengine-2.ta... | 0 | 16 | ready | 2023-07-19 17:55:01.141 | 2023-07-19 17:55:02.039 | | | | Query OK, 3 row(s) in set (0.001853s) ``` 查看当前mnode ```Bash kubectl exec -it tdengine-1 -n tdengine-test -- taos -s "show mnodes\G" taos> show mnodes\G *************************** 1.row *************************** id: 1 endpoint: tdengine-0.taosd.tdengine-test.svc.cluster.local:6030 role: leader status: ready create_time: 2023-07-19 17:54:18.559 reboot_time: 2023-07-19 17:54:19.520 Query OK, 1 row(s) in set (0.001282s) ``` ## 创建mnode ```Bash kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "create mnode on dnode 2" kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "create mnode on dnode 3" ``` 查看mnode ```Bash kubectl exec -it tdengine-1 -n tdengine-test -- taos -s "show mnodes\G" taos> show mnodes\G *************************** 1.row *************************** id: 1 endpoint: tdengine-0.taosd.tdengine-test.svc.cluster.local:6030 role: leader status: ready create_time: 2023-07-19 17:54:18.559 reboot_time: 2023-07-20 09:19:36.060 *************************** 2.row *************************** id: 2 endpoint: tdengine-1.taosd.tdengine-test.svc.cluster.local:6030 role: follower status: ready create_time: 2023-07-20 09:22:05.600 reboot_time: 2023-07-20 09:22:12.838 *************************** 3.row *************************** id: 3 endpoint: tdengine-2.taosd.tdengine-test.svc.cluster.local:6030 role: follower status: ready create_time: 2023-07-20 09:22:20.042 reboot_time: 2023-07-20 09:22:23.271 Query OK, 3 row(s) in set (0.003108s) ``` ## 使能端口转发 利用 kubectl 端口转发功能可以使应用可以访问 Kubernetes 环境运行的 TDengine 集群。 ```Plain kubectl port-forward -n tdengine-test tdengine-0 6041:6041 & ``` 使用 curl 命令验证 TDengine REST API 使用的 6041 接口。 ```Plain curl -u root:taosdata -d "show databases" 127.0.0.1:6041/rest/sql {"code":0,"column_meta":[["name","VARCHAR",64]],"data":[["information_schema"],["performance_schema"],["test"],["test1"]],"rows":4} ``` ## 集群测试 ### 数据准备 #### taosBenchmark 通过taosBenchmark 创建一个3副本的数据库,同时写入1亿条数据,同时查看数据 ```Bash kubectl exec -it tdengine-0 -n tdengine-test -- taosBenchmark -I stmt -d test -n 10000 -t 10000 -a 3 # query data kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "select count(*) from test.meters;" taos> select count(*) from test.meters; count(*) | ======================== 100000000 | Query OK, 1 row(s) in set (0.103537s) ``` 查看vnode分布,通过show dnodes ```Bash kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "show dnodes" taos> show dnodes id | endpoint | vnodes | support_vnodes | status | create_time | reboot_time | note | active_code | c_active_code | ============================================================================================================================================================================================================================================= 1 | tdengine-0.ta... | 8 | 16 | ready | 2023-07-19 17:54:18.552 | 2023-07-19 17:54:18.469 | | | | 2 | tdengine-1.ta... | 8 | 16 | ready | 2023-07-19 17:54:37.828 | 2023-07-19 17:54:38.698 | | | | 3 | tdengine-2.ta... | 8 | 16 | ready | 2023-07-19 17:55:01.141 | 2023-07-19 17:55:02.039 | | | | Query OK, 3 row(s) in set (0.001357s) ``` 通过show vgroup 查看 vnode 分布情况 ```Bash kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "show test.vgroups" taos> show test.vgroups vgroup_id | db_name | tables | v1_dnode | v1_status | v2_dnode | v2_status | v3_dnode | v3_status | v4_dnode | v4_status | cacheload | cacheelements | tsma | ============================================================================================================================================================================================== 2 | test | 1267 | 1 | follower | 2 | follower | 3 | leader | NULL | NULL | 0 | 0 | 0 | 3 | test | 1215 | 1 | follower | 2 | leader | 3 | follower | NULL | NULL | 0 | 0 | 0 | 4 | test | 1215 | 1 | leader | 2 | follower | 3 | follower | NULL | NULL | 0 | 0 | 0 | 5 | test | 1307 | 1 | follower | 2 | leader | 3 | follower | NULL | NULL | 0 | 0 | 0 | 6 | test | 1245 | 1 | follower | 2 | follower | 3 | leader | NULL | NULL | 0 | 0 | 0 | 7 | test | 1275 | 1 | follower | 2 | leader | 3 | follower | NULL | NULL | 0 | 0 | 0 | 8 | test | 1231 | 1 | leader | 2 | follower | 3 | follower | NULL | NULL | 0 | 0 | 0 | 9 | test | 1245 | 1 | follower | 2 | follower | 3 | leader | NULL | NULL | 0 | 0 | 0 | Query OK, 8 row(s) in set (0.001488s) ``` #### 手工创建 常见一个三副本的test1,并创建一张表,写入2条数据 ```Bash kubectl exec -it tdengine-0 -n tdengine-test -- \ taos -s \ "create database if not exists test1 replica 3; use test1; create table if not exists t1(ts timestamp, n int); insert into t1 values(now, 1)(now+1s, 2);" ``` 通过show test1.vgroup 查看xnode分布情况 ```Bash kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "show test1.vgroups" taos> show test1.vgroups vgroup_id | db_name | tables | v1_dnode | v1_status | v2_dnode | v2_status | v3_dnode | v3_status | v4_dnode | v4_status | cacheload | cacheelements | tsma | ============================================================================================================================================================================================== 10 | test1 | 1 | 1 | follower | 2 | follower | 3 | leader | NULL | NULL | 0 | 0 | 0 | 11 | test1 | 0 | 1 | follower | 2 | leader | 3 | follower | NULL | NULL | 0 | 0 | 0 | Query OK, 2 row(s) in set (0.001489s) ``` ### 容错测试 Mnode leader 所在的 dnode 掉线,dnode1 ```Bash kubectl get pod -l app=tdengine -n tdengine-test -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES tdengine-0 0/1 ErrImagePull 2 (2s ago) 20m 10.244.2.75 node86 tdengine-1 1/1 Running 1 (6m48s ago) 20m 10.244.0.59 node84 tdengine-2 1/1 Running 0 21m 10.244.1.223 node85 ``` 此时集群mnode发生重新选举,dnode1上的monde 成为leader ```Bash kubectl exec -it tdengine-1 -n tdengine-test -- taos -s "show mnodes\G" Welcome to the TDengine Command Line Interface, Client Version:3.0.7.1.202307190706 Copyright (c) 2022 by TDengine, all rights reserved. taos> show mnodes\G *************************** 1.row *************************** id: 1 endpoint: tdengine-0.taosd.tdengine-test.svc.cluster.local:6030 role: offline status: offline create_time: 2023-07-19 17:54:18.559 reboot_time: 1970-01-01 08:00:00.000 *************************** 2.row *************************** id: 2 endpoint: tdengine-1.taosd.tdengine-test.svc.cluster.local:6030 role: leader status: ready create_time: 2023-07-20 09:22:05.600 reboot_time: 2023-07-20 09:32:00.227 *************************** 3.row *************************** id: 3 endpoint: tdengine-2.taosd.tdengine-test.svc.cluster.local:6030 role: follower status: ready create_time: 2023-07-20 09:22:20.042 reboot_time: 2023-07-20 09:32:00.026 Query OK, 3 row(s) in set (0.001513s) ``` 集群可以正常读写 ```Bash # insert kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "insert into test1.t1 values(now, 1)(now+1s, 2);" taos> insert into test1.t1 values(now, 1)(now+1s, 2); Insert OK, 2 row(s) affected (0.002098s) # select kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "select *from test1.t1" taos> select *from test1.t1 ts | n | ======================================== 2023-07-19 18:04:58.104 | 1 | 2023-07-19 18:04:59.104 | 2 | 2023-07-19 18:06:00.303 | 1 | 2023-07-19 18:06:01.303 | 2 | Query OK, 4 row(s) in set (0.001994s) ``` 同理,至于非leader得mnode掉线,读写当然可以正常进行,这里就不做过多的展示。 ## 集群扩容 TDengine 集群支持自动扩容: ```Bash kubectl scale statefulsets tdengine --replicas=4 ``` 上面命令行中参数 `--replica=4` 表示要将 TDengine 集群扩容到 4 个节点,执行后首先检查 POD 的状态: ```Bash kubectl get pod -l app=tdengine -n tdengine-test -o wide ``` 输出如下: ```Plain NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES tdengine-0 1/1 Running 4 (6h26m ago) 6h53m 10.244.2.75 node86 tdengine-1 1/1 Running 1 (6h39m ago) 6h53m 10.244.0.59 node84 tdengine-2 1/1 Running 0 5h16m 10.244.1.224 node85 tdengine-3 1/1 Running 0 3m24s 10.244.2.76 node86 ``` 此时 Pod 的状态仍然是 Running,TDengine 集群中的 dnode 状态要等 Pod 状态为 `ready` 之后才能看到: ```Bash kubectl exec -it tdengine-3 -n tdengine-test -- taos -s "show dnodes" ``` 扩容后的四节点 TDengine 集群的 dnode 列表: ```Plain taos> show dnodes id | endpoint | vnodes | support_vnodes | status | create_time | reboot_time | note | active_code | c_active_code | ============================================================================================================================================================================================================================================= 1 | tdengine-0.ta... | 10 | 16 | ready | 2023-07-19 17:54:18.552 | 2023-07-20 09:39:04.297 | | | | 2 | tdengine-1.ta... | 10 | 16 | ready | 2023-07-19 17:54:37.828 | 2023-07-20 09:28:24.240 | | | | 3 | tdengine-2.ta... | 10 | 16 | ready | 2023-07-19 17:55:01.141 | 2023-07-20 10:48:43.445 | | | | 4 | tdengine-3.ta... | 0 | 16 | ready | 2023-07-20 16:01:44.007 | 2023-07-20 16:01:44.889 | | | | Query OK, 4 row(s) in set (0.003628s) ``` ## 集群缩容 由于 TDengine 集群在扩缩容时会对数据进行节点间迁移,使用 kubectl 命令进行缩容需要首先使用 "drop dnodes" 命令(**如果集群中存在3副本的db,那么缩容后的** **dnode** **个数也要必须大于等于3,否则drop dnode操作会被中止**),然后再节点删除完成后再进行 Kubernetes 集群缩容。 注意:由于 Kubernetes Statefulset 中 Pod 的只能按创建顺序逆序移除,所以 TDengine drop dnode 也需要按照创建顺序逆序移除,否则会导致 Pod 处于错误状态。 ```Bash kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "drop dnode 4" kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "show dnodes" taos> show dnodes id | endpoint | vnodes | support_vnodes | status | create_time | reboot_time | note | active_code | c_active_code | ============================================================================================================================================================================================================================================= 1 | tdengine-0.ta... | 10 | 16 | ready | 2023-07-19 17:54:18.552 | 2023-07-20 09:39:04.297 | | | | 2 | tdengine-1.ta... | 10 | 16 | ready | 2023-07-19 17:54:37.828 | 2023-07-20 09:28:24.240 | | | | 3 | tdengine-2.ta... | 10 | 16 | ready | 2023-07-19 17:55:01.141 | 2023-07-20 10:48:43.445 | | | | Query OK, 3 row(s) in set (0.003324s) ``` 确认移除成功后(使用 kubectl exec -i -t tdengine-0 -- taos -s "show dnodes" 查看和确认 dnode 列表),使用 kubectl 命令移除 POD: ```Plain kubectl scale statefulsets tdengine --replicas=3 -n tdengine-test ``` 最后一个 POD 将会被删除。使用命令 kubectl get pods -l app=tdengine 查看POD状态: ```Plain kubectl get pod -l app=tdengine -n tdengine-test -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES tdengine-0 1/1 Running 4 (6h55m ago) 7h22m 10.244.2.75 node86 tdengine-1 1/1 Running 1 (7h9m ago) 7h23m 10.244.0.59 node84 tdengine-2 1/1 Running 0 5h45m 10.244.1.224 node85 ``` POD删除后,需要手动删除PVC,否则下次扩容时会继续使用以前的数据导致无法正常加入集群。 ```Bash kubectl delete pvc aosdata-tdengine-3 -n tdengine-test ``` 此时的集群状态是安全的,需要时还可以再次进行扩容: ```Bash kubectl scale statefulsets tdengine --replicas=4 -n tdengine-test statefulset.apps/tdengine scaled kubectl get pod -l app=tdengine -n tdengine-test -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES tdengine-0 1/1 Running 4 (6h59m ago) 7h27m 10.244.2.75 node86 tdengine-1 1/1 Running 1 (7h13m ago) 7h27m 10.244.0.59 node84 tdengine-2 1/1 Running 0 5h49m 10.244.1.224 node85 tdengine-3 1/1 Running 0 20s 10.244.2.77 node86 kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "show dnodes" taos> show dnodes id | endpoint | vnodes | support_vnodes | status | create_time | reboot_time | note | active_code | c_active_code | ============================================================================================================================================================================================================================================= 1 | tdengine-0.ta... | 10 | 16 | ready | 2023-07-19 17:54:18.552 | 2023-07-20 09:39:04.297 | | | | 2 | tdengine-1.ta... | 10 | 16 | ready | 2023-07-19 17:54:37.828 | 2023-07-20 09:28:24.240 | | | | 3 | tdengine-2.ta... | 10 | 16 | ready | 2023-07-19 17:55:01.141 | 2023-07-20 10:48:43.445 | | | | 5 | tdengine-3.ta... | 0 | 16 | ready | 2023-07-20 16:31:34.092 | 2023-07-20 16:38:17.419 | | | | Query OK, 4 row(s) in set (0.003881s) ``` ## 清理 TDengine 集群 > **删除pvc时需要注意下pv persistentVolumeReclaimPolicy策略,建议改为Delete,这样在删除pvc时才会自动清理pv,同时会清理底层的csi存储资源,如果没有配置删除pvc自动清理pv的策略,再删除pvc后,在手动清理pv时,pv对应的csi存储资源可能不会被释放。** 完整移除 TDengine 集群,需要分别清理 statefulset、svc、configmap、pvc。 ```Bash kubectl delete statefulset -l app=tdengine -n tdengine-test kubectl delete svc -l app=tdengine -n tdengine-test kubectl delete pvc -l app=tdengine -n tdengine-test kubectl delete configmap taoscfg -n tdengine-test ``` ## 常见错误 ### 错误一 未进行 "drop dnode" 直接进行缩容,由于 TDengine 尚未删除节点,缩容 pod 导致 TDengine 集群中部分节点处于 offline 状态。 ```Plain kubectl exec -it tdengine-0 -n tdengine-test -- taos -s "show dnodes" taos> show dnodes id | endpoint | vnodes | support_vnodes | status | create_time | reboot_time | note | active_code | c_active_code | ============================================================================================================================================================================================================================================= 1 | tdengine-0.ta... | 10 | 16 | ready | 2023-07-19 17:54:18.552 | 2023-07-20 09:39:04.297 | | | | 2 | tdengine-1.ta... | 10 | 16 | ready | 2023-07-19 17:54:37.828 | 2023-07-20 09:28:24.240 | | | | 3 | tdengine-2.ta... | 10 | 16 | ready | 2023-07-19 17:55:01.141 | 2023-07-20 10:48:43.445 | | | | 5 | tdengine-3.ta... | 0 | 16 | offline | 2023-07-20 16:31:34.092 | 2023-07-20 16:38:17.419 | status msg timeout | | | Query OK, 4 row(s) in set (0.003862s) ``` ## 最后 对于在 Kubernetes 环境下 TDengine 的高可用和高可靠来说,对于硬件损坏、灾难恢复,分为两个层面来讲: 1. 底层的分布式块存储具备的灾难恢复能力,块存储的多副本,当下流行的分布式块存储如 Ceph,就具备多副本能力,将存储副本扩展到不同的机架、机柜、机房、数据中心(或者直接使用公有云厂商提供的块存储服务) 2. TDengine的灾难恢复,在 TDengine Enterprise 中,本身具备了当一个 dnode 永久下线(物理机磁盘损坏,数据分拣丢失)后,重新拉起一个空白的dnode来恢复原dnode的工作。 最后,欢迎使用[TDengine Cloud](https://cloud.taosdata.com/),来体验一站式全托管的TDengine云服务。 > TDengine Cloud 是一个极简的全托管时序数据处理云服务平台,它是基于开源的时序数据库 TDengine 而开发的。除高性能的时序数据库之外,它还具有缓存、订阅和流计算等系统功能,而且提供了便利而又安全的数据分享、以及众多的企业级功能。它可以让物联网、工业互联网、金融、IT 运维监控等领域企业在时序数据的管理上大幅降低人力成本和运营成本。