使用 DinD 在 Kubernetes 上部署 TiDB 集群

本文介绍了如何在个人电脑(Linux 或 macOS 系统)上采用 Docker in Docker (DinD) 方式在 Kubernetes 上部署 TiDB Operator 和 TiDB 集群。

DinD 将 Docker 容器作为虚拟机运行,并在第一层 Docker 容器中运行另一层 Docker 容器。kubeadm-dind-cluster 使用 DinD 技术在 Docker 容器中运行 Kubernetes 集群。TiDB Operator 通过完善过的一套 DinD 脚本来管理 DinD Kubernetes 集群。

环境准备

部署前,请确认软件、资源等满足如下需求:

  • 资源需求 CPU 2+,Memory 4G+

    注意:

    对于 macOS 系统,需要给 Docker 分配 2+ CPU 和 4G+ Memory。详情请参考 Mac 上配置 Docker

  • Docker:>= 17.03

    注意:

    • 由于 DinD 不能在 Docker Toolbox 或者 Docker Machine 上运行,Legacy Docker Toolbox 用户必须卸载 Legacy Docker Toolbox 并安装 Docker for Mac
    • 安装过程中,kubeadm 会检查 Docker 版本。如果 Docker 版本比 18.06 更新,安装过程会打印警告信息。集群可能仍然能正常工作,但是为保证更好的兼容性,建议 Docker 版本在 17.03 和 18.06 之间。你可以在 这里 下载旧版本 Docker。
  • Helm Client: 版本 >= 2.9.0 并且 < 3.0.0

  • Kubectl: 至少 1.10,建议 1.13 或更高版本

    注意:

    不同版本 kubectl 输出可能略有不同。

  • 对于 Linux 用户, 如果使用 5.x 或者更高版本内核,安装过程中 kubeadm 可能会打印警告信息。集群可能仍然能正常工作,但是为保证更好的兼容性,建议使用 3.10+ 或者 4.x 版本内核。

  • 需要 root 权限操作 Docker 进程

  • 文件系统支持

    对于 Linux 用户,如果主机使用 XFS 文件系统(CentOS 7 默认),格式化的时候必须指定 ftype=1 选项以启用 d_type 支持,详见 Docker 文档

    可以通过命令 xfs_info / | grep ftype 检查你的文件系统是否支持 d_type/ 是 Docker 进程的数据目录。

    如果根目录 / 使用 XFS 但是没有启用 d_type,但是另一个分区启用了 d_type 或者使用另外一种文件系统,可以修改 Docker 的数据目录使用那个分区。

    假设支持的文件系统挂载到路径 /data,通过下面步骤配置 Docker 使用它:

    {{< copyable “shell-root” >}}

    1. mkdir -p /data/docker && \
    2. systemctl stop docker.service && \
    3. mkdir -p /etc/systemd/system/docker.service.d/

    覆盖 Docker service 文件:

    {{< copyable “shell-root” >}}

    1. cat << EOF > /etc/systemd/system/docker.service.d/docker-storage.conf
    2. [Service]
    3. ExecStart=
    4. ExecStart=/usr/bin/dockerd --data-root /data/docker -H fd:// --containerd=/run/containerd/containerd.sock
    5. EOF

    重启 Docker 进程:

    {{< copyable “shell-root” >}}

    1. systemctl daemon-reload && \
    2. systemctl start docker.service

第 1 步:通过 DinD 部署 Kubernetes 集群

首先,请确认 Docker 进程正常运行,你可以通过代码库中的脚本使用 DinD 为 TiDB Operator 部署一套 Kubernentes 集群(1.12 版本)。

Clone 代码:

{{< copyable “shell-regular” >}}

  1. git clone --depth=1 https://github.com/pingcap/tidb-operator && \
  2. cd tidb-operator

创建集群:

{{< copyable “shell-regular” >}}

  1. manifests/local-dind/dind-cluster-v1.12.sh up

