安装一主两从, 使用docker desktop版本安装
先随便安装一个自己想要版本的myql镜像,主要目的是将该版本镜像相关的配置文件拷贝出来,因为我们要采用目录挂载的方式,但是手里又没有配置文件和数据目录,那就要用人家已经写好的,然后进去将我们想要的文件拷贝到宿主机上
# 默认拉取最新版本的mysql
docker pull mysql
# 启动容器加载镜像
docker run -itd --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
# 进入容器
docker exec -it mysql /bin/bash
# 容器内部连接测试mysql,输入密码成功后则说明安装成功
mysql -u root -p
在本机创建存放一主两从mysql服务的数据目录和配置文件目录, mysql目录为master, mysqls1和mysqls2为两个slave
# 创建本地挂载目录
mkdir E:\docker\mysql\data && mkdir E:\docker\mysql\conf &&
mkdir E:\docker\mysqls1\data && mkdir E:\docker\mysqls1\conf &&
mkdir E:\docker\mysqls2\data && mkdir E:\docker\mysqls2\conf
将上面安装好的mysql容器里的配置文件拷贝出来, 首先要确定配置文件所在容器中的目录,这一点可以从dockerfile中查看, 到dockerhub
上查找指定版本的镜像
确定好目录之后执行拷贝动作,拷贝完成后,原容器就没用了,然后停掉并且删除它即可
# 将mysql这个容器的配置文件和数据目录拷贝出来,可以看下镜像对应的docker file,查出原始文件所在目录
docker cp mysql:/var/lib/mysql E:\docker\mysql\data &&
docker cp mysql:/etc/mysql/ E:\docker\mysql\conf &&
docker cp mysql:/var/lib/mysql E:\docker\mysqls1\data &&
docker cp mysql:/etc/mysql/ E:\docker\mysqls1\conf &&
docker cp mysql:/var/lib/mysql E:\docker\mysqls2\data &&
docker cp mysql:/etc/mysql/ E:\docker\mysqls2\conf
# 停止并删除容器
docker stop mysql
docker rm mysql
挂载本地目录,以默认配置创建三个mysql容器,分别进入容器验证是否运行成功
#######################################################################################
# 修改my.conf,更改每个mysql服务的端口号,虽然我们已经做了端口映射,可以保证在容器内每个服务依然用3306,
# 但是不知道为啥,后面映射好之后命令行可以进入,navicat会报错Lost connection to MySQL server at ‘reading initial communication packet。然后还是修改了容器内服务自己的端口号
mysqls1 my.conf port=3307
mysqls2 my.conf port=3308
#######################################################################################
# 由于是在本地演示,只有一个主机,而且需要slave容器内连接master, 所以需要给每个容器分配固定ip,方便容器互联
# 创建桥接网络
docker network create --driver=bridge --subnet=172.20.12.0/16 mynet
# 挂载本地目录重新构建容器
docker run -itd --name mysql --net mynet --ip 172.20.12.1 -v E:\docker\mysql\data\mysql:/var/lib/mysql -v E:\docker\mysql\conf\mysql:/etc/mysql/ -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
# 启动第二个服务
docker run -itd --name mysqls1 --net mynet --ip 172.20.12.2 -v E:\docker\mysqls1\data\mysql:/var/lib/mysql -v E:\docker\mysqls1\conf\mysql:/etc/mysql/ -p 3307:3307 -e MYSQL_ROOT_PASSWORD=123456 mysql
# 启动第三个服务
docker run -itd --name mysqls2 --net mynet --ip 172.20.12.3 -v E:\docker\mysqls2\data\mysql:/var/lib/mysql -v E:\docker\mysqls2\conf\mysql:/etc/mysql/ -p 3308:3308 -e MYSQL_ROOT_PASSWORD=123456 mysql
# 进入容器并登陆验证是否安装成功
docker exec -it mysql /bin/bash
mysql -uroot -p
docker exec -it mysqls1 /bin/bash
mysql -uroot -p
docker exec -it mysqls1 /bin/bash
mysql -uroot -p
如果想要更改mysql的配置,则只要修改宿主机即本机目录下的my.conf目录即可
到这里基本的安装就完成了,关于主从同步的配置以及需要更改的配置还有坑,则在下面的响应步骤中再细讲
使用Navicat客户端去连接服务的时候报错authentication plugin 'caching_sha2_password'
## 进入mysql容器
docker exec -it mysql /bin/bash
## 连接到Mysql
mysql -u root -p
## 查看当前密码规则, 可以看到为caching_sha2_password
use mysql;
select user,plugin from user where user='root';
## 更改密码插件规则,并重新指定密码, root@后面连的是主机,主机是%则所有主机都会被更改规则
alter user 'root'@'%' identified with mysql_native_password by '123456';
# 还是更改密码规则,但是%是不包含localhost的,所以要再授权一下localhost
alter user 'root'@'localhost' identified with mysql_native_password by '123456';
## 可以再次查看密码规则,已经看到被更改过来了
select user,plugin from user where user='root';
## 刷新权限
FLUSH PRIVILEGES;
# 修改另外两个的步骤和上面一样,只是要进入各自不同的容器
在mysql的配置文件,my.cnf或my.ini下加入如下内容,在本例中即E:\docker\mysql\conf\my.conf
# 设置服务id,主从不能一致
server-id=1
# 开启binlog日志
log-bin=mysql-bin
# 设置binlog最多保存7天
expire_logs_days=7
# STATEMENT模式 默认值。每一条会修改数据的sql语句会记录到binlog中,优点是并不需要记录每一条sql语句和每一行的数# 据变化,减少了binlog日志量,节约IO,提高性能
# ROW模式 不记录每条sql语句的上下文信息,仅需记录哪条数据被修改了,修改成什么样了,缺点是会产生大量的日志
# MIXED模式(以上两种模式混合使用),一般的复制使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用# ROW模式保存binlog,MySQL会根据执行的SQL语句选择日志保存方式。
binlog_format=MIXED
# 设置需要同步的数据库
binlog-do-db=boot-quick
# 屏蔽系统库同步
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
修改两个mysql从服务器的配置文件,my.cnf或my.ini下加入如下内容,在本例中即E:\docker\mysqls1\conf\my.conf, E:\docker\mysqls2\conf\my.conf
#########################E:\docker\mysqls1\conf\my.conf#######################
# 开启日志
log-bin=mysql-bin
# 设置服务id,主从不能一致
server-id=2
# 设置需要同步的数据库
replicate_wild_do_table=boot-quick.%
# 屏蔽系统库同步
replicate_wild_ignore_table=mysql.%
replicate_wild_ignore_table=information_schema.%
replicate_wild_ignore_table=performance_schema.%
#########################E:\docker\mysqls2\conf\my.conf#######################
# 开启日志
log-bin=mysql-bin
# 设置服务id,主从不能一致
server‐id=3
# 设置要忽略的表
replicate-ignore-db=boot-quick.user_article
replicate-ignore-db=boot-quick.user_article_1
# 设置需要同步的数据库
replicate_wild_do_table=boot-quick.%
# 屏蔽系统库同步
replicate_wild_ignore_table=mysql.%
replicate_wild_ignore_table=information_schema.%
replicate_wild_ignore_table=performance_schema.%
非常重要的一个要注意的点
在实际项目中,如果要读写分离,必然是多台服务器,但是我们自己本机搭建环境演示完的话,要么搭建多个虚拟机也可以,否则就是只有一台服务器,然后使用容器进行隔离。
如我们目前搭建的服务器,都是我们自己的主机localhost
, 但是localhost
在容器内部和外部确实两个不同的概念。
下面我们会在mysql master创建一个用于同步的账号,授权的时候千万不要授权localhost
,因为这个帐号是在从库里使用的,在从库的容器内localhost
指的是自己了,那么这个用户肯定是不存在的。。。这是在本机搭建环境最最要注意的一个点,一不注意就会被同步时说access deny
搞乱好几天~~
那么现在我们要先获取mysql master这台容器的ip, 用于创建用户授权时指定ip为这台容器的ip, 当然容器的ip最好先创建网络,然后分配固定ip,我们前面已经给每个容器分配了固定ip,这里也可以来检查一下,看下用作master的mysql
docker inspect mysql
# 进入mysql主服务器容器
docker exec -it mysql /bin/bash
# 连接到主机
mysql -uroot -p
# 创建用户, 注意mysql的%是不包含localhost的, 'master_slave_sync'@'%'和'master_slave_sync'@'localhost'会# 被认为是两个用户,如果我们在本机演示用localhost就可,如果不是本机,最好直接使用ip,不必要用%,否则就要创建两
# 个帐号,下面演示是说明确实可以创建两个帐号,而且授权也是一样的道理,%和localhost确实是分开的
CREATE USER 'master_slave_sync'@'%' IDENTIFIED with mysql_native_password BY '123456';
# 还是创建用户, mysql的主机%是不包含localhost的,我们如果只有一个主机演示的话,需要再创建一下localhost
CREATE USER 'master_slave_sync'@'172.20.12.1' IDENTIFIED with mysql_native_password BY '123456';
# 授权
GRANT REPLICATION SLAVE ON *.* TO 'master_slave_sync'@'%';
# mysql授权的%并不包含localhost,如果我们演示使用本机的话,localhost主机也必须给
GRANT REPLICATION SLAVE ON *.* TO 'master_slave_sync'@'172.17.0.4';
# 刷新权限
FLUSH PRIVILEGES;
# 查看节点信息, 会返回当前binlog的日志位置记录点,这个点决定了从库想要从哪里开始同步数据
show master status;
进入从库数据库
-- 暂停同步
stop slave;
-- 重置slave,正常先不要执行
-- 启动slave报错Slave failed to initialize relay log info structure from the repository时使用
reset slave;
-- 指向主库连接信息
-- 修改从库指向到主库,使用上一步master status记录的文件名以及位点
-- 这里有一点需要注意的是,这个文件位置点表示同步的时候从这个点开始同步,那么之前的数据是不会同步的。
-- 所以如果是想要全量同步,请先自行将主库和从库的数据进行一次同步,然后再进行这个操作
CHANGE MASTER TO
master_host = '172.17.0.1',
master_user = 'master_slave_sync',
master_password = '123456',
-- 对应show master status的file
master_log_file = 'mysql-bin.000007',
-- 对应show master status的Position
master_log_pos = 1427;
-- 重启slave
start slave;
-- 查看slave状态
show slave status;
show slave status
请注意查看以下字段是否正常,或者错误原因是什么
注意,下面这个报错,如果排除发现主机和从机的server_id
确实不一致,那么再检查每个服务的有一个配置文件叫auto.conf
,里面有一个server-uuid
可能是一样的,删除这个文件或者更改对应的值即可,这个文件所在目录为mysql的data目录下
Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
前面已经配置好了主从同步配置,所以只要在master
库执行语句即可,slave会自动同步
CREATE DATABASE IF NOT EXISTS `boot-quick` default charset utf8mb4 COLLATE utf8mb4_general_ci;
use `boot-quick`;
DROP TABLE IF EXISTS auth_user;
CREATE TABLE auth_user
(
id BIGINT(20) NOT NULL COMMENT '主键ID' AUTO_INCREMENT,
user_name VARCHAR(30) NOT NULL COMMENT '姓名',
user_token varchar(64) NOT NULL COMMENT '用户随机码,生成密钥的盐,注册时生成且不可变!',
password VARCHAR(32) NOT NULL COMMENT '密码',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
birthday DATE NULL DEFAULT NULL COMMENT '生日',
last_modify_password bigint COMMENT '最后一次修改密码的时间',
last_login_time bigint COMMENT '最后一次使用密码登录的时间',
create_by VARCHAR(32) NULL,
create_time DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
modify_by VARCHAR(32) NULL,
modify_time TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
removed INT NOT NULL DEFAULT 0,
version INT NOT NULL DEFAULT 1,
PRIMARY KEY (id)
);