20230622mysql in k8s

0.背景

视频版 TODO 待录制

原计划是从手动到容器化再到云原生,每种阶段的搭建方式都来一次,但实际上容器化和云原生基本上没什么太大差距。因此跳过容器化阶段直接进入云原生的数据库搭建。

mysql属于有状态的应用,因此它的存储在一般的docker中需要特殊处理。有一种说法是没有必要在docker中搭建mysql,这个说法不完全对,在测试环境容器化可以带来很大的灵活性。实际上生产环境下上只要存储弄好了之后利用k8s的资源管理和调度能力是可以搭出合适的mysql集群的

其实前段时间已经给paraparty的群服务器搭过一次了,这里是总结下经验,详细记录请参考https://paraparty.feishu.cn/docx/FsBNdoDQAo4E8VxN0zZceTP8nsh

1.前期准备

在k8s中搭建mysql架构如图,来自官方的文档,直接照着搭即可。版本选择 8.0.33

MySQL、Kubernetes 通用术语. 例如Node可能代指一个Kubernetes Node或一个MySQL Node,Cluster可能代指一个MySQL InnoDB集群或Kubernetes集群,ReplicaSet是MySQL和Kubernetes都有的一个特性。

1.1.计算资源

  • k8s系统使用Controllers来管理Pod(在其中运行的容器化负载)的生命周期。Controllers是一个通用工具提供了广泛的服务能力,但复杂的服务需要包括operator之类额外的组件。Operator是一个运行在k8s集群中的软件和k8s-api进行交互来观测资源和服务来协助k8s进行生命周期的管理
  • MySQL Operator for Kubernetes 是一个专注于管理一个或多个由MySQL Server组成的MySQL InnoDB集群和MySQL Routers的工具。它自身在k8s集群中运行并作为k8s Deployment被管理,以此来保证自身的可用性 默认情况下它被部署在’mysql-operator’的k8s命名空间内,并监视k8s集群中所有的InnoDB集群和相关联的资源,为了执行这些任务operator订阅k8s-api服务来更新事件并按需连接到被管理的MySQL Server实例上。在k8s-controller的最顶层operator配置MySQL servers,使用Group Replication配置高可用集群,以及Mysql Router
  • MySQL InnoDB Cluster 一旦InnoDB Cluster (InnoDBCluster) 资源被部署到k8s-api上,Operator会创建如下的资源: k8s-StatefulSet来运行MySQL Server实例 他们管理Pods并分配相关的存储卷(storage Volume,sc),这个StatefulSet运行多个容器作为Pod,每个Pod都被其管理。 开始的几个提供一系列的初始化步骤来准备MySQL Server的配置和数据文件夹,紧接着两个容器作为业务容器保持存活。其中一个名为mysql的容器运行MySQL Server本体,另一个名为sidecar的容器来和operator写作负责节点的本地管理
  • k8s-Deployment来运行MySQL Routers MySQL Routers是无服务的状态应用,依照客户端要求来转发流量到当前的主节点或从节点,operator可以调整router的数量来根据实际的情况扩容或缩容

1.2.服务暴露

  • 一个MySQL InnoDB集群部署会创建如下的k8s-Services: 一个名为InnoDB Cluster的服务,它负责作为MySQL Router的主入口。同时提供了一个固定的本地DNS域名,格式为'{clustername}.svc.cluster.local’,并同时暴露需要的端口 详细信息查看官网文档 “MySQL InnoDB Cluster Service Explanation” and Connecting to MySQL InnoDB Cluster.
  • 第二个名为'{clustername}-instances’的服务为每个独立的实例提供了固定的本地DNS域名。一般来说他们不应该被直接访问,而应该使用主服务的域名来保证访问到正确的主节点或从节点。然而,为了运维或或监控来使用这个域名是有必要的,每个pod上都预装了MySQL Shell
  • Operator 创建和管理的其他资源不应该被手动修改,包括: 名为'{clustername}-initconf’的k8s-ConfigMap包括了MySQL 服务的配置信息,想要修改生成的my.cnf配置文件,查看 “Manifest Changes for InnoDBCluster”. 一系列k8s-Secrets用于存储系统不同部分的凭证, 名字是 ‘{clustername}.backup’, ‘{clustername.privsecrets}’, and ‘{clustername.router}’.
  • 获取operator创建的MySQL账号和关联的密码,查看 “MySQL Accounts Created by InnoDBCluster Deployment”.