如果集群创建过程中拉取镜像失败,可以像下面这样在执行脚本时设置环境变量 KUBE_REPO_PREFIXuhub.ucloud.cn/pingcap(Docker 镜像会从 UCloud Docker Registry 拉取):

{{< copyable “shell-regular” >}}

  1. KUBE_REPO_PREFIX=uhub.ucloud.cn/pingcap manifests/local-dind/dind-cluster-v1.12.sh up

或者为 DinD 配置 HTTP 代理:

{{< copyable “shell-regular” >}}

  1. export DIND_HTTP_PROXY=http://<ip>:<port> && \
  2. export DIND_HTTPS_PROXY=http://<ip>:<port> && \
  3. export DIND_NO_PROXY=.svc,.local,127.0.0.1,0,1,2,3,4,5,6,7,8,9 && \
  4. manifests/local-dind/dind-cluster-v1.12.sh up

由于系统环境或者配置的不同,集群创建过程中可能会输出一些警告信息,但是脚本应该正确执行并正常退出,没有任何错误。可以通过下面命令确认 k8s 集群已经启动并正常运行:

{{< copyable “shell-regular” >}}

  1. kubectl cluster-info

输出类似下面内容:

  1. Kubernetes master is running at http://127.0.0.1:8080
  2. KubeDNS is running at http://127.0.0.1:8080/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
  3. kubernetes-dashboard is running at http://127.0.0.1:8080/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy

列出节点信息(DinD 环境中,其实是 Docker 容器):

{{< copyable “shell-regular” >}}

  1. kubectl get nodes -o wide

输出类似如下内容:

  1. NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
  2. kube-master Ready master 11m v1.12.5 10.192.0.2 <none> Debian GNU/Linux 9 (stretch) 3.10.0-957.12.1.el7.x86_64 docker://18.9.0
  3. kube-node-1 Ready <none> 9m32s v1.12.5 10.192.0.3 <none> Debian GNU/Linux 9 (stretch) 3.10.0-957.12.1.el7.x86_64 docker://18.9.0
  4. kube-node-2 Ready <none> 9m32s v1.12.5 10.192.0.4 <none> Debian GNU/Linux 9 (stretch) 3.10.0-957.12.1.el7.x86_64 docker://18.9.0
  5. kube-node-3 Ready <none> 9m32s v1.12.5 10.192.0.5 <none> Debian GNU/Linux 9 (stretch) 3.10.0-957.12.1.el7.x86_64 docker://18.9.0

第 2 步:在 DinD Kubernetes 集群中部署 TiDB Operator

注意:

${chartVersion} 在后续文档中代表 chart 版本,例如 v1.0.0-beta.3

如果 K8s 集群启动并正常运行,可以通过 helm 添加 chart 仓库并安装 TiDB Operator。

  1. 添加 Helm chart 仓库:

    {{< copyable “shell-regular” >}}

    1. helm repo add pingcap http://charts.pingcap.org/ && \
    2. helm repo list && \
    3. helm repo update && \
    4. helm search tidb-cluster -l && \
    5. helm search tidb-operator -l
  2. 安装 TiDB Operator:

    {{< copyable “shell-regular” >}}

    1. helm install pingcap/tidb-operator --name=tidb-operator --namespace=tidb-admin --set scheduler.kubeSchedulerImageName=mirantis/hypokube --set scheduler.kubeSchedulerImageTag=final --version=${chartVersion}

    然后等待几分钟确保 TiDB Operator 正常运行:

    {{< copyable “shell-regular” >}}

    1. kubectl get pods --namespace tidb-admin -l app.kubernetes.io/instance=tidb-operator

    输出类似如下内容:

    1. NAME READY STATUS RESTARTS AGE
    2. tidb-controller-manager-5cd94748c7-jlvfs 1/1 Running 0 1m
    3. tidb-scheduler-56757c896c-clzdg 2/2 Running 0 1m

