TiDB Operator — Kubernetes 部署实战

一、为什么在 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
1 个赞

k8s 部署很详细