原本是选择在自己的云服务器上搭建Docker,但是建集群的时候发现Mysql只能启动一个实例,第二个实例运行后会自动关闭,经过排查发现是渣渣服务器的内存不够支撑多实例。
于是还是借助虚拟机环境来搭建,也能模拟多台服务器安装的情况。
本博客作为记录篇,用于Docker下快速搭建
Tomcat、Mysql、Nginx、Haproxy集群环境
链接:https://pan.baidu.com/s/1zSxo5u_PrJhTuxNqShIvEA
提取码:w2es
官方镜像地址http://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7-x86_64-DVD-1810.iso
一开始我是用Putty连接+WinSCP传输文件,后来发现新的工具XobaXterm功能还挺多的。
和VM一起都放在上面的网盘里了
安装CentOS的虚拟机步骤就不复述了,为方便测试直接选用root账号登录,不嫌麻烦也可以用sudo获取root操作权限。
/-/y是指后续Y/N操作都以Y执行
yum install -y docker
//安装后执行显示版本则成功
docker version
至阿里云 获取镜像加速地址
手动修改/etc/docker/daemon.json为
{
个人的加速地址
}
或者直接执行网址内的shell脚本
//创建网关 避免每次重启ip变化
docker network create --subnet=172.18.0.0/16 mynetwork
//拉取tomcat镜像
docker pull tomcat
//运行普通容器
docker run --name tomcat -d tomcat
//复制webapp出来 因为这个目录不是运行生成的就会直接被覆盖 容器运行后生成的不会被覆盖可以不复制
docker cp tomcat:/usr/local/tomcat/webapps /docker/tomcat/webapps/
//删除容器
docker stop tomcat
docker rm tomcat
//运行正式容器 启动双实例共用webapps
docker run \
-p 12001:8080 \
--restart=always \
--privileged=true \
--name tomcat_02 \
-v /docker/tomcat/tomcat_02/webapps:/usr/local/tomcat/tomcat/webapps \
--network=mynetwork \
--ip 172.18.0.12 \
-d tomcat
//拉取mysql镜像 不加版本默认下最新版
docker pull mysql:5.7.17
//创建配置文件 内容在下面
touch /docker/mysql/conf/my_01.cnf
//创建挂载文件 需要与下面启动配置与my.cnf中配置的对应
配置文件存放路径:/docker/mysql/conf/my.conf
数据文件存放路径:/docker/mysql/data
日志文件存放路径:/docker/mysql/logs
//查看镜像Image_id
docker images
//启动mysql容器 启动失败使用docker logs --tail=30 mysql 查看
//运行正式容器 启动双实例
docker run \
-p 22001:3306 \
--restart=always \
--privileged=true \
--name mysql_02 \
-e MYSQL_ROOT_PASSWORD=123456 \
-v /docker/mysql/mysql_02/conf/my.cnf:/etc/mysql/my.cnf \
-v /docker/mysql/mysql_02/logs:/usr/local/mysql/logs \
-v /docker/mysql/mysql_02/data:/usr/local/mysql/data \
--network=mynetwork \
--ip 172.18.0.22 \
-d mysql
[client]
default-character-set=utf8
port=3306
[mysql]
default-character-set=utf8
[mysqld]
character-set-server=utf8
collation-server=utf8_unicode_ci
datadir=/usr/local/mysql/data
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
[mysqld_safe]
log_error=/usr/local/mysql/logs/mysql_error.log
slow_query_log = 1
#超过1秒则为慢查询
long_query_time = 1
slow_query_log_file = /usr/local/mysql/logs/mysql_slow.log
再通过Navicat进行连接测试
看Mysql版本,可能需要开通远程登录权限,另外如果真实环境使用的话,服务器防火墙及云服务器安全组之类的都需要设置
Nginx主要是web服务器,具备负载均衡LB的功能,多进程模式,社区活跃,然后是因为Nginx在负载均衡下的能力比Haproxy差一点,以及它不支持TCP,要实现Mysql的负载均衡要使用插件,所以后面又使用Haproxy作为负载均衡中间件使用。
//拉取nginx镜像
docker pull nginx
//运行普通容器
docker run --name nginx -d nginx
//复制容器运行必备的配置文件 直接挂载的话会被覆盖成空文件导致运行失败 容器运行后生成的不会被覆盖可以不复制
docker cp nginx:/etc/nginx/nginx.conf /docker/nginx/conf/
//删除容器
docker stop nginx
docker rm nginx
//运行正式容器
docker run \
-p 31001:80 \
--restart=always \
--privileged=true \
--name nginx \
-v /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /docker/nginx/conf/conf.d:/etc/nginx/conf.d \
-v /docker/nginx/html:/usr/share/nginx/html \
-v /docker/nginx/logs:/var/log/nginx \
--network=mynetwork \
--ip 172.18.0.31 \
-d nginx:latest
user nginx;
worker_processes 4; #工作进程数,为CPU的核心数或者两倍
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
use epoll; #Linux最常用支持大并发的事件触发机制
worker_connections 65535;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 120;
#gzip on;
#gzip on;
limit_conn_zone $binary_remote_addr zone=perip:10m; #添加limit_zone,限制同一IP并发数
include /etc/nginx/conf.d/*.conf; #包含nginx虚拟主机配置文件目录
}
upstream test {
ip_hash;
#server 192.168.65.129:18080 weight=1;#根据上面IIS配置
#server 192.168.65.129:18081 weight=1;#根据上面IIS配置
server 172.18.0.3:8080 weight=1;
server 172.18.0.2:8080 weight=1;
}
server {
listen 80;
server_name localhost;
#charset GB2312;
location /
{
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://test;
}
# 查看nginx的并发连接数配置
location /NginxStatus
{
stub_status on;
access_log off;
auth_basic "NginxStatus";
}
access_log off;
error_page 404 /404.html;
error_page 500 502 503 504 /404.html;
location = /404.html {
root html;
}
limit_conn perip 200; #同一ip并发数为200,超过会返回503
}
//拉取haproxy镜像
docker pull haproxy
//创建配置文件 内容往下
touch /docker/haproxy/config/haproxy.cfg
//运行正式实例 同样创建多个实例 这里挂载的keepalived后续使用
docker run \
-p 32001:8888 -p 32002:3306 \
--restart=always \
--privileged=true \
--name haproxy_02 \
-v /docker/haproxy/haproxy_02/config:/usr/local/etc/haproxy \
-v /docker/haproxy/haproxy_02/keepalived.conf:/etc/keepalived/keepalived.conf \
--network=mynetwork \
--ip 172.18.0.32 \
-d haproxy
需要在MySQL中创建一个没有权限的haproxy用户,密码为空。Haproxy使用这个账户对MySQL数据库心跳检测,用户名可在配置文件中配置
global
#工作目录
chroot /usr/local/etc/haproxy
#日志文件,使用rsyslog服务中local5日志设备(/var/log/local5),等级info
log 127.0.0.1 local5 info
#守护进程运行
daemon
defaults
log global
mode http
#日志格式
option httplog
#日志中不记录负载均衡的心跳检测记录
option dontlognull
#连接超时(毫秒)
timeout connect 5000
#客户端超时(毫秒)
timeout client 50000
#服务器超时(毫秒)
timeout server 50000
#监控界面
listen admin_stats
#监控界面的访问的IP和端口
bind 0.0.0.0:8888
#访问协议
mode http
#登录的URI相对地址
stats uri /
#统计报告格式
stats realm Global\ statistics
#登陆帐户信息
stats auth test:test
#数据库负载均衡
listen proxy-mysql
#访问的IP和端口(前面ip=0代表任何ip都可访问)
bind 0.0.0.0:3306
#网络协议
mode tcp
#负载均衡算法(轮询算法)
#轮询算法:roundrobin
#权重算法:static-rr
#最少连接算法:leastconn
#请求源IP算法:source
balance roundrobin
#日志格式
option tcplog
#在MySQL中创建一个没有权限的haproxy用户,密码为空。Haproxy使用这个账户对MySQL数据库心跳检测
option mysql-check user haproxy
server NODE1 172.18.0.21:3306 check weight 1 maxconn 2000
server NODE2 172.18.0.21:3306 check weight 1 maxconn 2000
#使用keepalive检测死链
option tcpka
打开监控界面正常
然后通过Navicat连接Haproxy去查数据库就会发现查询结果是在两个数据库之间按权值跳跃的。
keepalived的实现是要在docker服务内创建,所以要进入各自的宿主机进行安装
//进入容器
docker exec -it haproxy_01 bash
//安装keepalived
apt-get update
apt-get -y install keepalived
//配置文件在haproxy的时候映射过,这里就不创建了 内容在下面有
//开启keepalived
service keepalived start
//安装ping
apt-get install iputils-ping
//ip a 查看是否加入网卡 如果存在的话会显示keepalived配置的ip
ip a
//容器及宿主机各自都测试是否连通
ping 172.18.0.100
各自的容器和各自的keepalived都ping通后,宿主机也需要安装keepalived,宿主机的keepalived只是作为一个中转,因为外部Ip是没法直接访问到容器内部keepalived生成的vip的。
//宿主机安装keepalived
yum install -y keepalived
//修改配置文件/etc/keepalived 在下面有
//开启keepalived
service keepalived start
//然后ping虚拟ip 如果ping通而在外部网络不能访问 有防火墙就开端口 有安全组就设置白名单
多个容器的配置完全一样,但是要保证他们相互都能Ping通
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 100
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
172.18.0.100
}
}
vrrp_instance VI_1 {
state MASTER
#这里是宿主机的网卡,可以通过ip a查看当前自己电脑上用的网卡名是哪个
interface ens33
virtual_router_id 100
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
#这里是指定的一个宿主机上的虚拟ip,要外部能访问到的,作为中转连接至容器内keepalived172.18.0.100
192.168.65.222
}
}
#接受监听数据来源的端口,网页入口使用
virtual_server 192.168.65.222 8888 {
delay_loop 3
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
#haproxy的对应ip端口
real_server 172.18.0.100 8888 {
weight 1
}
}
#接受监听数据来源的端口,数据库使用
virtual_server 192.168.65.222 3306 {
delay_loop 3
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
#haproxy的对应ip端口
real_server 172.18.0.100 3306 {
weight 1
}
}
首先,通过VM的克隆生成一个新的虚拟机,并运行Docker与Mysql。
或者直接用上述容器生成指令生成多个不同端口Mysql容器
然后在找资料的过程发现Mysql集群方案实在是有点多,一时不知道做哪种方案。
1.master上将操作记录到二进制bin-log里面去
2.slaves读取bin-log日志到本地的中继日志relay-log
3.slaves执行relay-log里的事件
1.基于语句的复制: 在主服务器上执行的SQL语句,在从服务器上执行同样的语句。MySQL默认采用基于语句的复制,效率比较高。一旦发现没法精确复制时, 会自动选着基于行的复制。
2.基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍。从mysql5.0开始支持。
3.混合类型的复制: 默认采用基于语句的复制,一旦发现基于语句的无法精确的复制时,就会采用基于行的复制。
和redis的aof有点类似
vi /etc/my.cnf 如果是docker容器修改挂载文件即可
[mysqld]
server-id=1 #这个id全局唯一,slaves上的id不能与之冲突
log-bin=mysql-bin #必须开启二进制日志功能
重启数据库并进入执行语句
GRANT REPLICATION SLAVE ON *.* to 'test'@'%' identified by '123456'; #创建一个同步账户,用来同步数据用
flush privileges;
show master status;#记下数据内容file和position 要再slave中用
#这里可以锁住所有表来防止slave部署过程中的修改,但是部署好最后要记得解锁
vi /etc/my.cnf 如果是docker容器修改挂载文件即可
[mysqld]
server-id=2 #这个id,全局唯一,不能与master,或者其他slaves冲突
log-bin=mysql-bin #slaves上没有必要开启bin-log功能,当slave作为其他slave的master时除外
#binlog-do-db=databasename1,databasename2 #这个参数是指定需要复制的数据库名字,默认复制所有
#binlog-ignore-db=databasename1,databasename2 #这个参数是指定不需要复制的数据库名字
重启数据库并进入执行语句
#stop SLAVE;
change master to
master_host='192.168.65.129',#如果是同服务器Docker部署的就使用服务器内部IP与端口
master_port=9001,
master_user='test',
master_password='123456',
master_log_file='mysql-bin.000007',#上面记录的值
master_log_pos=311;#上面记录的值
start SLAVE;
show slave status;
非常关键 如果是采用VM复制的虚拟机,要修改宿主机挂载文件的/docker/mysql/data_01/auth.cnf的id,这个id不能重复,或者进容器内find / -name "auto.cnf"再修改,不过要安装vim比较麻烦
如果Slave_Sql_Running是NO,可以尝试执行
stop slave ;
set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
start slave ;
show slave STATUS;
总而言之,如果运行失败一定要去看日志文件
docker logs -f --tail=30 mysql01
测试了同服务器不同docker容器及不同服务器下的集群
192.168.65.129_9001
192.168.65.129_9002
192.168.65.130_9001
注意
服务器内部使用docker连接的话需要使用内部的IP及容器内部端口
服务器之间则直接使用外部IP与外部端口
docker pull percona/percona-xtradb-cluster
//创建挂载目录
docker volume rm v1
docker volume rm v2
docker volume rm v3
docker volume create --name v1
docker volume create --name v2
docker volume create --name v3
//查看目录
docker volume inspect v1
//创建网络
docker network create --subnet=172.19.0.0/24 pxc
//开防火墙
firewall-cmd --zone=public --add-port=3301/tcp --permanent
firewall-cmd --zone=public --add-port=3302/tcp --permanent
firewall-cmd --reload
docker run \
-p 3301:3306 \
--name=node1 \
--privileged=true \
-e CLUSTER_NAME=cluster1 \
-e MYSQL_ROOT_PASSWORD=root \
-e XTRABACKUP_PASSWORD=root \
--net=pxc \
--ip 172.19.0.2 \
-d pxc
docker run \
-p 3302:3306 \
--name=node2 \
--privileged=true \
-e CLUSTER_NAME=cluster1 \
-e MYSQL_ROOT_PASSWORD=root \
-e XTRABACKUP_PASSWORD=root \
-e CLUSTER_JOIN=node1 \
--net=pxc \
--ip 172.19.0.3 \
-d pxc