第 3 步:在 DinD Kubernetes 集群中部署 TiDB 集群

通过 helm 和 TiDB Operator,我们可以很轻松的部署一套 TiDB 集群:

{{< copyable “shell-regular” >}}

  1. helm install pingcap/tidb-cluster --name=demo --namespace=tidb --version=${chartVersion}

等待几分钟,确保 TiDB 所有组件正常创建并进入 ready 状态,可以通过下面命令持续观察:

{{< copyable “shell-regular” >}}

  1. kubectl get pods --namespace tidb -l app.kubernetes.io/instance=demo -o wide --watch

当所有 Pod 状态为 RunningCtrl+C 停止 watch。

通过下面步骤获取集群信息:

{{< copyable “shell-regular” >}}

  1. kubectl get tidbcluster -n tidb

输出类似如下信息:

  1. NAME PD STORAGE READY DESIRE TIKV STORAGE READY DESIRE TIDB READY DESIRE
  2. demo pingcap/pd:v3.0.0-rc.1 1Gi 3 3 pingcap/tikv:v3.0.0-rc.1 10Gi 3 3 pingcap/tidb:v3.0.0-rc.1 2 2

{{< copyable “shell-regular” >}}

  1. kubectl get statefulset -n tidb

输出类似如下信息:

  1. NAME DESIRED CURRENT AGE
  2. demo-pd 3 3 1m
  3. demo-tidb 2 2 1m
  4. demo-tikv 3 3 1m

{{< copyable “shell-regular” >}}

  1. kubectl get service -n tidb

输出类似如下信息:

  1. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  2. demo-discovery ClusterIP 10.96.146.139 <none> 10261/TCP 1m
  3. demo-grafana NodePort 10.111.80.73 <none> 3000:32503/TCP 1m
  4. demo-pd ClusterIP 10.110.192.154 <none> 2379/TCP 1m
  5. demo-pd-peer ClusterIP None <none> 2380/TCP 1m
  6. demo-prometheus NodePort 10.104.97.84 <none> 9090:32448/TCP 1m
  7. demo-tidb NodePort 10.102.165.13 <none> 4000:32714/TCP,10080:32680/TCP 1m
  8. demo-tidb-peer ClusterIP None <none> 10080/TCP 1m
  9. demo-tikv-peer ClusterIP None <none> 20160/TCP 1m

{{< copyable “shell-regular” >}}

  1. kubectl get configmap -n tidb

输出类似如下信息:

  1. NAME DATA AGE
  2. demo-monitor 5 1m
  3. demo-monitor-dashboard-extra-v3 2 1m
  4. demo-monitor-dashboard-v2 5 1m
  5. demo-monitor-dashboard-v3 5 1m
  6. demo-pd 2 1m
  7. demo-tidb 2 1m
  8. demo-tikv 2 1m

{{< copyable “shell-regular” >}}

  1. kubectl get pod -n tidb

输出类似如下信息:

  1. NAME READY STATUS RESTARTS AGE
  2. demo-discovery-649c7bcbdc-t5r2k 1/1 Running 0 1m
  3. demo-monitor-58745cf54f-gb8kd 2/2 Running 0 1m
  4. demo-pd-0 1/1 Running 0 1m
  5. demo-pd-1 1/1 Running 0 1m
  6. demo-pd-2 1/1 Running 0 1m
  7. demo-tidb-0 1/1 Running 0 1m
  8. demo-tidb-1 1/1 Running 0 1m
  9. demo-tikv-0 1/1 Running 0 1m
  10. demo-tikv-1 1/1 Running 0 1m
  11. demo-tikv-2 1/1 Running 0 1m

访问数据库和监控面板

通过 kubectl port-forward 暴露服务到主机,可以访问 TiDB 集群。命令中的端口格式为:<主机端口>:<k8s 服务端口>

注意:

