作者:王悦
爱可生研发团队成员,负责数据库管理平台相关项目的开发和故障排查,好奇 MySQL 技术原理及各类数据库实现方案。
本文来源:转载自公众号-图解 MySQL
*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
注:阅读本文需要了解 pod,controller,service 等一些 kubernetes 的基本概念。
什么是 kubernetes?有了容器技术后为什么还需要 kubernetes?
容器凭借其良好的移植性,敏捷性和革命性的打包方式迅速成为云服务的新基础设施。但 Docker 毕竟只是 “container runtime”,我们需要一个编排框架作为系统核心来串联开发、测试、部署、运维等整个软件生命周期。kubernetes 就提供这样一个框架,提供大量容器的部署、编排、管理的能力。
如果将 MySQL 部署在 kubernetes 会有哪些挑战?带来了什么收益?
虽然 kubernetes 社区一直在努力使得有状态应用成为一等公民,也推出了 statefulset 控制器支持 pod 的顺序部署,稳定的域名访问和存储访问。但鉴于 MySQL 部署运维的多样性和复杂性,在 kubernetes 上部署 MySQL 仍然要面临众多挑战。
1、业务流量入口的配置方式
传统虚拟机环境下,我们通过虚 IP 的方式,让业务应用都配置事先定义的一个虚 IP 为链接数据库的地址,然后由高可用服务保证虚 IP 始终能被路由到 master 数据库。
在 kubernetes 中,出现了一层网络插件屏蔽了底层网络拓扑,高可用服务管理虚 IP 的方式需要随之适应调整,比如通过 service 结合标签完成虚 IP 的漂移,但 service 本身是 kubernetes 提供的一项功能,其可靠性和性能都取决于 kubernetes 服务的稳定。
以性能来说,service 是 kube proxy 组件通过配置 iptables 实现的,当 iptables 规则较多时不可避免的会产生时延,需要我们针对性的解决。
2、容器隔离带来的监控视野问题
在 kubernetes 中,如果将 MySQL 制作为 container 运行在一个 pod 中,container 会将 MySQL 进程和运行环境隔离在一个单独的 namespace 中。监控组件在获取 MySQL 的一些 metirc 时,可能不得不进入与 MySQL 同一个 namespace 中,在部署和设计监控组件时需要考虑到这些限制。
3、存储
在 kubernetes 中,支持配置各种不同的存储。如果使用本地存储 local persistent volume,则需要绑定 MySQL 在一个固定的节点,这就完全浪费了 kubernetes 灵活调度的天然优势;而如果使用远程共享存储,确实是将 MySQL 进程与其存储完全解耦,使得 MySQL 进程可以在任意节点调度,然而考虑到高 I/O 吞吐量的情况,就不是那么美好了。
设计时需要考量远程存储是否能够满足 MySQL 的带宽要求。
4、高可用/备份恢复
kubernetes 提供的 statefulset 控制器只能提供最基本的部署,删除功能,无法实现完善的 MySQL 集群高可用/备份恢复操作。对于有状态应用的部署,仍需要定制开发,所以多数公司提供了定制的 operator 来完成应用容器的管理。比如 etcd operator,MySQL operator,后文将为大家详述我测试使用 MySQL operator 的一些记录。
注:operator 是 CoreOs 推出的旨在简化复杂有状态应用管理的框架,我们可以通过 operator 自定义一个有状态应用容器的控制器,operator 通过 kubernetes API 观察集群现有状态,管理集群行为,以达到用户期望的集群状态。
说完了问题和挑战,我们来说说收益。
把 MySQL 塞进 kubernetes 生态带来了什么?
- 丰富的网络配置
结合kubernetes的cni网络插件可以快速实现限流,黑白名单...
- 各类 kubernetes 调度、运维功能
敏捷部署,滚动更新,依据负载情况的节点调度...
- 与同样部署在 kubernetes 生态的业务应用紧密配合
然而考虑到 MySQL 这类持久层软件的特殊性,不能简单的套用 kubernetes 的原生 API 功能,比如滚动更新需要考虑主从角色的先后顺序,配套高可用软件在 MySQL 更新阶段的行为,业务流量的切换等等。这些在传统环境中已经解决的问题在 kubernetes 中仍然需要被重新规划解决方案。
控制器介绍
鉴于以上种种挑战,在 kubernetes 上管理 MySQL 需要一套专为 MySQL 设计的控制器(就我们前面说到的 operator),目前开源社区中比较流行的有以下两个控制器:
Oracle MySQL operator
先简单过一遍功能:
- 最低支持 MySQL 8.0.11 版本
- 只能支持部署MySQL Group Replication 架构,不支持 Master-Slave 部署
- operator 自动建立的 service 无法区分读写节点,推荐应用使用 mysql router,由 mysql router 路由至下游实例
- 提供 mysqldump(不支持其他备份工具)配置定时备份,备份文件上传远程存储,目前仅实现了 AWS S3 接口
- 支持从远程存储中获取备份执行回放还原
- operator 内置提供了一些基础 metric 监控集群状态
具体的安装步骤就不在这里详述了,大家可以参考
下面探索一下 operator 部署时的一些实现方式:
- operator 监听用户定义的配置 cr,调用 kubernetes api 创建 statefulset 来部署MySQL Group Replication 集群
- 使用 kubernetes secret 存储和管理 root 密码
- statefulset 创建的 pod 中定义两个 container,一个容纳 mysqld 进程,一个容纳以 sidecar 的模式负责运维功能的 mysql agent 进程
- mysqld 作为容器的 1 号进程,由 kubernetes 负责守护
- mysql agent 进程负责 mysqld 的状态监控,备份和回放任务的执行,opertaor 的 metric 也是由其提供
FAQ:
Q: pod 重启后能否保证实例的数据不丢失?
A:operator 在创建实例时会将 datadir 配置为 mysqlvolume 挂载(如 pvc 或 emptydir),所以实例重启后能够重新挂载恢复数据。注:限制是用户不能自定义 data,binlog,redolog 目录,如果不在默认的 /var/lib/mysql 目录中,数据会随 pod 重启而消亡
Q:可以为 mysqld container 设置 cpu,mem 资源限制吗?
A:可以在创建集群时配置限制,但该功能只在 master 版本上存在,目前 helm hub 中使用的是 0.3.0 tag 版本,该版本中无该功能
Q:业务和实例不在一个 kubernetes 集群时该如何连接?
A:在实例所在集群上先部署一个 mysql-router,然后通过暴露 mysql-router 给外部集群来提供访问。
暴露方式有多种可选,如 NodePort,LoadBalancer,Ingress 等
可见 Oracle MySQL operator 提供的功能非常基础,而且其 github 仓库已经一年多没有维护了,官方好像不是很想推动 MySQL 上 kubernetes,毕竟传统云服务提供的 RDS 服务已经能够满足大部分用户场景。
Percona MySQL operator
另外,Percona 也提供了一个 MySQL 的 operator,能够部署高可用 master-slave 结构的 MySQL,但依托于 Percona 版的 MySQL 提供的功能,并不支持原生的 MySQL 镜像。
结语
使用 operator 运维有状态应用确实能够解决多数问题,但维护数据库应用本身就是复杂困难的,需要适应很多场景,在 kubernetes 上完全解决这些问题短期内非常困难。
上述两个 MySQL operator 目前的实现都相对基础,直接在生产环境部署的稳定性也没有保障,只能作为调研测试的对象。