一、为什么在 Kubernetes 上部署 TiDB
1.1 传统部署 vs K8s 部署
传统 TiUP 部署:
物理机/VM 物理机/VM 物理机/VM
┌──────────┐ ┌──────────┐ ┌──────────┐
│ TiDB x1 │ │ TiKV x1 │ │ PD x1 │
│ 手动管理 │ │ 手动管理 │ │ 手动管理 │
│ 扩缩容: │ │ 扩缩容: │ │ 扩缩容: │
│ 编辑YAML │ │ 编辑YAML │ │ 编辑YAML │
│ 执行命令 │ │ 执行命令 │ │ 执行命令 │
└──────────┘ └──────────┘ └──────────┘
K8s + TiDB Operator 部署:
Kubernetes 集群
┌─────────────────────────────────────────────┐
│ │
│ ┌──────────────────────────────────────┐ │
│ │ TiDB Operator │ │
│ │ (自动管理 TiDB 集群的生命周期) │ │
│ └──────────┬───────────────────────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ v v v │
│ ┌──────┐┌──────┐┌──────┐ │
│ │TiDB ││TiKV ││ PD │ ← Pod 自动调度 │
│ │Pod x3││Pod x5││Pod x3│ ← 存储自动管理 │
│ └──────┘└──────┘└──────┘ ← 故障自动恢复 │
│ │
│ 用户操作: kubectl edit tidbcluster │
│ 扩缩容: replicas: 3 → 5 自动完成 │
└─────────────────────────────────────────────┘
1.2 TiDB Operator 的核心能力
| 能力 | 说明 |
|---|---|
| 自动部署 | 一条 CRD 创建完整 TiDB 集群 |
| 弹性伸缩 | 修改 replicas 自动扩缩容 |
| 滚动升级 | 在线升级版本,不中断服务 |
| 故障自愈 | Pod 故障自动重建,数据自动恢复 |
| 备份恢复 | 内置 Backup/Restore CRD |
| 监控集成 | 自动部署 Prometheus + Grafana |
| 多云适配 | 支持 AWS、GCP、阿里云、腾讯云等 |
二、环境准备
2.1 前置条件
| 组件 | 版本要求 |
|---|---|
| Kubernetes | 1.26+ |
| Helm | 3.11+ |
| kubectl | 与 K8s 版本一致 |
| 节点资源 | 最少 3 个 Worker 节点,每个 8C32G+ |
| 存储 | 需要 StorageClass 支持动态 PV |
2.2 安装 Helm
# 安装 Helm
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 添加 PingCAP Helm 仓库
helm repo add pingcap https://charts.pingcap.org/
helm repo update
2.3 配置 StorageClass
TiDB Operator 需要 StorageClass 来动态分配存储卷:
# 以 AWS EBS 为例
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-gp3
provisioner: ebs.csi.aws.com
parameters:
type: gp3
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
# 确认 StorageClass 可用
kubectl get storageclass
# 输出:
# NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE
# ebs-gp3 ebs.csi.aws.com Retain WaitForFirstConsumer
# ebs-io1 ebs.csi.aws.com Retain WaitForFirstConsumer
三、安装 TiDB Operator
3.1 安装
# 创建命名空间
kubectl create namespace tidb-admin
# 安装 TiDB Operator
helm install tidb-operator pingcap/tidb-operator \
--namespace=tidb-admin \
--version=v1.6.0 \
--create-namespace
3.2 验证安装
# 检查 Operator 状态
kubectl get pods -n tidb-admin
# 输出:
# NAME READY STATUS
# tidb-controller-manager-xxxxx 1/1 Running
# tidb-scheduler-xxxxx 2/2 Running
# tidb-admission-webhook-xxxxx 1/1 Running
# 检查 CRD 是否注册
kubectl get crd | grep pingcap
# 输出:
# tidbclusters.pingcap.com
# backups.pingcap.com
# restores.pingcap.com
# backupschedules.pingcap.com
3.3 自定义 Operator 配置
# values-operator.yaml
scheduler:
schedulerName: tidb-scheduler
replicas: 1
admissionWebhook:
replicas: 1
controllerManager:
replicas: 1
controllerID: "" # 如果为空,管理所有集群
helm upgrade tidb-operator pingcap/tidb-operator \
--namespace=tidb-admin \
-f values-operator.yaml
四、部署 TiDB 集群
4.1 最小集群
# tidb-cluster-minimal.yaml
apiVersion: pingcap.com/v1alpha1
kind: TidbCluster
metadata:
name: basic
namespace: tidb-cluster
spec:
version: v8.5.0
timezone: Asia/Shanghai
pvReclaimPolicy: Retain
# PD 配置
pd:
baseImage: pingcap/pd
replicas: 3
requests:
storage: "10Gi"
storageClassName: ebs-gp3
config:
schedule.leader-schedule-limit: 4
schedule.region-schedule-limit: 2048
# TiKV 配置
tikv:
baseImage: pingcap/tikv
replicas: 3
requests:
storage: "100Gi"
storageClassName: ebs-io1 # TiKV 推荐高性能存储
config:
storage.block-cache.capacity: "4GB"
server.grpc-concurrency: 6
# TiDB 配置
tidb:
baseImage: pingcap/tidb
replicas: 2
service:
type: ClusterIP # 或 LoadBalancer 对外暴露
# TiFlash 配置(可选)
tiflash:
baseImage: pingcap/tiflash
replicas: 1
requests:
storage: "100Gi"
storageClassName: ebs-gp3
# 创建集群
kubectl apply -f tidb-cluster-minimal.yaml
# 查看集群状态
kubectl get tc -n tidb-cluster
# 输出:
# NAME READY PD STORAGE READY DESIRE TIKV STORAGE READY DESIRE TIDB READY DESIRE
# basic True pingcap/pd:v8.5.0 10Gi,3 True 3 pingcap/tikv:v8.5.0 100Gi,3 True 3 pingcap/tidb:v8.5.0 True 2
# 查看 Pod 状态
kubectl get pods -n tidb-cluster
# 输出:
# basic-discovery-xxxx 1/1 Running
# basic-pd-0 1/1 Running
# basic-pd-1 1/1 Running
# basic-pd-2 1/1 Running
# basic-tidb-0 2/2 Running
# basic-tidb-1 2/2 Running
# basic-tikv-0 1/1 Running
# basic-tikv-1 1/1 Running
# basic-tikv-2 1/1 Running
4.2 连接 TiDB
# 方式一: 通过端口转发
kubectl port-forward -n tidb-cluster svc/basic-tidb 4000:4000 &
mysql -h 127.0.0.1 -P 4000 -u root
# 方式二: 使用 LoadBalancer 类型 Service(云环境)
# 修改 Service 类型为 LoadBalancer
kubectl patch svc basic-tidb -n tidb-cluster -p \
'{"spec":{"type":"LoadBalancer"}}'
# 获取外部 IP
kubectl get svc basic-tidb -n tidb-cluster
# 输出:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# basic-tidb LoadBalancer 10.96.0.100 52.14.128.50 4000/TCP
# 连接
mysql -h 52.14.128.50 -P 4000 -u root
4.3 访问 Dashboard
# Dashboard 通过 PD Service 暴露(端口 2379)
kubectl port-forward -n tidb-cluster svc/basic-pd 2379:2379 &
# 浏览器打开
# http://127.0.0.1:2379/dashboard
五、弹性伸缩
5.1 扩容 TiKV
# 修改 TidbCluster 资源,将 TiKV replicas 从 3 改为 5
# kubectl edit tc basic -n tidb-cluster
# 或直接 patch:
kubectl patch tc basic -n tidb-cluster --type='merge' \
-p '{"spec":{"tikv":{"replicas":5}}}'
# 观察扩容过程
kubectl get pods -n tidb-cluster -w
# 输出:
# basic-tikv-3 0/1 Pending
# basic-tikv-3 0/1 ContainerCreating
# basic-tikv-3 1/1 Running ← 新节点加入
# ... PD 自动迁移 Region 到新节点
# 查看 TiKV 节点
kubectl get tc basic -n tidb-cluster -o jsonpath='{.status.tikv.stores}'
5.2 扩容 TiDB
# 将 TiDB 从 2 副本扩容到 4
kubectl patch tc basic -n tidb-cluster --type='merge' \
-p '{"spec":{"tidb":{"replicas":4}}}'
5.3 缩容
# 将 TiKV 从 5 缩容到 3
kubectl patch tc basic -n tidb-cluster --type='merge' \
-p '{"spec":{"tikv":{"replicas":3}}}'
缩容时 PD 会先将该节点上的 Region 迁移到其他节点,然后再删除 Pod,确保数据不丢失。
六、滚动升级
6.1 升级集群版本
# 升级 TiDB 版本(如 v8.5.0 → v8.6.0)
kubectl patch tc basic -n tidb-cluster --type='merge' \
-p '{"spec":{"version":"v8.6.0"}}'
升级顺序由 Operator 自动控制:
升级顺序:
1. PD Follower → 等待同步 → 切换 Leader → 升级原 Leader
2. TiKV → 逐个滚动升级,等待 Region Leader 迁移
3. TiDB → 逐个滚动升级,连接自动重连
4. TiFlash → 最后升级
6.2 观察升级进度
# 查看集群状态
kubectl get tc basic -n tidb-cluster
# 升级期间 READY 会变为 False
# 查看 Pod 版本
kubectl get pods -n tidb-cluster -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
# 查看事件
kubectl get events -n tidb-cluster --sort-by='.lastTimestamp' | grep -i upgrade
6.3 暂停/恢复升级
# 在 TidbCluster spec 中添加暂停标记
spec:
paused: true # 暂停升级
# 恢复升级
spec:
paused: false
七、备份与恢复
7.1 备份到 S3
# backup-s3.yaml
apiVersion: pingcap.com/v1alpha1
kind: Backup
metadata:
name: full-backup
namespace: tidb-cluster
spec:
# 备份工具: dumpling 或 br
backupType: full
backupMethod: br
# 备份目标
storage:
s3:
provider: aws
bucket: tidb-backup-bucket
prefix: full-backup-20240521
# 使用 Secret 存储 AWS 凭证
secretName: s3-secret
# 备份的 TiDB 集群
from:
host: basic-tidb
port: 4000
user: root
secretName: backup-secret
# 备份配置
br:
cluster: basic
clusterNamespace: tidb-cluster
# 并发度
concurrency: 4
# 日志级别
logLevel: info
# 创建 AWS 凭证 Secret
kubectl create secret generic s3-secret \
--from-literal=access_key=AKIAIOSFODNN7EXAMPLE \
--from-literal=secret_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \
-n tidb-cluster
# 创建备份
kubectl apply -f backup-s3.yaml
# 查看备份状态
kubectl get backup -n tidb-cluster
# 输出:
# NAME BACKUP_TYPE MODE STATUS COMPLETION_TIME
# full-backup Full BR Complete 2024-05-21T10:30:00Z
7.2 定时备份
# backup-schedule.yaml
apiVersion: pingcap.com/v1alpha1
kind: BackupSchedule
metadata:
name: daily-backup
namespace: tidb-cluster
spec:
# Cron 表达式: 每天凌晨 2:00
schedule: "0 2 * * *"
maxBackups: 7 # 保留最近 7 个备份
maxReservedTime: "7d"
backupTemplate:
backupType: full
backupMethod: br
storage:
s3:
provider: aws
bucket: tidb-backup-bucket
prefix: scheduled-backup
secretName: s3-secret
from:
host: basic-tidb
port: 4000
user: root
secretName: backup-secret
kubectl apply -f backup-schedule.yaml
# 查看定时备份
kubectl get backupschedules -n tidb-cluster
7.3 从备份恢复
# restore.yaml
apiVersion: pingcap.com/v1alpha1
kind: Restore
metadata:
name: full-restore
namespace: tidb-cluster
spec:
restoreType: full
backupType: br
# 从哪个备份恢复
backupLocation:
s3:
provider: aws
bucket: tidb-backup-bucket
prefix: full-backup-20240521
secretName: s3-secret
# 恢复到哪个集群
to:
host: basic-tidb
port: 4000
user: root
secretName: backup-secret
br:
cluster: basic
clusterNamespace: tidb-cluster
kubectl apply -f restore.yaml
# 查看恢复状态
kubectl get restore -n tidb-cluster
八、监控集成
8.1 部署监控
# monitor.yaml
apiVersion: pingcap.com/v1alpha1
kind: TidbMonitor
metadata:
name: basic
namespace: tidb-cluster
spec:
clusters:
- name: basic
prometheus:
baseImage: prom/prometheus
version: v2.47.0
replicas: 1
logLevel: info
service:
type: ClusterIP
grafana:
baseImage: grafana/grafana
version: 10.2.0
replicas: 1
service:
type: ClusterIP
initializer:
baseImage: pingcap/tidb-monitor-initializer
version: v1.6.0
reloader:
baseImage: pingcap/tidb-monitor-reloader
version: v1.6.0
kubectl apply -f monitor.yaml
# 访问 Grafana
kubectl port-forward -n tidb-cluster svc/basic-grafana 3000:3000 &
# 浏览器打开: http://127.0.0.1:3000
# 默认账号/密码: admin/admin
九、高级配置
9.1 拓扑分布约束
spec:
pd:
replicas: 3
nodeSelector:
topology.kubernetes.io/zone: us-east-1a
tolerations:
- key: "dedicated"
operator: "Equal"
value: "tidb"
effect: "NoSchedule"
tikv:
replicas: 3
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/instance
operator: In
values:
- basic-tikv
topologyKey: kubernetes.io/hostname
9.2 配置 TiProxy
spec:
tiproxy:
baseImage: pingcap/tiproxy
replicas: 2
config:
proxy.addr: "0.0.0.0:6000"
proxy.proxy-protocol: "v2"
9.3 使用专属调度器
TiDB Operator 提供了专属的 TiDB Scheduler,可以优化 Pod 的调度策略:
spec:
pd:
schedulerName: tidb-scheduler # 使用 TiDB 专属调度器
tikv:
schedulerName: tidb-scheduler
tidb:
schedulerName: tidb-scheduler
9.4 配置 TLS
spec:
tlsCluster:
enabled: true
pd:
tlsClientSecretName: "pd-client-tls"
# 生成证书(使用 cert-manager 或手动)
kubectl apply -f tidb-tls-secret.yaml
十、故障排查
10.1 Pod 无法启动
# 查看 Pod 事件
kubectl describe pod basic-tikv-0 -n tidb-cluster
# 常见原因:
# - StorageClass 不可用 → 检查 storageclass
# - 资源不足 → 检查节点资源
# - 镜像拉取失败 → 检查镜像地址和网络
10.2 集群无法 Ready
# 查看 TidbCluster 状态
kubectl get tc basic -n tidb-cluster -o yaml
# 查看 Operator 日志
kubectl logs -n tidb-operator \
deployment/tidb-controller-manager
10.3 TiKV Pod 重启
# 查看 Pod 重启原因
kubectl get pod basic-tikv-0 -n tidb-cluster \
-o jsonpath='{.status.containerStatuses[0].lastState}'
# 查看 TiKV 日志
kubectl logs basic-tikv-0 -n tidb-cluster -c tikv --tail=100
10.4 备份失败
# 查看备份详情
kubectl describe backup full-backup -n tidb-cluster
# 查看备份 Job 日志
kubectl get jobs -n tidb-cluster
kubectl logs job/full-backup -n tidb-cluster