如果你不是在本地 PC 而是在远程主机上部署的 DinD 环境,可能无法通过 localhost 访问远程主机的服务。如果使用 kubectl 1.13 或者更高版本,可以在执行 kubectl port-forward 命令时添加 --address 0.0.0.0 选项,在 0.0.0.0 暴露端口而不是默认的 127.0.0.1

  • 通过 MySQL 客户端访问 TiDB

    在访问 TiDB 集群之前,请确保已安装 MySQL client。

    1. 使用 kubectl 暴露 TiDB 服务端口:

      {{< copyable “shell-regular” >}}

      1. kubectl port-forward svc/demo-tidb 4000:4000 --namespace=tidb

      注意:

      如果代理建立成功,会打印类似输出:Forwarding from 0.0.0.0:4000 -> 4000。测试完成后按 Ctrl + C 停止代理并退出。

    2. 然后,通过 MySQL 客户端访问 TiDB,打开一个新终端标签或者一个新终端窗口,执行下面命令:

      {{< copyable “shell-regular” >}}

      1. mysql -h 127.0.0.1 -P 4000 -u root
  • 查看监控面板

    1. 使用 kubectl 暴露 Grafana 服务端口:

      {{< copyable “shell-regular” >}}

      1. kubectl port-forward svc/demo-grafana 3000:3000 --namespace=tidb

      注意:

      如果代理建立成功,会打印类似输出:Forwarding from 0.0.0.0:3000 -> 3000。测试完成后按 Ctrl + C 停止代理并退出。

    2. 然后,在浏览器中打开 http://localhost:3000 访问 Grafana 监控面板:

      • 默认用户名:admin
      • 默认密码:admin
  • 永久远程访问

    尽管这是一个非常简单的演示集群,不适用于实际使用,如果能不通过 kubectl port-forward 就能远程访问也会比较有用,当然,你需要一个终端。

    TiDB、Prometheus 和 Grafana 默认通过 NodePort 服务暴露,所以可以为它们搭建一个反向代理。

    1. 使用下面命令找到这些服务的 NodePort:

      {{< copyable “shell-regular” >}}

      1. kubectl get service -n tidb | grep NodePort

      输出类似如下内容:

      1. demo-grafana NodePort 10.111.80.73 <none> 3000:32503/TCP 1m
      2. demo-prometheus NodePort 10.104.97.84 <none> 9090:32448/TCP 1m
      3. demo-tidb NodePort 10.102.165.13 <none> 4000:32714/TCP,10080:32680/TCP 1m

      在这个输出示例中,各服务的 NodePort 为:Grafana 32503、Prometheus 32448、TiDB 32714。

    2. 列出集群的节点 IP 地址。

      DinD 是在 Docker 容器中运行的 K8s 集群,所以服务端口暴露到了容器地址上,而不是主机上。可以通过下面命令列出 Docker 容器的 IP 地址:

      {{< copyable “shell-regular” >}}

      1. kubectl get nodes -o yaml | grep address

      输出类似如下内容:

      1. addresses:
      2. address: 10.192.0.2
      3. address: kube-master
      4. addresses:
      5. address: 10.192.0.3
      6. address: kube-node-1
      7. addresses:
      8. address: 10.192.0.4
      9. address: kube-node-2
      10. addresses:
      11. address: 10.192.0.5
      12. address: kube-node-3

      在反向代理中使用这些 IP 地址。

    3. 搭建反向代理。

      任意一个(或者所有)容器 IP 可以配置为反向代理的 upstream。你可以使用任何支持 TCP (TiDB) 或者 HTTP (Grafana 和 Prometheus) 的反向代理提供远程访问。HAPROXY 和 NGINX 是两个常用的选择。

水平扩缩容 TiDB 集群

