docker pull nginx
#挂载启动
docker run -it -d \
--name=nginx \
--network=pub_network \
--ip=192.168.10.2 \
-p 80:80 \
-v /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-v /docker/nginx/html:/usr/share/nginx/html \
-v /docker/nginx/logs:/var/log/nginx \
--privileged nginx
docker pull redis
#配置下面内容
# 文件路径:/docker/redis/redis.conf
port 6379
bind *
protected-mode no
daemonize no
pidfile /docker/redis/redis.pid
# 启动
docker run \
-p 6379:6379 \
--name redis \
--privileged=true \
-v /docker/redis/data:/data \
-v /docker/redis/redis.conf:/etc/redis/redis.conf \
-d redis \
redis-server /etc/redis/redis.conf
docker pull mysql:5.7
#配置
#文件 /docker/mysql/conf/my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
# 启动容器
docker run -d -p 3306:3306 \
--privileged=true \
-v /docker/mysql/log:/var/log/mysql \
-v /docker/mysql/data:/var/lib/mysql \
-v /docker/mysql/conf/:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=root \
--name mysql \
mysql:5.7
#进入容器内部
docker exec -it mysql bash
mysql -uroot -proot
#给root开远程权限
grant all privileges on *.* to root@"%" identified by "root";
flush privileges;
#容器内部查看字符集编码
SHOW VARIABLES LIKE 'CHARACTER%';
这里在容器内部查看SHOW VARIABLES LIKE 'CHARACTER%';时要保证字符集编码是utf-8,否则插入中文会显示乱码。

新建主服务器容器实例33061
docker run -p 33061:3306 --name mysql-master \
--privileged=true \
-v /docker/mysql2/mysql-master/log:/var/log/mysql \
-v /docker/mysql2/mysql-master/data:/var/lib/mysql \
-v /docker/mysql2/mysql-master/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
或者(注意:如果配置文件名不是叫my.cnf,而是错写成my.conf,那么上面这种路径映射则无效,此时-v后面的必须指定具体的文件名才生效)
docker run -p 33061:3306 --name mysql-master \
--privileged=true \
-v /docker/mysql2/mysql-master/log:/var/log/mysql \
-v /docker/mysql2/mysql-master/data:/var/lib/mysql \
-v /docker/mysql2/mysql-master/conf/my.conf:/etc/mysql/my.conf \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
如果出现下面问题,通常都是配置文件没有正确读取到。
##
问题一:mysqld: Can't read dir of '/etc/mysql/conf.d/' (Errcode: 2 - No such file or directory)
##
问题二:show variables like 'log_bin';显示的是off则binlog没打开。
准备主服务器配置文件
这里文件名一定一定一定要写成“ my.cnf ”,不能改名字,否则上面-v只能用文件名映射,而不能使用路径映射。
/docker/mysql2/mysql-master/conf/my.cnf
[mysqld]
#设置server_id,统一局域网中需要唯一
server_id=33061
#指定不需要同步的数据库名称
binlog-ignore-db=mysql
#开启二进制日志功能
log-bin=mysql-master.bin
# 设置二进制日志使用的内存大小(事务)
binlog_cache_size=5M
#设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
#二进制日志过期清理时间,默认为0,表示不自动清理
expire_logs_days=7
#跳过主从复制中遇到的所有错误或者指定类型的错误,避免slave端复制中断
# 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
配置文件上传到/docker/mysql2/mysql-master/conf/后,重启容器。docker restart mysql-master
注意:
如果执行show master status;提示的是Empty;这种显示空的记录,则说明没有打开binlog日志。
也可以在mysql客户端中执行show variables like 'log_bin';如果显示off,则也说明binlog没有打开。
那么问题就出现在配置文件my.cnf根本没有加载进来。
在主库内部创建同步用户slave:
create user 'slave'@'%' identified by 'slave';
grant replication slave,replication client on *.* to 'slave'@'%';
登录主库执行SQL:

