网络上有很多基于K8S搭建mysql主从同步的文章,其中有很多都源自于下面这篇文章,我们权且就叫它参考文章吧:

这篇文章里的方法是没有问题的,但是因为作者在做实验的时候用到的mysql官方的docker镜像比较老,如果采用官方最新的镜像(基于mysql8.0.15)用参考文章里的方法会遇到一些错误,这里记录一下自己在搭建过程中遇到的各种坑以免以后遇到同样的问题又折腾半天。

宿主机操作系统:Mac

虚拟机操作系统:CentOS 7

mysql基础镜像:  mysql官方最新镜像(基于mysql8.0.15)

先大概列举一下遇到的坑,然后在详述血泪史:

(1) 构建镜像时出现gpg: ..... not assigned;

(2) 主库容器出错,出现...for the right syntax to use near 'IDENTIFIED BY'错误;

(3) 宿主机连接不到K8S的NodePort;

(4) 主从同步时出现error connecting to master错误,错误码2061;

(4) 主从同步时出现The slave I/O thread stops because master and slave have equal MySQL server ids错误;

下面开始详细记录一下过程

构建镜像

首先需要构建mysql主库和从库的基础镜像,按照参考文献中的做法,将构建官方基础镜像的Dockerfile等下载下来,下下来后会看到有三个东东:

0f0e6ca5f9876be576eee805dc119dcf.png

按照参考文章的做法,我们需要做两件事:修改Dockerfile和docker-entrypoint.sh,当然写参考文章的作者非常贴心,怎么改,改动添加到文件中哪个位置都已经告诉我们了,于是欢天喜地的按照文章中的做法一字不落的搞定,然后开始构建镜像:

docker build -t="edgetech/mysql-master:v1" .

接下来遇到了取经路上的第一个小鬼,构建镜像时提示下面这样的错误:

gpg: ...... not assigned

完全不清楚这个错误是什么鬼,网上搜索大半天也没有找到解决方案,束手无策之际随手又重新执行了一遍docker build命令,我靠,居然可以了!好吧,看来是网络问题,继续往前走。

K8S中部署并运行mysql主从集群

把构建好的镜像上传到docker hub上,现在可以开始写K8S的资源文件了,为了能在宿主机上连接mysql,稍微改了一下,用NodePort的方式,首先是mysql-master-rc.yaml:

d13cfc84e988d209c3200928dbe88b0b.png

然后是mysql-master-service.yaml:

bd77a3a297addc71f2a45e87309ff325.png

接下来是mysql-slave相关的,基本上类似,先看看mysql-slave-rc.yaml:

9569cf3fa940ce7f7362d1025e825112.png

好,赶紧的先运行起来:

kubectl create -f ...

喝杯小茶,坐等POD被调度起来,一段时间后通过kubectl get pods查看进度,What!!!,mysql-master对应的POD状态居然是:CrashLoopBackOff,这是什么情况,看样子是主库的容器挂掉了,得看看这个容器内部到底发生了什么:

docker ps -a

发现主库对应的容器确实处于Exited状态,查看一下这个容器的日志:

docker logs ...

看到这样一行日志:... for the right syntax to use near 'IDENTIFIED BY',看样子是构建镜像时修改了配置文件有点问题,参考文章中说要在docker-entrypoint.sh加入下面的代码:

echo "CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}"

echo "GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}"

echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"

但是mysql 8.0开始这种写法会出问题,其实打开参考文章链接原文,下面的评论区已经有人指出了错误的地方:

echo "GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}"

但是这哥们好事只做了一半,没有告诉我们正确的写法,其实只要把这一句后面的IDENTIFIED BY这一部分去掉就可以了,正确的写法:

echo "CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}"

echo "GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%' | "${mysql[@]}"

echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"

好吧,重新构建一下镜像、上传,然后再次运行,这次没问题了,kubectl get pods,发现状态OK,都是Runing。

K8S NodePort连接不上的问题

我们从宿主机上用Navicat来连接一下试试,填入虚拟机的IP地址和NodePort映射的master库的端口30002连一下,问题又来了,居然连不到,K8S的NodePort不可能有问题吧,防火墙也是关掉的呀?肯定是哪里的配置有问题,果然网上搜了一下,有高人指点:

原来是selinux搞的鬼,按文中的说法操作一下:

setenforce 0

iptables --flush

iptables -tnat --flush

service docker restart

iptables -P FORWARD ACCEPT

宿主机上再次用navicat连接,果然OK。

MYSQL主从同步问题

现在数据库可以正常连接上了,来试试主从同步是否OK,在master上创建一个数据库,并建立表,随便加一些数据,然后进入从库,navicat上敲一下命令:

show slave status

哇靠,问题又来了,上面的SQL告诉我error connecting to master...,并且Last_IO_Errno为2061,只好再次网上求援,下面这个文章详细说明了出现这个错误的原因:

看来是因为我们用了mysql最新的官方镜像,所以参考文章中的改法已经不适用了,修改一下构建主镜像的docker-entrypoint.sh,改成下面这样:

echo "CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED WITH 'mysql_native_password' BY '$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}"

echo "GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%' ;" | "${mysql[@]}"

echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"

注意改动点,第一行创建用户那里增加了 IDENTIFIED WITH 'mysql_native_password',按照网上那篇文章的说法,是因为MySQL8.0默认指定使用需要SSL的身份验证插件caching_sha2_password,因此需要绕过绕过SSL插件的验证,改为mysql_native_password验证来做同步复制。

重新制作镜像,然后利用新镜像再次验证主从同步,果不其然还有坑,这一次show slave status报出了下面的错误:

The slave I/O thread stops because master and slave have equal MySQL server ids...

用show variables like 'server_id'分别在主库和从库看一下,果然这个值都是1,在看看之前对Dockerfile的修改,主库用sed将server_id设置成了1:

RUN sed -i '/[mysqld]/a server-id=1nlog-bin' /etc/mysql/mysql.conf.d/mysqld.cnf

而存库则设置成了一个随机值:

RUN RAND="$(date +%s | rev | cut -c 1-2)$(echo ${RANDOM})" && sed -i '/[mysqld]/a server-id='$RAND'nlog-bin' /etc/mysql/mysql.conf.d/mysqld.cnf

按说主从库的server id不应该相同,但怎么就一样了呢?仔细看看Dockerfile,原来用了mysql官方镜像以后,参考文章中添加这两处修改的地方已经不适用了,要改一改,看看问题在哪里:

原文中的:

0b46000f30e707ffa3c4f9293048aad3.png

最新的:

578891afb738442c4432aea4f30c60f0.png

注意到了吗,最新的官方镜像里,会将构建上下文中的config目录拷贝到容器的/etc/mysql里,这样我们的修改其实是被覆盖掉了,所以要把RUN sed -i ....这一句放到 COPY config/ /etc/mysql/这一句的下面。

对主和从的Dockerfile又重新进行修改后构建镜像,再次测试,这次再也没有出错了,主从同步OK。

总结

其实搭建基于K8S的Mysql主从配置过程中遇到的这些问题,大多都源自于使用了官方最新的mysql镜像,而参考文章中的做法用的则是比较老的,导致如果完全照搬会出现问题,好在所有这些问题都比较容易解决,这里记录一下避免将来踩同样的坑,掉同一条河。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