你可以通过简单地修改 replicas 来扩容或者缩容 TiDB 集群。

  1. 获取当前使用的 tidb-cluster chart 对应的 values.yaml:

    {{< copyable “shell-regular” >}}

    1. mkdir -p /home/tidb/demo && \
    2. helm inspect values pingcap/tidb-cluster --version=${chartVersion} > /home/tidb/demo/values-demo.yaml
  2. 编辑 /home/tidb/demo/values-demo.yaml

    例如,要扩容集群,可以将 TiKV replicas 从 3 修改为 5,或者将 TiDB replicas 从 2 修改为 3。

  3. 执行下面命令升级集群:

    {{< copyable “shell-regular” >}}

    1. helm upgrade demo pingcap/tidb-cluster --namespace=tidb -f /home/tidb/demo/values-demo.yaml --version=${chartVersion}

注意:

如果要缩容 TiKV,因为要安全地迁移数据,缩容需要的时间取决于已有数据量的大小。

通过 kubectl get pod -n tidb 命令验证每个组件的数量是否等于在 /home/tidb/demo/values-demo.yaml 中设置的数量,并且所有 Pod 都已处于 Running 状态。

升级 TiDB 集群

  1. 编辑文件 /home/tidb/demo/values-demo.yaml

    例如,修改PD、TiKV 和 TiDB imagev3.0.0-rc.2

  2. 执行如下命令升级集群:

    {{< copyable “shell-regular” >}}

    1. helm upgrade demo pingcap/tidb-cluster --namespace=tidb -f /home/tidb/demo/values-demo.yaml --version=${chartVersion}

    通过 kubectl get pod -n tidb 命令确认所有 Pod 处于 Running 状态。然后你可以访问数据库并通过 tidb_version() 确认版本:

    {{< copyable “sql” >}}

    1. select tidb_version();

    输出类似如下内容:

    1. *************************** 1. row ***************************
    2. tidb_version(): Release Version: v3.0.0-rc.2
    3. Git Commit Hash: 06f3f63d5a87e7f0436c0618cf524fea7172eb93
    4. Git Branch: HEAD
    5. UTC Build Time: 2019-05-28 12:48:52
    6. GoVersion: go version go1.12 linux/amd64
    7. Race Enabled: false
    8. TiKV Min Version: 2.1.0-alpha.1-ff3dd160846b7d1aed9079c389fc188f7f5ea13e
    9. Check Table Before Drop: false
    10. 1 row in set (0.001 sec)

销毁 TiDB 集群

测试结束后,使用如下命令销毁 TiDB 集群:

{{< copyable “shell-regular” >}}

  1. helm delete demo --purge

注意:

上述命令只是删除运行的 Pod,数据仍然会保留。

如果你不再需要那些数据,可以通过下面命令清除数据(注意,这将永久删除数据)。

{{< copyable “shell-regular” >}}

  1. kubectl get pv -l app.kubernetes.io/namespace=tidb -o name | xargs -I {} kubectl patch {} -p '{"spec":{"persistentVolumeReclaimPolicy":"Delete"}}' && \
  2. kubectl delete pvc --namespace tidb --all

停止、重启 Kubernetes 集群

  • 如果要停止 DinD Kubernetes 集群,可以执行下面命令:

    {{< copyable “shell-regular” >}}

    1. manifests/local-dind/dind-cluster-v1.12.sh stop

    可以通过 docker ps 命令验证所有 Docker 容器都已停止运行。

  • 如果停止 DinD Kubernetes 集群后又要重新启动,可以执行下面命令:

    {{< copyable “shell-regular” >}}

    1. manifests/local-dind/dind-cluster-v1.12.sh start

销毁 DinD Kubernetes 集群

如果要删除 DinD Kubernetes 集群,可以执行下面命令:

{{< copyable “shell-regular” >}}

  1. manifests/local-dind/dind-cluster-v1.12.sh clean && \
  2. sudo rm -rf data/kube-node-*

警告:

销毁 DinD Kubernetes 集群后,必须清除数据,否则当你重新创建新集群时,TiDB 集群会启动失败。