先记录下遇到的坑,避免之后忘了;
花时间最多去解决的一个题是:在docker下启动haproxy服务后在这个docker服务内安装keepalived无法ping通的问题,虽然最后也是莫名其妙就好了,但是加强了不少对docker的理解和还需深入学习的地方。
为什么要用keepalived+haproxy实现docker下的高可用负载均衡?在不同环境下有哪些方式可以实现高可用负载均衡?
首先第一点,实现负载均衡并不是只有haproxy一个中间件,网上还有很多方案是用keepalived+LVS等等,所以对于docker下的高可用负载均衡不一定只有keepalived+haproxy。只是本次我是基于之前搭建的pxc集群进行继续搭建的,所以用的是haproxy。
为什么这里强调的是docker、keepalived?
首先我们运行环境是docker,keepalived的作用是抢占虚拟ip,docker环境下,镜像内的网段外网是无法访问的,所以我们需要一个外网在宿主机上映射到docker内的ip上,keepalived一方面可以映射ip到docker服务内,二可以在docker服务内强占虚拟ip。所以在docker搭建负载均衡的多种方案中都常见会出现keepalived。
为什么要抢占虚拟ip?为什么要用keepalived呢?
负载均衡中间件(haproxy,lvs)等等在实际中不可能只是单节点存在(单节点不需要keepalived),都要有冗余设计,即集群设计,和数据库集群不一样的是,docker中实现负载均衡中间件的集群是通过抢占一个ip地址实现的,有主备和主主方式,虽然方式不一样,但都有一个心跳检测的共同点,在主节点抢占虚拟ip时,主从节点上会有心跳检测线,如果发现主节点心跳检测连不上,则从节点会主动抢占ip实现数据不中断的冗余机制;
总结描述:由于是在docker环境下,我们要搭建负载均衡集群需要通过keepalived抢占虚拟ip实现,而负载均衡功能需要haproxy中间件实现,所以本次我搭建的是一个在docker环境下高可用的负载均衡方案是:keepalived+haproxy。
haproxy具体方法:
下载docker镜像;
Docker pull haproxy
重命名
docker tag docker.io/haproxy haproxy
删除多余镜像
docker rmi docker.io/haproxy
ftp上传docker配置文件,目录自行定义,目录映射根据定义目录名映射
查看配置文件(需要编辑可编辑)
cat haproxy.cfg
启动创建docker-haproxy服务
docker run -it -d -p 4001:8888 -p 4002:3306 -v /data/haproxy/config:/usr/local/etc/haproxy --name haproxy01 --privileged --net=net1 --ip 172.20.0.07 haproxy
端口8888是监控页面端口,3006是MySQL服务端口,参数都可以在配置文件中调整
进入docker-haproxy服务
docker exec -it haproxy01 /bin/bash
启用配置文件(启用完配置文件才算是真的启动了haproxy服务)
haproxy -f /usr/local/etc/haproxy/haproxy.cfg
退出haproxy交互,回到宿主机
ctrl+D
haproxy配置信息:
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 /dbs
#统计报告格式
stats realm Global\ statistics
#登陆帐户信息
stats auth admin:abc123456
#数据库负载均衡
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.20.0.2:3306 check weight 1 maxconn 2000
server NODE2 172.20.0.3:3306 check weight 1 maxconn 2000
server NODE3 172.20.0.4:3306 check weight 1 maxconn 2000
server NODE4 172.20.0.5:3306 check weight 1 maxconn 2000
server NODE5 172.18.0.6:3306 check weight 1 maxconn 2000
#使用keepalive检测死链
option tcpka
要解释配置文件真的可以写个单独的说明,我这里只说下链接数据库的几点,即option参数后面的;
NODE1+ip这个是指的PXC集群的docker镜像名和所制定的ip地址,这个要和数据库集群一致,后面的权重,最大链接数可以执行设置,也可以直接套用我的,其他的说明配置文件中都有;可直接使用;最后在网页上输入宿主机IP+监控端口+/dbs即可进入监控页面。
监控界面:
keepalived搭建:
keepalived的实现是要在docker服务内创建,最后宿主机中也要创建实现docker内外的连接;
docker服务内创建,我们需要进入到该服务并安装keepalived
进入docker-haproxy服务
docker exec -it haproxy01 /bin/bash
更新update,安装keepalived
apt-get update
apt-get install keepalived
安装vim 安装ifconfig命令 安装ping
apt-get install net-tools
apt-get install iputils-ping
新建并写入一个keepalived的配置文件
vim /etc/keepalived/keepalived.conf
配置文件信息:
#取名为K1,可自定义
vrrp_instance VI_1 {
#定义节点属性
state MASTER
#定义虚拟网卡
interface eth0
#定义组vriid
virtual_router_id 100
#定义权重
priority 100
#定义心跳检测时间1秒
advert_int 1
#定义组用户密码
authentication {
auth_type PASS
auth_pass 123456
}
#定义docker内ip地址,必须要在和haproxy同一个网段
virtual_ipaddress {
172.20.0.100
}
}
启动
service keepalived start
到这一步理论上就完事了,只需要在新建一个haproxy+keepalived组成集群即可,在这里我遇到一个坑是:
启动keepalived后宿主机无法ping通用keepalived,报错:
[root@centos7 ~]# ping 172.20.0.100
PING 172.20.0.100 (172.20.0.100) 56(84) bytes of data.
From 172.20.0.100 icmp_seq=1 Destination Host Unreachable
From 172.20.0.100 icmp_seq=2 Destination Host Unreachable
解决方案:
大多数都是我把配置文件没写对,重写配置文件,重启服务;
这里检查能否ping通,需要看服务内你的配置文件写入的ip有没有出现在docker的网卡上,具体方法是:
进入到docker服务内,不是在宿主机上哦,查看配置文件
root@8351443065ea:/etc/keepalived# cat keepalived.conf
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.20.0.100
}
}
如果配置文件信息都是正确的,通过ip a命令会显示如当前docker服务有的网卡
root@8351443065ea:/etc/keepalived# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
73: eth0@if74: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:14:00:07 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.20.0.7/24 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe14:7/64 scope link
valid_lft forever preferred_lft forever
很明显没有我配置文件中的172.20.0.100ip地址,代表配置文件未生效,大多数配置文件错误
停掉keepalived服务重新修改编辑后重启
root@8351443065ea:/etc/keepalived# service keepalived stop
[ ok ] Stopping keepalived: keepalived.
重启服务
root@8351443065ea:/etc/keepalived# service keepalived start
[ ok ] Starting keepalived: keepalived.
再次查看docker服务的ip
root@8351443065ea:/etc/keepalived# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
73: eth0@if74: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:14:00:07 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.20.0.7/24 scope global eth0
valid_lft forever preferred_lft forever
这里出现了我的配置文件ip地址
inet 172.20.0.100/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe14:7/64 scope link
valid_lft forever preferred_lft forever
在服务内直接ping这个ip,发现能ping通,切换宿主机,也能ping通,解决问题
root@8351443065ea:/etc/keepalived# ping 172.20.0.100
PING 172.20.0.100 (172.20.0.100) 56(84) bytes of data.
64 bytes from 172.20.0.100: icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from 172.20.0.100: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 172.20.0.100: icmp_seq=3 ttl=64 time=0.060 ms
^C
最后,再新建一个haproxy再添加slave的keepalive,加入到master中,即完成负载均衡集群的搭建。
新建第二个haproxy容器的配置文件和第一个容器是一样的,需要注意的地方是,在docker run新建容器的时候,由于4001,4002端口和ip都被占用了,所以在run的时候要指定未使用的新端口和ip,比如4003,4004端口等等;
第二个keepalived的配置文件和第一个配置文件完全一样,如果想要分配不同的权重比列,只需要更改权重参数就可以了。
最后,本地宿主机安装keepalived进行外网路由:
宿主机操作:
安装keepalived
yum install -y keepalived
安装完后配置文件本省有自带的在,/etc/keepalived文件夹中,通过ftp替换掉这个配置文件
宿主机KP配置文件信息:
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,一定要和宿主机网卡在同一个网段,我的宿主机网卡ip是192.168.1.85,所以指定虚拟ip是给的90
192.168.1.90
}
}
#接受监听数据来源的端口,网页入口使用
virtual_server 192.168.1.90 8888 {
delay_loop 3
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
#把接受到的数据转发给docker服务的网段及端口,由于是发给docker服务,所以和docker服务数据要一致
real_server 172.20.0.100 8888 {
weight 1
}
}
#接受数据库数据端口,宿主机数据库端口是3306,所以这里也要和宿主机数据接受端口一致
virtual_server 192.168.1.90 3306 {
delay_loop 3
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP
#同理转发数据库给服务的端口和ip要求和docker服务中的数据一致
real_server 172.20.0.100 3306 {
weight 1
}
}
配置完后,通过命令service keepalived start启动宿主机的KP,通过ip a查看网卡中是否出现定义的90 IP地址,如果没有出现大多数是配置文件不正确。
通过ping 90ip地址,发现能够ping通
切换到windows上,进入cmd ping宿主机90ip地址发现能ping通,通过浏览器输入
http://192.168.1.90:8888/dbs
进入到监听页面:
到此实现了外网访问的负载均衡集群搭建。
在此如果cmd能ping通90ip 而网页无法进入监听界面,问题出现在防火墙上,centos7默认防火墙是没有开启开启vrrp 协议,而keepalived用的是vrrp协议,所以要么让防火强开通vrrp协议,命令:
执行命令1
firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface em1 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
执行命令2
firewall-cmd --reload
或者直接关闭防火墙:
systemctl stop firewalld.service
以上防火墙命令只针对于centos7的firewalld,其他防火墙或者linux版本可以自行百度让vrrp协议能够使用即能让网页进入到监听界面。
最后通过navicat链接进行验证:
HA链接的是宿主机90 IP 的3306端口进入MySQL服务,代表总keepalived,
H1,H2是链接宿主机85 IP的4002、4004端口进入MySQL服务,代表HA单节点
PXC各节点是链接宿主机85 IP的3307、3308、3309等端口代表PXC集群各个单节点
测试:
手动关掉PXC部分节点,监控界面观察H1、H2,出现集群预警,正常PXC节点写入数据,发现能正常写入。PXC集群成功。
手动关掉H1或H2、通过HA观察,发现正常,在通过navicat链接关掉的HA单节点,发现无法链接,二HA 能正常写入,代表HA集群搭建成功。
以上,实现了高可用的MySQL数据库集群及其负载均衡。
还没解决的问题:
虽然目前通过调整配置文件ping通了keepalived,但是这也只是偶然猜测出来的一个解决方案,其实我本来希望是通过docker logs去查看服务报错信息确定具体问题出现在哪里,但是使用docker logs后发现,这个日志查询命令只能查看haproxy容器的日志,我在haproxy中安装了keepalived之后,keepalived的日志没有办法查看,目前还没有找到一个简单易懂能查看docker服务内独立应用的日志方法,这里还需要继续深入学习。