新建从服务器容器实例33062
docker run -p 33062:3306 --name mysql-slave \
--privileged=true \
-v /docker/mysql2/mysql-slave/log:/var/log/mysql \
-v /docker/mysql2/mysql-slave/data:/var/lib/mysql \
-v /docker/mysql2/mysql-slave/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
准备从服务器配置文件
/docker/mysql2/mysql-slave/conf/my.cnf
[mysqld]
#设置server_id,统一局域网中需要唯一
server_id=33062
#指定不需要同步的数据库名称
binlog-ignore-db=mysql
#开启二进制日志功能
log-bin=mall-mysql-slave.bin
# 设置二进制日志使用的内存大小(事务)
binlog_cache_size=1M
#设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
#二进制日志过期清理时间,默认为0,表示不自动清理
expire_logs_days=7
#跳过主从复制中遇到的所有错误或者指定类型的错误,避免slave端复制中断
# 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
#配置中继日志
relay_log=mall-mysql-relay-bin
# 表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
# slave设置为只读(具有super权限的用户除外)
read_only=1
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
配置文件上传到/docker/mysql2/mysql-slave/conf/后,重启容器。docker restart mysql-slave
登录从库的mysql,执行主从复制语句
# 登录从库容器
docker exec -it mysql-slave bash
# 登录mysql
mysql -uroot -proot
# 执行下面sql,必须为一行
change master to master_host='192.168.80.250',master_user='slave',master_password='slave',master_port=33061,master_log_file='mysql-master.000003',master_log_pos=154,master_connect_retry=30;

主从复制的参数说明:
master_host: 主数据库的IP地址
master_port: 主数据库的端口,这里填映射到容器外面的端口号
master_user:在主数据库创建的用于同步数据的用户账号
master_password:在主数据库创建的用于同步数据的用户密码
master_log_file:指定数据库从哪个日志文件开始复制数据,通过在主库中show master status;获取File参数
master_log_pos:指定数据库从哪个位置开始复制数据,通过在主库中show master status;获取position参数
master_connect_retry: 连接失败重试的时间间隔,单位为秒
在从库的mysql中执行:
# 从库开启主从复制
start slave;
# 查看从库状态
show slave status\G;
从库开启主从复制后的状态如下:

这样就全部完成,后续自己验证。
关于redis的版本上哪查找,从下面这里查看:
https://github.com/docker-library/redis

# 根据上面的截图,可以看到6.2.13版本最近刚更新,所以先拉取redis镜像
docker pull redis:6.2.13
# 然后再启动集群
docker run -d --name redis1 --net host --privileged=true -v /docker/redis-cluster/redis1:/data redis:6.2.13 --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis2 --net host --privileged=true -v /docker/redis-cluster/redis2:/data redis:6.2.13 --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis3 --net host --privileged=true -v /docker/redis-cluster/redis3:/data redis:6.2.13 --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis4 --net host --privileged=true -v /docker/redis-cluster/redis4:/data redis:6.2.13 --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis5 --net host --privileged=true -v /docker/redis-cluster/redis5:/data redis:6.2.13 --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis6 --net host --privileged=true -v /docker/redis-cluster/redis6:/data redis:6.2.13 --cluster-enabled yes --appendonly yes --port 6386

# 先进入任意一个节点
docker exec -it redis1 bash
# 然后执行下面:
redis-cli --cluster create 192.168.80.250:6381 192.168.80.250:6382 192.168.80.250:6383 192.168.80.250:6384 192.168.80.250:6385 192.168.80.250:6386 --cluster-replicas 1
--cluster-replicas 1: 表示每个master创建一个slave节点

一共16384个槽分配给3组主从节点。
6381:0 - 5460
6382:5461 - 10922
6383:10923 - 16383
#随机进入一个容器
docker exec -it redis1 bash
# 进入redis集群
redis-cli -p 6381
# 查看集群信息
cluster info
# 查看集群节点信息
cluster nodes

