Open penglongli opened 6 years ago
首发于:https://blog.coding.net/blog/Haproxy&Keepalived
适合具有 Docker 和 Bash 相关基础的开发、运维等同学。本文没有太过深入的介绍,也并没有用到一些高级特性,仅适合用来作为一个基础科普文来阅读。
最近在搭新的 Coding 内部测试环境,老大说把以前使用 nginx 插件来做的 LB(Load balancing) 全部换成 HAProxy 来做。经过几天的不断“查阅资料”,简单实现了该服务的动态构建。
本文循序渐进按照以下几个层次来讲:
HAProxy 与 Keepalived 的简单介绍
搭建 haproxy + keepalived 服务过程
环境准备:
五台 Linux 主机
一个虚拟的 IP
192.168.0.146(一个内网没人用的 IP)
HAProxy 是一个提供高可用、负载均衡和基于 HTTP/TCP 应用代理的解决方案。
Keepalived 是用 C 编写的路由软件,主要目标是为 Linux 系统及基于 Linux 的设施提供强大的高可用性和负载均衡。
在本文中,HAProxy 我们用来做 HTTP/TCP 应用的 HA + LB 方案,Keepalived 被用来做 HAProxy 的 HA 方案。下边是对两者的简单介绍和简单使用。
关于 HAProxy 的一些概念限于篇幅的原因不再详细说了,可以参考这篇文章 An Introduction to HAProxy and Load Balancing Concepts。下边仅会介绍我们会使用到的一些概念。
HAProxy 的 Proxy 配置可以分为如下几个部分(HAProxy Configuration#4):
<name>
其中 defaults 包含一些全局的默认环境变量,frontend 定义了如何把数据 forward 到 backend,backend 描述了一组接收 forward 来的数据的后端服务。listen 则把 frontend 和 backend 组合到了一起,定义出了一个完整的 proxy。
下面是一段简单的 HAProxy 的配置:
listen app1-cluster bind *:4000 mode http maxconn 300 balance roundrobin server server1 192.168.0.189:4004 maxconn 300 check server server2 192.168.0.190:4004 maxconn 300 check server server3 192.168.0.191:4004 maxconn 300 check listen app2-cluster bind *:5000 mode http maxconn 300 balance roundrobin server server1 192.168.0.189:5555 maxconn 300 check server server2 192.168.0.190:5555 maxconn 300 check server server3 192.168.0.191:5555 maxconn 300 check
我们在 HAProxy 的配置文件中定义了两个 listen 模块,分别监听在 4000、5000 端口。监听在 4000 端口的模块,使用 roundrobin (轮询)负载均衡算法,把请求分发到了三个后端服务。
关于 Keepalived 的详细介绍可以参考:Keepalived Introduction
Keepalived 是一个用于负载均衡和高可用的路由软件。
其负载均衡(Load balancing)的特性依赖于 Linux 虚拟服务器(LVS)的 IPVS 内核模块,提供了 Layer 4 负载均衡器(TCP 层级,Layer 7 是 HTTP 层级,即计算机网络中的OSI 七层网络模型与 TCP/IP 四层网络模型)。
Keepalived 实现了虚拟冗余路由协议(VRRP, Virtual Redundancy Routing Protoco),VRRP 是路由故障切换(failover)的基础。
简单来说,Keepalived 主要提供两种功能:
我们接下来会用个简单的配置来描述后者的工作原理:
在 haproxy-master 机器上:
vrrp_script chk_haproxy { script "killall -0 haproxy" # verify haproxy's pid existance interval 2 # check every 2 seconds weight -2 # if check failed, priority will minus 2 } vrrp_instance VI_1 { state MASTER # Start-up default state interface ens18 # Binding interface virtual_router_id 51 # VRRP VRID(0-255), for distinguish vrrp's multicast priority 105 # VRRP PRIO virtual_ipaddress { # VIP, virtual ip 192.168.0.146 } track_script { # Scripts state we monitor chk_haproxy } }
在 haproxy-backup 机器上:
vrrp_script chk_haproxy { script "killall -0 haproxy" interval 2 weight -2 } vrrp_instance VI_1 { state BACKUP interface ens18 virtual_router_id 51 priority 100 virtual_ipaddress { 192.168.0.146 } track_script { # Scripts state we monitor chk_haproxy } }
我们为两台机器(master、backup)安装了 Keepalived 服务并设定了上述配置。
可以发现,我们绑定了一个虚拟 IP (VIP, virtual ip): 192.168.0.146,在 haproxy-master + haproxy-backup 上用 Keepalived 组成了一个集群。在集群初始化的时候,haproxy-master 机器的 <state> 被初始化为 MASTER。
<state>
间隔 2 seconds(<interval>) 会定时执行 <script>脚本 ,每个<vrrp_instance> 会记录脚本的 exit code。
<interval>
<script>
<vrrp_instance>
关于<weight> 参数的使用:
<weight>
weight 默认值为 0,对此如果感到迷惑可以参考:HAProxy github code
故障切换工作流程:
其中有几处地方需要注意:
<virtual_router_id>
关于 Keepalived 各个参数代表含义的问题,可以同时参考下文与 Github 代码文档来看:
我们在 host-1、host-2、host-3 三台机器上,每台机器的 4004、5555 端口分别启起来一个服务,服务打印一段字符串,用来模拟业务集群中的三个实例。
如下所示:
192.168.0.189/host-1
4004 端口:
5555 端口:
192.168.0.190/host-2
192.168.0.191/host-3
如上所示,我们在三台机器上搭建了两个集群,结构如下图所示:
我们现在有两台机器:haproxy-master、haproxy-backup,本小节的目标是在这两台机器上分别搭一套相同的 HAProxy 服务。(为了方便,下边直接用 Docker 做了)
我们直接使用了 haproxy:1.7.9 版本的 Docker 镜像,下边是具体的步骤:
coding@haproxy-master:~/haproxy$ tree . . ├── Dockerfile └── haproxy.cfg 0 directories, 2 files coding@haproxy-master:~/haproxy$ cat Dockerfile FROM haproxy:1.7.9 COPY haproxy.cfg /usr/local/etc/haproxy/ coding@haproxy-master:~/haproxy$ cat haproxy.cfg global daemon maxconn 30000 log 127.0.0.1 local0 info log 127.0.0.1 local1 warning defaults mode http option http-keep-alive option httplog timeout connect 5000ms timeout client 10000ms timeout server 50000ms timeout http-request 20000ms # custom your own frontends && backends && listen conf #CUSTOM listen app1-cluster bind *:4000 mode http maxconn 300 balance roundrobin server server1 192.168.0.189:4004 maxconn 300 check server server2 192.168.0.190:4004 maxconn 300 check server server3 192.168.0.191:4004 maxconn 300 check listen app2-cluster bind *:5000 mode http maxconn 300 balance roundrobin server server1 192.168.0.189:5555 maxconn 300 check server server2 192.168.0.190:5555 maxconn 300 check server server3 192.168.0.191:5555 maxconn 300 check listen stats bind *:1080 stats refresh 30s stats uri /stats
在完成上述代码后,我们可以构建我们自己的 Docker 镜像,并运行它:
coding@haproxy-master:~/haproxy$ docker build -t custom-haproxy:1.7.9 . Sending build context to Docker daemon 3.584kB Step 1/2 : FROM haproxy:1.7.9 1.7.9: Pulling from library/haproxy 85b1f47fba49: Pull complete 3dee1a596b5f: Pull complete 259dba5307a2: Pull complete 9d51568f5880: Pull complete d2c6077a1eb7: Pull complete Digest: sha256:07579aed81dc9592a3b7697d0ea116dea7e3dec18e29f1630bc2c399f46ada8e Status: Downloaded newer image for haproxy:1.7.9 ---> 4bb854517f75 Step 2/2 : COPY haproxy.cfg /usr/local/etc/haproxy/ ---> 4e846d42d719 Successfully built 4e846d42d719 Successfully tagged custom-haproxy:1.7.9 coding@haproxy-master:~/haproxy$ docker run -it --net=host --privileged --name haproxy-1 -d custom-haproxy:1.7.9 fb41ab81d2140af062708e5b84668b7127014eb9ae274e4c2761d06e2f6d7950
通过命令 docker ps -a 我们可以看到,容器已经正常运行了,接下来我们在 web 端打开相应的地址可以看到所有服务的状态:
我们刚才在 haproxy-master 机器上搭建了一个 haproxy 服务,在其 4000、5000 端口绑定了两个业务集群。我们在浏览器访问:http://192.168.0.144:4000/、http://192.168.0.144:5000/ ,并且重复刷新即可看到会打印不同的 JSON 出来。可以证明我们请求确实是分发到了业务集群的几个实例中。
接下来,还要在 haproxy-backup 上搭建一个一模一样的 HAProxy 服务,步骤同上。
在上一小节中,我们在 haproxy-master、haproxy-backup 两台机器上搭了两套相同的 HAProxy 服务。我们希望在一个连续的时间段,只由一个节点为我们提供服务,并且在这个节点挂掉后另外一个节点能顶上。
本小节的目标是在haproxy-master、haproxy-backup 上分别搭 Keepalived 服务,并区分主、备节点,以及关停掉一台机器后保证 HAProxy 服务仍然正常运行。
使用如下命令安装 Keepalived:
coding@haproxy-master:~$ sudo apt-get install keepalived coding@haproxy-master:~/haproxy$ keepalived -v Keepalived v1.2.19 (03/13,2017)
我们在 haproxy-master 机器上,增加如下配置:
coding@haproxy-master:~$ cat /etc/keepalived/keepalived.conf vrrp_script chk_haproxy { script "killall -0 haproxy" interval 2 } vrrp_instance VI_1 { state MASTER interface ens18 virtual_router_id 51 priority 105 virtual_ipaddress { 192.168.0.146 } track_script { chk_haproxy } }
在 haproxy-backup 机器上增加如下配置:
coding@haproxy-backup:~$ cat /etc/keepalived/keepalived.conf vrrp_script chk_haproxy { script "killall -0 haproxy" interval 2 } vrrp_instance VI_1 { state BACKUP interface ens18 virtual_router_id 51 priority 100 virtual_ipaddress { 192.168.0.146 } track_script { chk_haproxy } }
在配置结束之后,我们分别重启两台机器上的 Keepalived 服务:
oot@haproxy-master:~# systemctl restart keepalived (注:不同的发行版命令不同,本文基于 Ubuntu 16.04)
此时我们的 Keepalived 服务就搭建完成了,VIP 是 192.168.0.146。此时我们通过浏览器访问:http://192.168.0.146:1080/stats,即可看到 HAProxy 服务的状态。
我们也可以通过 ssh user@192.168.0.146 看目前 MASTER 节点为哪台机器。ssh 后发现目前的 MASTER 节点为 haproxy-master 机器,我现在把这台机器上的 haproxy 服务停掉:
root@haproxy-master:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fb41ab81d214 custom-haproxy:1.7.9 "/docker-entrypoin..." About an hour ago Up 1 second haproxy-1 root@haproxy-master:~# docker stop fb41ab81d214 fb41ab81d214
然后我们访问:http://192.168.0.146:1080/stats,会在稍微停顿下后仍然能显示出来 haproxy 服务的状态。我们再 ssh user@192.168.0.146 后,发现我们进入了 haproxy-backup 机器上。此时的 MASTER 节点就是 haproxy-backup 机器。
以此来看,我们已经搭建出来了一个简单的 HAProxy + Keepalived 服务了。整体结构图如下所示:
有一点需要注意,容易混淆:
区分主节点、备节点是 Keepalived 服务来做的,HAProxy 在所有节点上的配置应该是相同的。
限于篇幅原因会在第二篇文章中介绍剩下的:
coding.net的url访问不了,图也没了,想看第二篇:)
https://github.com/penglongli/haproxy-keepalived 可以用这个库来做
适合具有 Docker 和 Bash 相关基础的开发、运维等同学。本文没有太过深入的介绍,也并没有用到一些高级特性,仅适合用来作为一个基础科普文来阅读。
背景
最近在搭新的 Coding 内部测试环境,老大说把以前使用 nginx 插件来做的 LB(Load balancing) 全部换成 HAProxy 来做。经过几天的不断“查阅资料”,简单实现了该服务的动态构建。
本文循序渐进按照以下几个层次来讲:
HAProxy 与 Keepalived 的简单介绍
搭建 haproxy + keepalived 服务过程
环境准备:
五台 Linux 主机
一个虚拟的 IP
192.168.0.146(一个内网没人用的 IP)
HAProxy 与 Keepalived 简单介绍
HAProxy 是一个提供高可用、负载均衡和基于 HTTP/TCP 应用代理的解决方案。
Keepalived 是用 C 编写的路由软件,主要目标是为 Linux 系统及基于 Linux 的设施提供强大的高可用性和负载均衡。
在本文中,HAProxy 我们用来做 HTTP/TCP 应用的 HA + LB 方案,Keepalived 被用来做 HAProxy 的 HA 方案。下边是对两者的简单介绍和简单使用。
HAProxy
关于 HAProxy 的一些概念限于篇幅的原因不再详细说了,可以参考这篇文章 An Introduction to HAProxy and Load Balancing Concepts。下边仅会介绍我们会使用到的一些概念。
HAProxy 的 Proxy 配置可以分为如下几个部分(HAProxy Configuration#4):
<name>
]<name>
<name>
<name>
其中 defaults 包含一些全局的默认环境变量,frontend 定义了如何把数据 forward 到 backend,backend 描述了一组接收 forward 来的数据的后端服务。listen 则把 frontend 和 backend 组合到了一起,定义出了一个完整的 proxy。
下面是一段简单的 HAProxy 的配置:
我们在 HAProxy 的配置文件中定义了两个 listen 模块,分别监听在 4000、5000 端口。监听在 4000 端口的模块,使用 roundrobin (轮询)负载均衡算法,把请求分发到了三个后端服务。
Keepalived
关于 Keepalived 的详细介绍可以参考:Keepalived Introduction
Keepalived 是一个用于负载均衡和高可用的路由软件。
其负载均衡(Load balancing)的特性依赖于 Linux 虚拟服务器(LVS)的 IPVS 内核模块,提供了 Layer 4 负载均衡器(TCP 层级,Layer 7 是 HTTP 层级,即计算机网络中的OSI 七层网络模型与 TCP/IP 四层网络模型)。
Keepalived 实现了虚拟冗余路由协议(VRRP, Virtual Redundancy Routing Protoco),VRRP 是路由故障切换(failover)的基础。
简单来说,Keepalived 主要提供两种功能:
我们接下来会用个简单的配置来描述后者的工作原理:
在 haproxy-master 机器上:
在 haproxy-backup 机器上:
我们为两台机器(master、backup)安装了 Keepalived 服务并设定了上述配置。
可以发现,我们绑定了一个虚拟 IP (VIP, virtual ip): 192.168.0.146,在 haproxy-master + haproxy-backup 上用 Keepalived 组成了一个集群。在集群初始化的时候,haproxy-master 机器的
<state>
被初始化为 MASTER。间隔 2 seconds(
<interval>
) 会定时执行<script>
脚本 ,每个<vrrp_instance>
会记录脚本的 exit code。关于
<weight>
参数的使用:weight 默认值为 0,对此如果感到迷惑可以参考:HAProxy github code
故障切换工作流程:
<script>
脚本检测失败后,如果“当前 MASTER 节点的 priority” < “当前 BACKUP 节点的 priority” 时,会发生路由故障切换。其中有几处地方需要注意:
<virtual_router_id>
,同一组 VIP 绑定的多个 Keepalived 服务的<virtual_router_id>
必须相同;多组 VIP 各自绑定的 Keepalived 服务一定与另外组不相同。否则前者会出现丢失节点,后者在初始化的时候会出错。关于 Keepalived 各个参数代表含义的问题,可以同时参考下文与 Github 代码文档来看:
搭建 haproxy + keepalived 服务过程
搭建业务服务
我们在 host-1、host-2、host-3 三台机器上,每台机器的 4004、5555 端口分别启起来一个服务,服务打印一段字符串,用来模拟业务集群中的三个实例。
如下所示:
192.168.0.189/host-1
4004 端口:
5555 端口:
192.168.0.190/host-2
4004 端口:
5555 端口:
192.168.0.191/host-3
4004 端口:
5555 端口:
如上所示,我们在三台机器上搭建了两个集群,结构如下图所示:
使用 HAProxy 做业务服务的高可用和负载均衡
我们现在有两台机器:haproxy-master、haproxy-backup,本小节的目标是在这两台机器上分别搭一套相同的 HAProxy 服务。(为了方便,下边直接用 Docker 做了)
我们直接使用了 haproxy:1.7.9 版本的 Docker 镜像,下边是具体的步骤:
在完成上述代码后,我们可以构建我们自己的 Docker 镜像,并运行它:
通过命令 docker ps -a 我们可以看到,容器已经正常运行了,接下来我们在 web 端打开相应的地址可以看到所有服务的状态:
我们刚才在 haproxy-master 机器上搭建了一个 haproxy 服务,在其 4000、5000 端口绑定了两个业务集群。我们在浏览器访问:http://192.168.0.144:4000/、http://192.168.0.144:5000/ ,并且重复刷新即可看到会打印不同的 JSON 出来。可以证明我们请求确实是分发到了业务集群的几个实例中。
接下来,还要在 haproxy-backup 上搭建一个一模一样的 HAProxy 服务,步骤同上。
使用 Keepalived 做 HAProxy 服务的高可用
在上一小节中,我们在 haproxy-master、haproxy-backup 两台机器上搭了两套相同的 HAProxy 服务。我们希望在一个连续的时间段,只由一个节点为我们提供服务,并且在这个节点挂掉后另外一个节点能顶上。
本小节的目标是在haproxy-master、haproxy-backup 上分别搭 Keepalived 服务,并区分主、备节点,以及关停掉一台机器后保证 HAProxy 服务仍然正常运行。
使用如下命令安装 Keepalived:
我们在 haproxy-master 机器上,增加如下配置:
在 haproxy-backup 机器上增加如下配置:
在配置结束之后,我们分别重启两台机器上的 Keepalived 服务:
此时我们的 Keepalived 服务就搭建完成了,VIP 是 192.168.0.146。此时我们通过浏览器访问:http://192.168.0.146:1080/stats,即可看到 HAProxy 服务的状态。
我们也可以通过 ssh user@192.168.0.146 看目前 MASTER 节点为哪台机器。ssh 后发现目前的 MASTER 节点为 haproxy-master 机器,我现在把这台机器上的 haproxy 服务停掉:
然后我们访问:http://192.168.0.146:1080/stats,会在稍微停顿下后仍然能显示出来 haproxy 服务的状态。我们再 ssh user@192.168.0.146 后,发现我们进入了 haproxy-backup 机器上。此时的 MASTER 节点就是 haproxy-backup 机器。
以此来看,我们已经搭建出来了一个简单的 HAProxy + Keepalived 服务了。整体结构图如下所示:
结尾
有一点需要注意,容易混淆:
区分主节点、备节点是 Keepalived 服务来做的,HAProxy 在所有节点上的配置应该是相同的。
限于篇幅原因会在第二篇文章中介绍剩下的: