利用Kubernetes搭建mysql主从复制集群

96
paulliu
0.3 2016.10.17 14:40* 字数 1900

之前相关的文章请参考:
Docker集群管理方案Kubernetes之部署
Docker集群管理方案Kubernetes之组件

通过本文的实践,我们可以了解一下k8s能带给我们什么。另外,实际生产环境中mysql的主从复制考虑的事情会更多。

mysql主从复制

mysql的主从复制可以通过如下方式实现。

  1. master
    在master主机上修改配置文件,比如通常是修改my.cnf。
    [mysqld] server-id=1 log-bin
    在mysql上创建同步账号并授权。
    如下,创建用户名为repl,密码为1234567:
    create user 'repl'@'%' identified by '1234567';
    如下,给repl用户授权允许同步:
    grant replication slave on *.* to 'repl'@'%' identified by '1234567';

  2. slave
    同样,在slave主机上修改配置文件。
    [mysqld] server-id=2 log-bin
    接着配置如下,其中x.x.x.x为master主机ip地址。
    change master to master_host='x.x.x.x',master_user='repl',master_password='1234567';

注意server-id为主机标识,不能重复。

利用Docker实现主从复制

本节介绍利用Docker官网镜像文件实现上述的各项配置,这是为了接下来k8s的使用。利用Docker实现mysql的方式有很多种,可以参考其他文章。

mysql官网Docker镜像文件地址:https://hub.docker.com/_/mysql/
这里用的是8.0 Dockerfile,包括两个文件Dockerfile, docker-entrypoint.sh。

  1. 准备master的镜像
    将Dockerfile, docker-entrypoint.sh复制一份作为master的镜像。
    在Dockerfile中添加如下:
    RUN sed -i '/\[mysqld\]/a server-id=1\nlog-bin' /etc/mysql/mysql.conf.d/mysqld.cnf
    在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_REPLICATION_USER和MYSQL_REPLICATION_PASSWORD,用作主从复制的账号和密码。
    通过下面的截图可以看到上面添加内容所在的位置。

    Dockerfile.png

    docker-entrypoint.sh.png

  2. 准备slave的镜像
    将Dockerfile, docker-entrypoint.sh复制一份作为slave的镜像。
    在Dockerfile中添加如下:
    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用的是随机数。
    在docker-entrypoint.sh中添加如下:
    echo "STOP SLAVE;" | "${mysql[@]}" echo "CHANGE MASTER TO master_host='$MYSQL_MASTER_SERVICE_HOST', master_user='$MYSQL_REPLICATION_USER', master_password='$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}" echo "START SLAVE;" | "${mysql[@]}"
    通过下面的截图可以看到上面添加内容所在的位置。

    Dockerfile.png

    docker-entrypoint.sh.png

    重要的来了,上面slave的配置中,master_host一项用的是$MYSQL_MASTER_SERVICE_HOST,这个环境变量(enviromnent variable)是由k8s生成的。
    k8s的service创建后,会自动分配一个cluster ip,这个cluster ip是动态的,我们没法直接使用或硬编码,k8s为了service对容器的可见,生成了一组环境变量,这些环境变量用于记录service name到cluster ip地址的映射关系,这样容器中就可以使用这些变量来使用service。(类似的,Docker中提供了links。)

举例:如果service的名称为foo,则生成的环境变量如下:
FOO_SERVICE_HOST
FOO_SERVICE_PORT
更多介绍请参考k8s官方资料:http://kubernetes.io/docs/user-guide/container-environment/

  1. 构建镜像并上传至docker hub
    分别构建用于mysql master和mysql slave的Docker镜像,并上传至docker hub,地址为https://hub.docker.com/ (这是因为当我们用k8s去做mysql集群部署的时候,k8s默认会去docker hub下载镜像。通常在生产环境中服务器是不运行连接internet的,因此通常会搭建自己的docker hub服务器。)。

构建master镜像

切换到master Dockerfile所在的目录,执行命令:
docker build -t paulliu/mysql-master:0.1 .

构建slave镜像

切换到slave Dockerfile所在的目录,执行命令:
docker build -t paulliu/mysql-slave:0.1 .

镜像推送

然后将构建好的镜像文件推送到docker hub,首先使用下面的命令登陆,如果没有注册,需要先到官网注册一下。
docker login
接着执行推送命令:
docke push paulliu/mysql-master:0.1
docke push paulliu/mysql-slave:0.1

如果感觉上面的一堆配置太麻烦,可以直接使用我构建好的镜像,地址为:
https://hub.docker.com/u/paulliu/

k8s部署

终于进入到正题,接下来开始利用k8s构建mysql集群。
首先声明,由于yaml格式的问题,没法直接贴源代码,只能贴截图,见谅。

  1. mysql master的部署
    replication controller和service的yaml文件如下,文件名分别为mysql-master-rc.yaml和mysql-master-service.yaml。
    replication controller:

    mysql-master-rc.yaml.png

    可以看到在env中添加了mysql需要的环境变量。
    service:
    mysql-master-service.yaml.png

    切换到yaml文件所在目录,执行命令以部署mysql master服务:
    kubectl create -f mysql-master-rc.yaml
    kubectl create -f mysql-master-service.yaml

  2. mysql slave的部署
    replication controller和service的yaml文件如下,文件名分别为mysql-slave-rc.yaml和mysql-slave-service.yaml。
    replication controller:

    mysql-slave-rc.yaml.png

    service:
    mysql-slave-service.yaml.png

    切换到yaml文件所在目录,执行命令以部署mysql slave服务:
    kubectl create -f mysql-slave-rc.yaml
    kubectl create -f mysql-slave-service.yaml

  3. 查看运行状态
    执行命令,查看k8s各资源的运行情况:
    kubectl get pods,service,rc
    我的环境的运行截图,各资源运行正常。

    k8s.png

  4. 测试mysql的主从复制
    到目前为止,mysql的一主一从均运行在k8s的pod中。由于上面service创建并没有使用type: NodePort方式,所以service只能在kubernetes的pods中引用,外界是无法使用的。

mysql master上的操作

通过如下命令连接到pods中的容器,其中mysql-master-pe18a为pod名称。
kubectl exec -it mysql-master-pe18a /bin/bash
接着连接本地mysql master服务器:
mysql -uroot -p
至此进入到mysql命令模式。
执行命令show master status;查看状态。
执行下面的命令创建数据库以及表,以测试数据同步:
create database paul_test_sync_db; use paul_test_sync_db; create table test_tb(id int(3),name char(10)); insert into test_tb values(001,'ok');

mysql slave上的操作

按照上面相同的方式进入到mysql slave的命令行,执行以下命令:
show slave status\G;
通过该命令可以查看主从同步的情况,通常利用该命令来检查主从配置是否有问题。

mysql-slave-running.png

执行以下命令,可以看到刚才在master上创建的库表已经同步过来了:
show databases; use paul_test_sync_db; select * from test_tb;

  1. 集群伸缩
    上面仅仅是一主一从,那接下来看看如何利用k8s对从服务器进行扩展。
    此处将原先的1台从服务器扩展为3台,执行命令:
    kubectl scale rc mysql-slave --replicas=3
    上面命令的意思是将名称为mysql-slave的rc控制的pod副本数量变更为3。
    执行kubectl get pods命令可以看到扩展后的结果。

总结

本文假设你已经对kubernetes有一定了解,因此并没有对一些命令、文件进行解释。
本文搭建的mysql一主多从集群环境,并没有考虑外部卷的挂载,因此当集群服务重启后,在mysql中创建的数据库、添加的数据会全部丢失。

随笔
Web note ad 1