集群模式下使用redis-cli -p 6381方式登录操作,会出现以下错误
(error) MOVED 12706 192.168.80.250:6383

# 集群模式操作登录要带-c
redis-cli -p 6381 -c

#检查key在槽位的分配
redis-cli --cluster check 192.168.80.250:6381

原来的3主3从,现在需要扩容为4主4从:
新增2个容器节点
docker run -d --name redis7 --net host --privileged=true -v /docker/redis-cluster/redis7:/data redis:6.2.13 --cluster-enabled yes --appendonly yes --port 6387
docker run -d --name redis8 --net host --privileged=true -v /docker/redis-cluster/redis8:/data redis:6.2.13 --cluster-enabled yes --appendonly yes --port 6388
进入redis7内部,设置redis7为主节点
# 进入redis7容器
docker exec -it redis7 bash
# 将新增的redis7作为master节点加入原集群
redis-cli --cluster add-node 192.168.80.250:6387 192.168.80.250:6381
6387作为新增的节点的主节点
6381为原来集群里面的主节点

检查集群状况
redis-cli --cluster check 192.168.80.250:6381

有4个主节点,但是新加主节点并没有分配槽位。
redis-cli --cluster reshard 192.168.80.250:6381
How many slots do you want to move(from 1 to 16384) ? 4096
# 一共需要移动多少个槽位:16384 / 4个节点 = 4096
What is the receiving node ID? 5531025f87a1b01266dcaa4f3981e3092001428c
# 接收槽位的node节点的id号,这里填写M:后面的一串数字
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs
Source node #1: all
# 从哪些节点移动到新增:选择all,所有
Do you want to proceed with the proposed reshard plan (yes/no)? yes
# 生成一个重新分配hash槽的执行计划,输入yes来确认执行
所有选项的截图如下:

确认分配后,集群的信息:

通过分配后的槽位截图可以看到,将已有的槽位上平均移动了槽位到新增的主节点上。
所以在新增的M主节点上看到有3个不同范围的槽位,加起来一共是4096个。
redis-cli --cluster add-node 新IP:新的slave端口 新IP:新的master端口 --cluster-slave --cluster-master-id 新主节点id
参考上面如下:
redis-cli --cluster add-node 192.168.80.250:6388 192.168.80.250:6387 --cluster-slave --cluster-master-id 5531025f87a1b01266dcaa4f3981e3092001428c
# 5531025f87a1b01266dcaa4f3981e3092001428c是主节点6387的编号

最后一次检查集群,4主4从全部分配完毕。

方法:
(1)先清除从节点6388
(2)清除出来的槽号重新分配
(3)再删除6387
(4)恢复3主3从
# 从redis集群删除从节点6388(不是删除容器)
redis-cli --cluster del-node 192.168.80.250:6388 63b1f70509e115940a50600c7c3b9b025646ec8f

# 重新分配槽号
redis-cli --cluster reshard 192.168.80.250:6381
# 移动多少个槽号
How many slots do you want to move (from 1 to 16384)? 4096
# 哪个节点id接收
# 这里不再每个节点都接收了,就用一个节点6381接收4096个,所以填主节点6381的id
What is the receiving node ID? e811feca4e241517851cf49a9ee06263164f2db2
# 从哪个节点转移,这里一定选6387节点的id
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1: 5531025f87a1b01266dcaa4f3981e3092001428c
Source node #2: done
redis-cli --cluster del-node 192.168.80.250:6387 5531025f87a1b01266dcaa4f3981e3092001428c
# 检查节点,又恢复到3主3从了
redis-cli --cluster check 192.168.80.250:6381

在删除节点的过程中,我们将多出来的槽全部分配给了6381,所以可以看到在6381上个有8192个槽位,其余2个节点仍然只有4096个槽位。
当然,也可以平分到6381,6382,6383三个节点上,只是操作起来比较麻烦而已。