美文网首页
Docker搭建多机多节点haproxy+keepalived负

Docker搭建多机多节点haproxy+keepalived负

作者: 一只神奇的小绵羊 | 来源:发表于2019-11-19 11:39 被阅读0次

    本文为多宿主搭建,单机搭建可参考下方文章
    https://www.cnblogs.com/CaesarLinsa/p/11037613.html

      坑很多,配置要求比较严苛,请注意

      多物理机搭建最大的问题是,默认bridge网络模式下docker容器使用的是bridge按照DHCP协议动态分配的子网IP,容器是虚拟网络容器,相对于外部网络是隔离的,所以无法通过hosts解析到外部IP,也无从连接其他mq节点

    多宿主集群当前已知的搭建模式有:
    ① host的网络模式(- -net host)
    ② 插件(Calico flannel weave Docker Overlay)
    ③ overlay的网络模式
    ④ 内网DNS服务器提供域名解析

      这里提供host网络模式的集群搭建,以两台物理机为例,网络环境为内网

    172.16.22.72 (主机)
    172.16.22.59 (备机)
    172.16.22.240(VIP)
    

    (零)、架构图

    image

    (一)、创建MQ容器

      两种方法均可,均为增加hosts映射关系进行节点寻址,最终产出相同。建议采用方法一 ,后续节点扩增更灵活

    • 方法一

    1.创建hosts
    两台机器都创建/opt/rabbitmq目录,然后在rabbitmq目录下创建hosts文件

    mkdir /opt/rabbitmq
    cd /opt/rabbitmq
    vi hosts
    
    #ip            真实主机hostname(如果主机名为localhost会有一点问题,建议更改)
    172.16.22.72   support
    172.16.22.59   hr02
    

    2.运行容器
    当docker发现本地没有 rabbitmq:management 的镜像时会主动从仓库拉取,management 为带有管理页面的版本

    #172.16.22.72
    docker run -d --net host --name rabbit1  -v /opt/rabbitmq:/var/lib/rabbitmq:z  -v /opt/rabbitmq/hosts:/etc/hosts -e RABBITMQ_ERLANG_COOKIE='RABBITMQ'  rabbitmq:management
    
    #172.16.22.59
    docker run -d --net host --name rabbit2  -v /opt/rabbitmq:/var/lib/rabbitmq:z  -v /opt/rabbitmq/hosts:/etc/hosts -e RABBITMQ_ERLANG_COOKIE='RABBITMQ'  rabbitmq:management
    
    • 方法二
    #172.16.22.72
    docker run -d --net host --name rabbit1 --add-host=support:172.16.22.72 --add-host=hr02:172.16.22.59 -e RABBITMQ_ERLANG_COOKIE='RABBITMQ'  rabbitmq:management
    
    #172.16.22.59
    docker run -d --net host --name rabbit2 --add-host=support:172.16.22.72 --add-host=hr02:172.16.22.59 -e RABBITMQ_ERLANG_COOKIE='RABBITMQ'  rabbitmq:management
    

      【可选】

      如果要将文件映射到宿主机方便以后迁移备份,可以添加文件映射命令如下。要注意,添加映射后不会开启管理页面的插件,需要进入容器手动启用插件,原因尚未探寻

    #etc存放配置,lib存放数据库,log存放日志
    -v /home/rabbitmq/etc/rabbitmq:/etc/rabbitmq -v /home/rabbitmq/lib/rabbitmq:/var/lib/rabbitmq ->v /home/rabbitmq/log/rabbitmq:/var/log/rabbitmq
    

      开启插件

    docker exec -it rabbit1 /bin/bash
    rabbitmq-plugins enable rabbitmq_management
    

      【解释】

    #采用host的网络模式
    --net host
    #容器命名为rabbit1
    --name rabbit1  
    #将宿主机的/opt/rabbitmq目录映射到容器中的/var/lib/rabbitmq目录,
    #z是一个标记,在selinux环境下使用
    -v /opt/rabbitmq:/var/lib/rabbitmq:z  
    #设置env 环境变量。这里的cookie可以为任意值,所有节点保持一致即可
    -e RABBITMQ_ERLANG_COOKIE='RABBITMQ'
    #增加host
    --add-host=support:172.16.22.72
    

    (二)、搭建集群

      将除了第一个节点外的其他节点加入第一个节点,每个节点都执行如下命令。加入节点时,
    加上--ram 命令则为创建内存节点,不加为硬盘节点

    #进入容器
    docker exec -it rabbit2 /bin/bash
    #关闭应用
    rabbitmqctl stop_app
    #清除所有队列
    rabbitmqctl reset
    #加入节点
    rabbitmqctl join_cluster --ram rabbit@support
    #启动应用
    rabbitmqctl start_app
    #查看集群状态
    rabbitmqctl cluster_status
    #【备用】从rabbit@support主节点上移除rabbit@hr02节点
    rabbitmqctl -n rabbit@support forget_cluster_node rabbit@hr02
    
    image
      【补充】:
    tcp4369端口用于集群邻居发现;
    tcp5671,5672端口用于AMQP 0.9.1 and 1.0 clients使用;
    tcp15672端口用于http api与rabbitadmin访问,后者仅限在management plugin开启时;
    tcp25672端口用于erlang分布式节点/工具通信
    

      【个人理解】:
      ① 节点的全称默认为 【节点名字@主机名称】
      ② 假定节点2(hr02)要加入的节点1的全称是【rabbit@support】,rabbitmq首先会在同一网段/桥下寻找是否存在该节点,如果不存在,会在节点2配置的hosts中寻找support对应的ip,通过4369端口进行连接。如果连接成功,节点2会告知对方,节点2想要连接的对方的节点的名称是【rabbit@support】,对方则会按照【rabbit@support】的全名在本地进行节点搜索
      ③ 如果节点1的主机名称为localhost,那即使在节点2的hosts配置了【support - 目标ip】的映射关系,在节点1也无法搜索到【rabbit@support】这个节点,因为节点1的真实节点名称是【rabbit@localhost】

      【节点操作】:
    删除集群中的节点:
    ①进入待删除节点容器
    ②停止节点 rabbitmqctl stop_app
    ③进入主节点容器删除待删除节点 rabbitmqctl forget_cluster_node node_name

    增加集群中的节点:
    ①进入待增加节点容器
    ②清除数据 rabbitmqctl reset
    ③加入集群 rabbitmqctl join_cluster 主节点名称
    ④启动节点 rabbitmqctl start_app

    (三)、部署Haproxy

      第三、四步的目的是创建主备haproxy和主备对应的监测kp,重点依旧是网络IP配置及VIP创建。
      ha安装没什么好说的。kp装在宿主机、单独容器或ha容器都可以,只不过如果要装在ha容器或单独容器内要用host网络模式且容器运行的时候加- -privileged参数,否则对VIP有影响;如果kp是装在宿主机上,ha用什么网络模式都可以,kp只是一个全端口转发。
      建议将kp装在ha容器内,方便通过脚本监控ha的存活状态。

      1.编辑haproxy配置文件如下:

    mkdir /home/haproxy
    vi /home/haproxy/haproxy.cfg
    
    global
      daemon
      maxconn 10000
      #日志输出配置,所有日志都记录在本机,以local0的日志级别(系统不可用)输出
      #local0~local7
      # emerg 0-系统不可用      alert 1-必须马上采取行动的事件
      # crit 2-关键的事件       err 3-错误事件
      # warning 4-警告事件      notice 5-普通但重要的事件
      # info 6-有用的信息       debug 7-调试信息
     log 127.0.0.1 local0 info
    
    defaults
      mode http
      #应用全局的日志配置
      log global
      #超时配置
      timeout connect 5000ms
      timeout client 5000ms
      timeout server 5000ms
      timeout check 2000ms
    
    #负载均衡的名字(自定义)
    #监听5666端口并转发到rabbitmq服务
    listen rabbitmq_cluster
      bind 0.0.0.0:5666#对外提供的虚拟的端口
      option tcplog
      mode tcp
      #负载均衡算法为轮询
      balance roundrobin
      #对后端服务器的健康状况检查间隔为2000毫秒,
      #连续2次健康检查成功,则认为是有效的,连续3次健康检查失败,则认为服务器宕机
      server rabbit1 172.16.22.72:5672 check inter 5000ms rise 2 fall 3
      server rabbit2 172.16.22.59:5672 check inter 5000ms rise 2 fall 3
    
    #haproxy的客户页面
    listen http_front 
      bind 0.0.0.0:25666
      stats uri /haproxy #页面地址
      #页面的用户名和密码,建议主备设为不同,方便确定抢占到VIP的服务器是主机还是备机
      stats auth root:ruijie 
      stats admin if TRUE #管理界面,成功登陆后可通过webui管理节点
    
    #rabbit管理页面,监听15666端口转发到rabbitmq的客户端
    listen rabbitmq_admin 
      bind 0.0.0.0:15666
      server rabbit1 172.16.22.72:15672 check inter 5000ms rise 2 fall 3
      server rabbit2 172.16.22.59:15672 check inter 5000ms rise 2 fall 3
    

      2.创建haproxy容器
      这里采用host模式进行创建,使用宿主机的网卡,否则KP创建的VIP是容器内VIP而不是容器外VIP

    #-v 中的参数:ro表示read only,宿主文件为只读。如果不加此参数默认为rw,即允许容器对宿主文件的读写
    #一定要添加--privileged参数,使用该参数,container内的root拥有真正的root权限。
    #否则,container内的root只是外部的一个普通用户权限(无法创建网卡)
    docker run -d --name cluster-rabbit-haproxy --privileged --net host -v /home/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro haproxy
    

      3.在备机上以同样的配置和命令创建一台备份haproxy

    (四)、安装keepalived

      这里采用的方式是将kp安装在haproxy容器内

    1.进入haproxy容器

    docker exec -it cluster-rabbit-haproxy /bin/bash
    

    2.更新,安装keepalived

    apt-get update
    apt-get install keepalived
    

    3.安装ifconfig,安装ping,安装vim,安装ps

    apt-get install net-tools
    apt-get install iputils-ping
    apt-get install vim
    apt-get install procps
    

    4.创建kp配置文件

    vi /etc/keepalived/keepalived.conf
    
    #keepalived配置文件
    global_defs {
        router_id NodeA                 #路由ID, 主备的ID不能相同
        notification_email {
            xxx@xxx.com
        }
        notification_email_from xxx@xxx.com
        smtp_server 127.0.0.1
        smtp_connect_timeout 30
        vrrp_skip_check_adv_addr
        #在keepalived的服务器上配合使用nginx或haproxy时,需要把这一项注掉,否则VIP ping不通,80端口也无法正常访问
        # vrrp_strict 
        vrrp_garp_interval 0
        vrrp_gna_interval 0
    }
    
    #自定义监控脚本
    vrrp_script chk_haproxy {
            script "/etc/keepalived/check_haproxy.sh"
            interval 5
            weight 2
    }
    
    vrrp_instance VI_1 {
            state MASTER #Master为主机,备机设为BACKUP
            interface ens160        #指定网卡(宿主机真实网卡,ip a查看)
            virtual_router_id 1
            priority 100            #优先级,BACKUP机器上的优先级要小于这个值
            advert_int 1            #设置主备之间的检查时间,单位为s
            authentication {        #定义验证类型和密码,主备需相同
                    auth_type PASS
                    auth_pass ruijie
            }
            track_script {
                    chk_haproxy     #ha存活监控脚本
            }
            virtual_ipaddress {     #VIP地址,可为多个。如果有需要可以部署双机双VIP
               172.16.22.240
            }
    }
    

      【补充】关于双机双VIP(参考@dloux_zc)
      A B 双机, 正常情况下A绑定vip1, B绑定vip2;顶层通过dns解析将不同的域名分别指向其中一个vip, 以充分利用服务器资源;
      在发生故障时,A或B上同时绑定两个VIP。
      在大流量的情况下不建议这么用,如果AB 都接近满载,一旦发生故障,其中一台的流量全部导到另一台,可能很快将另一台服务器也压崩。
      仅作测试及小流量情况又不想浪费备机资源的情况下使用。

      5.配置监控脚本

    vi /etc/keepalived/check_haproxy.sh
    
    #!/bin/bash
    if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ];then
            haproxy -f /usr/local/etc/haproxy/haproxy.cfg
    fi
    sleep 2
    if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ];then
            #service keepalived stop
            /etc/init.d/keepalived stop
    fi
    

      6.启动

    service keepalived start
    

      7.查看配置是否成功

    ip a
    

      使用的网卡出现虚拟ip,则为配置成功


    image

      注:ha容器重启之后kp不会自动重启

      至此,高可用的MQ集群已经搭建完毕,对外暴露5666端口进行MQ通信,15666端口进行MQ可视化管理,ip:25666/haproxy地址进行ha管理

    (五)、配置镜像队列(可选)

      增加一条策略即可

    image
      Name为自定义名称;Pattern为正则匹配,^为匹配全部;Definition为具体策略与规则,ha-mode配置高可用模式,all为全部
    image
      队列只能定义在一个节点上,普通模式队列仅存在于一个节点,镜像模式队列存在于所有节点,+1表示额外存在的队列数。如果是+2就表示在另外两个节点也存在此队列,即存在另外两个节点
    image

    (六)、测试

      访问haproxy的管理页面: http://172.16.22.240:25666/haproxy
      连接rabbitmq 的5666端口并发送数据,可以在此页面,对每次的请求转发进行监控

    image
      访问rabbitmq的客户端: http://172.16.22.240:15666
      该页面为ha对mq集群的轮询访问
    image

    (七)、连接异常的问题处理

    参考: https://www.cnblogs.com/xishuai/p/rabbitmq-and-haproxy-channel-shutdown-connection-error.html

      SpringBoot连接集群可能会有 Channel shutdown: connection error 连接错误的问题,
    报错信息如下:

    2019-11-18 16:55:23 INFO o.s.a.r.l.SimpleMessageListenerContainer: Restarting Consumer@7925e772: tags=[[amq.ctag-NKT1PBwEVFNlR6zlAklF4A, amq.ctag-QHdxvp2TeHV-7d26AonMPA]], channel=Cached Rabbit Channel: AMQChannel(amqp://guest@172.16.22.240:5666/AS_System_Event,2), conn: Proxy@fe156f4 Shared Rabbit Connection: SimpleConnection@bb21063 [delegate=amqp://guest@172.16.22.240:5666/AS_System_Event, localPort= 61176], acknowledgeMode=MANUAL local queue size=0
    2019-11-18 16:55:23 INFO       o.s.a.r.c.CachingConnectionFactory: Attempting to connect to: [172.16.22.240:5666]
    2019-11-18 16:55:23 INFO       o.s.a.r.c.CachingConnectionFactory: Created new connection: connectionFactory#68c4a860:1/SimpleConnection@f36276b [delegate=amqp://guest@172.16.22.240:5666/AS_System_Event, localPort= 61190]
    2019-11-18 16:55:27 ERROR      o.s.a.r.c.CachingConnectionFactory: Channel shutdown: connection error
    

      从红框可以看得出来,springboot一直在重复【重启消费者——连接服务端——创建新连接——连接异常】,而绿框则为轮询请求的两个服务端。参考链接文章确定问题为客户端连接超时:

      为什么会出现此问题呢?因为 HAProxy 配置了客户端连接超时参数 timeout client ms,如果客户端连接超过配置的此参数,那么 HAProxy 将会删除这个客户端连接。
      RabbitMQ 客户端使用永久连接到代理,从不超时,那为什么还会出现问题?因为如果 RabbitMQ 在一段时间内处于非活动状态,那么 HAProxy 将自动关闭连接

    image

    引用原文:

    image
    说了那么多,我们该怎么解决此问题呢?
    两种方案:
    ① 修改系统的tcp_keepalive_time配置,间隔时间低于 HAProxy 配置的timeout client超时时间(因为有可能影响其他系统服务,不推荐)。
    ② 修改 HAProxy 中的timeout client超时时间,配置大于系统的tcp_keepalive_time间隔时间(推荐)。因为系统tcp_keepalive_time发送TCP keepalive数据包间隔时间是 2 个小时,所以,我们将 HAProxy 中的timeout client超时时间,设置为 3 个小时

    配置文件完整示例:

    global
      daemon
      ...
    
    defaults
      ...
    
    listen rabbitmq_cluster
       bind 0.0.0.0:5666
      option tcplog
      timeout client  3h
      timeout server  3h
      mode tcp
      balance roundrobin
      server rabbit1 172.16.22.72:5672 check inter 5000ms rise 2 fall 3
      server rabbit2 172.16.22.59:5672 check inter 5000ms rise 2 fall 3
    
    listen http_front 
      ...
    
    listen rabbitmq_admin 
      ...
    

      重新运行 HAProxy,系统正常运行无异常

    参考:
    https://blog.csdn.net/qq_21108311/article/details/82973763#commentBox
    https://www.cnblogs.com/CaesarLinsa/p/11037613.html
    https://blog.csdn.net/kevin3101/article/details/86579311

    相关文章

      网友评论

          本文标题:Docker搭建多机多节点haproxy+keepalived负

          本文链接:https://www.haomeiwen.com/subject/yovbictx.html