2.mysql-operator

如架构图所示,mysql-operator负责具体pod的创建和维护,因此需要先安装mysql-operator,文档参考官方文档

2.1.原理追踪

简单来说mysql-operator是一个给mysqlsh开发的python模块,它会启动一个python脚本通过kopf监听k8s集群资源变动的事件并执行预定义的操作
详细追踪过程如下:
集群部署的mysql-operator会启动mysqlsh,利用–pym加载外部名为mysqloperator的python模块

这个模块在community-operator镜像制作的时候会被打进去,关键命令是COPY mysqloperator/ /usr/lib/mysqlsh/python-packages/mysqloperator

https://github.com/mysql/mysql-operator/blob/a711f0d08dc7097778c1417779146c8ce89721c4/docker-build/Dockerfile#L19
默认指定的参数是operator,根据mod = importlib.import_module(entrypoints[sys.argv[1]], "mysqloperator")可以定位到operator_main.py
https://github.com/mysql/mysql-operator/blob/a711f0d08dc7097778c1417779146c8ce89721c4/mysqloperator/__main__.py#L25
https://github.com/mysql/mysql-operator/blob/a711f0d08dc7097778c1417779146c8ce89721c4/mysqloperator/operator_main.py#L46
根据这个可以确定mysql-operator使用的是kpof来监听k8s集群事件的
kpof官方文档 https://kopf.readthedocs.io/en/stable/
kpof源码https://github.com/nolar/kopf
根据operator_xxx.py的命名风格猜测operator_cluster.py是我要找的内容,点开后可以明显看到@kopf.on.create 装饰器(py里叫decorator,java叫注解)
官方文档参考https://kopf.readthedocs.io/en/stable/handlers/#registering
https://github.com/mysql/mysql-operator/blob/a711f0d08dc7097778c1417779146c8ce89721c4/mysqloperator/controller/innodbcluster/operator_cluster.py#L52
往下翻翻很容易看到statefulset = cluster_objects.prepare_cluster_stateful_set(icspec, logger)
https://github.com/mysql/mysql-operator/blob/a711f0d08dc7097778c1417779146c8ce89721c4/mysqloperator/controller/innodbcluster/operator_cluster.py#L165
跳转到cluster_objects.py很容易发现yaml定义了
https://github.com/mysql/mysql-operator/blob/a711f0d08dc7097778c1417779146c8ce89721c4/mysqloperator/controller/innodbcluster/cluster_objects.py#L226
保险起见往下追一层,同理根据一样的原则很容易追到init对应的python代码是在init_main.py的main
parser.add_argument('--datadir', type = str, default = "/var/lib/mysql", help = "Path do data directory")
https://github.com/mysql/mysql-operator/blob/a711f0d08dc7097778c1417779146c8ce89721c4/mysqloperator/init_main.py#L77

2.2.mysqlsh的使用

文档 https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-features.html
除了root的密码可以作为运维使用之外,localroot在sidecar中也可以使用,虽然官方不建议但是这个省事。其他账号参考https://dev.mysql.com/doc/mysql-operator/en/mysql-operator-mysql-accounts.html
localroot的sock放在了/var/run/mysqld/mysql.sock/var/run/mysqld/mysqlx.sock,通过以下方式可进入shell且无需密码
  • 执行mysqlsh 'localroot@(/var/run/mysqld/mysql.sock)'
  • mysqlsh下执行\connect localroot@(/var/run/mysqld/mysql.sock)
  • 其他语法可参考https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-connection-socket.html

3.部署记录

https://dev.mysql.com/doc/mysql-operator/en/mysql-operator-innodbcluster-common.html

创建以下资源即可间接控制mysql-operator搭建集群

详细配置可以参考https://dev.mysql.com/doc/mysql-operator/en/mysql-operator-innodbcluster-simple-kubectl.html

假设namespace是mysql-test,集群名是cluster1的话,创建完成后会暴露如下内网域名

检查集群状态

集群创建后会有几个默认账号,一般建议用root作为超管使用。如前面步骤所示root是存在secret里的,其他的几个账户也是在相同的位置。mysqlbackup、mysqlrouter、mysqladmin这几个账户的密码都能从test1-backuptest1-routertest1-privsecrets中找到。其他账户请参考1.2中的链接

 

0 Comments
Leave a Reply