0%

从零玩转 HAProxy

HAProxy_Logo

一、介绍

HAProxy 是法国人 Willy Tarreau 开发的一个开源软件,是一款应对 C10K 以上的同时连接的高性能的 TCP 和 HTTP 负载均衡器。其功能是用来提供基于 cookie 的持久性,基于内容的交换,过载保护的高级流量管制,自动故障切换,以正则表达式为基础的控制运行时间,基于 Web 的报表,高级日志记录以帮助排除故障的应用或网络及其他功能.

和 Nginx 一样,都支持在 4 层把 https 请求负载均衡至后端,或者在 7 层作为 https 会话卸载器

https

不同于 Nginx 的是,HAproxy 只能做 TCP/UDP/HTTP 的反向代理,自身不能做 Web 站点。

二、HAProxy 程序的组成

安装

CentOS 的 Base 源已经收录 HAProxy,可使用 YUM 直接安装。

1
yum install haproxy -yum

程序环境

  • 主程序/usr/sbin/haproxy
  • 主配置文件/etc/haproxy/haproxy.cfg
  • Unit file/usr/lib/systemd/system/haproxy.service

配置文件

大体分为 2 个配置段

  • global:全局配置段,主要负责:
    • 进程及安全配置相关的参数
    • 性能调整相关参数
    • Debug 参数
    • 用户列表
    • peers
  • proxies:代理配置段,主要负责:
    • defaults:为 frontend, listen, backend 提供默认配置。
    • frontend:前端,相当于 nginx 中的 server {}
    • backend:后端,相当于 nginx 中的 upstream {}
    • listen:前端和后端一致。

简单的调度配置示例

load

1
2
3
4
5
frontend web *:80
default_backend websrvs
backend websrvs
server srv1 172.16.100.6:80 check
server srv2 172.16.100.7:80 check

三、配置参数详解

参数可用位置矩阵图:http://cbonte.github.io/haproxy-dconv/1.5/configuration.html#4.1

global 配置段参数

进程及安全管理

chroot, user, group, uid, gid, daemon:这几条都能根据名字鉴别之意。

官方强烈建议这两条配置默认即可,HAProxy 会自动调整,所以不建议配置:

  • nbproc <number>:要启动的 haproxy 的进程数量,官方建议单进程。
  • ulimit-n <number>:每个 haproxy 进程可打开的最大文件数。

性能调整

  • maxconn 4000:设定每个 HAProxy 程序进程 所能接受的最大并发连接数,默认是 4000
    • 所以总的并发连接数等于:nbproc * maxconn
  • maxconnrate <number>:设定每个 HAProxy 进程每秒种所能创建的非 ssl 的最大连接数量。
  • maxsessrate <number>:设定每个 HAProxy 进程每秒种所能创建的最大会话(session)数量。
  • maxsslconn <number>:设定每个 HAProxy 进程所能接受的 ssl 的最大并发连接数。
  • spread-checks <0..50, in percent>:为了分散健康状态检测时的压力,设置检测延迟,最多不能超过检查周期长度的 50%。

proxies 配置段参数

HAProxy 可以通过配置文件,进行颗粒度很细很精准的各种代理配置,但随之而来的是配置项会相当复杂,难度提高,不过可以结合官方文档来学习。

proxies 的配置段有如下 四个区域

  1. defaults <name>:为 frontend, listen, backend 提供默认配置。
  2. frontend <name>:前端,相当于 nginx 中的 server {}
  3. backend <name>:后端,相当于 nginx 中的 upstream {}
  4. listen <name>:前端和后端一致。

注意:同一个参数可用于多个区域,但是生效的作用域不同,生效范围越小的优先级越高。

具体可用位置建议结合官网的 参数可用位置矩阵图 来使用

常用的一些参数

default_backend

default_backend <backend>:可用在除了 backend 的其他区域中,指定要使用的 backend

bind

bind [IP:PORT],[:PORT]:指定前端要监听的端口,也可以直接接在 frontend 后边指定,没有区别,如 frontend web *:80

balance 调度算法

balancer

定义要在后端使用的负载均衡算法

这里先说一下动态算法和静态算法的区别:

  • 动态算法特性:新加服务器后或调整权重后,reload 即可生效,且支持慢启动,流量缓慢增加。
  • 静态算法特性:新加服务器后或调整权重后,必须重启服务生效,且不支持慢启动。

语法:balance <algorithm> [ <arguments> ]

  • <algorithm>:指定调度算法。
    • round-robin:轮询。(动态算法)
    • static-rr:静态轮询。
    • leastconn:最少连接优先,适用于长会话的场景。(动态算法)
    • first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务器。
    • source:源地址 HASH。
    • hdr <name>:对于每个 http 请求,此处由 <name> 指定的 http 首部将会被取出做 HASH 计算,没有有效值的会被轮询调度。
    • uri:对 uri 的左半部分做 HASH 计算。
    • uri-param:对用户请求的 uri 的 <params> 部分中的参数的值作 HASH 计算。通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个 Backend Server。
1
2
3
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
左半部分:/<path>;<params>
整个 uri:/<path>;<params>?<query>#<frag>

定义 HASH 类型

定义 source, hdr, uri, uri-param 这几种调度算法的 HASH 方式。

语法:hash-type

  • map-based:取模算法。(静态算法)
  • consistent:一致性 HASH。(动态算法)

动态算法特性:新加服务器后或调整权重后,reload 即可生效,且支持慢启动,流量缓慢增加。
静态算法特性:新加服务器后或调整权重后,必须重启服务生效,且不支持慢启动。

配置 server

定义后端主机

定义后端主机的各服务器及其选项。

语法:server <name> <address>[:[port]] [param*]

  • <name>:自定义服务器在 haproxy 上的内部名称,出现在日志及警告信息中。
  • <address>:服务器地址,支持使用主机名。
  • [:[port]]:端口映射,省略时,表示同 bind 中绑定的端口。
  • [param*]:其他参数,包括:
    • maxconn <maxconn>:当前 server 的最大并发连接数。
    • backlog <backlog>:当前 server 的连接数达到上限后的后援队列长度。
    • backup:设定当前 server 为备用服务器。
    • check:对当前 server 做健康状态检测。
      • addr:健康检测时使用的 IP 地址。
      • port:针对此端口进行健康检测。
      • inter <delay>:连续两次健康检测之间的时间间隔,默认为 2000ms。
      • rise <count>:连续多少次健康检测结果为“成功”才标记服务器为可用,默认为 2
      • fall <count>:连续多少次健康检测结果为“失败”才标记服务器为不可用,默认为 3
      • HAProxy 默认在 4 层做健康检测,也支持一些应用层的检测方法:option httpchk, smtpchk, mysql-check, pgsql-check, ssl-hello-chk
    • cookie <value>:为当前后端 server 定义 cookie 值,用于实现基于 cookie 的会话绑定
    • disabled:标记为不可用,同 Nginx 中的 down
    • error-limit:定义 server 健康检测连续失败的次数,到达后,执行 on-error 的设定,默认是 10 次。
    • on-error <mode>:后端 server 故障时的如何处理。
      • fastinter:开始快速检测,加快检测频率,并进行请求排干。
      • fail-check:模拟一个失败的检查,后强制执行 fastinter,并进行请求排干,默认为此配置。
      • sudden-death:模拟一次致命错误,如再失败一次,则将 server 置为 down,并强制 fastinter
      • mark-down:直接把 server 置为 down 状态,并强制执行 fastinter
    • redir <prefix>:将发往此 server 的所有 GET 和 HEAD 类的请求重定向至指定的 URL。
    • weight <weight>:定义权重,默认为 1。

使用 cookie 进行会话绑定。

1
2
3
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ]
[ postonly ] [ preserve ] [ httponly ] [ secure ]
[ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
  • rewirte:重写
  • insert:插入
  • prefix:前缀

基于 cookie 的 session sticky 的实现:

1
2
3
4
backend websrvs
cookie WEBSRV insert nocache indirect
server srv1 172.16.100.6:80 weight 2 check rise 1 fall 2 maxconn 3000 cookie srv1
server srv2 172.16.100.7:80 weight 1 check rise 1 fall 2 maxconn 3000 cookie srv2

启用监控状态统计页面的参数

HAProxy 自带了一个强大的监控页,而且能统计数据。

  • stats enable:启用统计页;基于默认的参数启用 stats page。
  • stats hide-version:隐藏头部信息。
  • stats scope:定义显示哪些区域,默认为全部显示
  • stats uri <prefix>:自定义 stats page 的 uri。
  • stats realm <realm>:认证时显示的内容。
  • stats auth <user>:<passwd>:认证时的账号和密码,可使用多次。
  • stats refresh <delay>:设定自动刷新时间间隔。
  • stats admin { if | unless } <cond>:启用 stats page 中的管理功能。
  • stats refresh <s>:自动刷新时间。

默认值:

  • stats uri : /haproxy?stats
  • stats realm : "HAProxy Statistics"
  • stats auth : no authentication
  • stats scope : no restriction

配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 公开访问 (但是只显示此后端)
backend public_www
server srv1 192.168.0.1:80
stats enable
stats hide-version
stats scope .
stats uri /admin?stats
stats realm Haproxy\ Statistics
stats auth admin1:AdMiN123
stats auth admin2:AdMiN321

// 内部监控访问 (无限制)
backend private_monitoring
stats enable
stats uri /admin?stats
stats refresh 5s
stats admin if TRUE // TRUE 这个关键字表示只有经过认证成功后才能被管理

设定 mode 模式

mode { tcp|http|health }:定义 HAProxy 的工作模式

  • tcp:基于 layer4 实现代理,可代理 mysql, pgsql, ssh, ssl 等协议。
  • http:仅当代理的协议为 http 时使用。
  • health:工作为健康状态检查的响应模式,用于检查前端,当连接请求到达时回应 “OK” 后即断开连接。

示例:

1
2
3
4
5
6
listen ssh
bind :22022
balance leastconn
mode tcp
server sshsrv1 172.16.100.6:22 check
server sshsrv2 172.16.100.7:22 check

自定义错误页

  • errorfile <code> <file>:读取本地文件系统上的某个文件当做错误页的内容。

示例:

1
2
3
4
errorfile 400 /etc/haproxy/errorfiles/400badreq.http
errorfile 408 /dev/null # workaround Chrome pre-connect bug
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
errorfile 503 /etc/haproxy/errorfiles/503sorry.http
  • errorloc <code> <url>:直接响应一个新的 URL 给客户端。

示例:

1
2
errorloc 403 http://www.monster.com/error_pages/403.html
option forwardfor [ except <network> ] [ header <name> ] [ if-none ]

自定义报文首部

添加 X-Forwarded-For 首部

可以在数据报文离开 HAProxy 主机前,添加自定义报文首部,比如可以把发往后端主机的请求报文中添加 X-Forwarded-For 首部,值为前端客户端的地址,用于向后端主发送真实的客户端IP。

语法:option forwardfor [ except <network> ] [ header <name> ] [ if-none ]

  • [ except <network> ]:请求报请来自此处指定的网络时不予添加此首部。
  • [ header <name> ]:使用自定义的首部名称,而非 X-Forwarded-For

示例:

1
2
3
4
5
6
7
8
9
// 请求报请来自本机时不添加此首部
frontend www
mode http
option forwardfor except 127.0.0.1

// 使用自定义 `X-Client`,而非 `X-Forwarded-For`
backend www
mode http
option forwardfor header X-Client
添加自定义报文首部

还可以添加一些自定义的首部。

  • reqadd <string> [{if | unless} <cond>]:添加一个自定义的请求报文首部。
  • rspadd <string> [{if | unless} <cond>]:添加一个自定义的响应报文首部。
    • <string>:定义一个首部和其对应的值,任何空格或已知的分隔符必须使用反斜杠 \ 转义。
    • [{if | unless} <cond>]:可使用由 ACL 定义的可选匹配条件。

示例:
给客户端响应一个自定义的首部 X-Via,值为 HAPorxy

1
rspadd X-Via:\ HAPorxy
隐藏首部
  • reqdel <search> [{if | unless} <cond>]:删除通过正则表达式,匹配到的请求报文首部。
  • reqidel <search> [{if | unless} <cond>]:删除通过正则表达式,匹配到的请求报文首部,并忽略大小写。
  • rspdel <search> [{if | unless} <cond>]:删除通过正则表达式,匹配到的响应报文首部。
  • rspidel <search> [{if | unless} <cond>]:删除通过正则表达式,匹配到的响应报文首部,并忽略大小写。

示例:
隐藏所有响应报文中包含 Server.* 的首部。

1
rspidel  Server.*

compression 压缩

为指定的 MIME 类型启用压缩传输功能

  • compression algo <algorithm> ...:启用 http 协议的压缩机制。

    • <algorithm>:指明压缩算法: gzip, deflate
  • compression type <mime type> ...:指明压缩的 MIME 类型。

    • <mime type>:常见的适用于压缩的类型为文本类型。

示例:

1
2
compression algo gzip deflate
compression type text/plain text/html text/xml text/json

定义基于 7 层的健康状态检测

对后端服务器做 http 协议的健康状态检测

  • option httpchk:不做任何定义时,只会使用 OPTIONS 请求方法来检测主页,注意默认不是使用 GET 做检测。
  • option httpchk <uri>:对指定的 uri 使用 OPTIONS 请求方法来检测,注意默认不是使用 GET 做检测。
  • option httpchk <method> <uri>:对指定的 uri,用指定的请求方法做检测。
  • option httpchk <method> <uri> <version>:对指定的 uri,用指定的请求方法,对指定的协议版本做检测。

自定义检测机制:

  • http-check expect [!] <match> <pattern>:检查 HTTP 响应的内容,或特定的状态代码。

注意:有空格需要使用 \ 来转移,可以使用正则表达式匹配,但是会影响性能。

示例:

1
2
3
4
5
6
7
8
9
10
11
// only accept status 200 as valid
http-check expect status 200

// consider SQL errors as errors
http-check expect ! string SQL\ Error

// consider status 5xx only as errors
http-check expect ! rstatus ^5

// check that we have a correct hexadecimal tag before /html
http-check expect rstring <!--tag:[0-9a-f]*</html>

定义连接超时时长

定义连接超时时长,默认单位是 毫秒

  • timeout client <timeout>:定义客户端非活动时间;
  • timeout server <timeout>:定义后端服务的非活动时间;
  • timeout http-keep-alive <timeout>:定义持久连接的持久时长;
  • timeout http-request <timeout>:等待完整 HTTP 请求的最大允许时间
  • timeout connect <timeout>:定义与后端服务器尝试连接成功的最长时间。
  • timeout client-fin <timeout>:定义与客户端的半关闭(half-closed)连接的非活动超时时间。
  • timeout server-fin <timeout>:定义与后端服务器的半关闭(half-closed)连接的非活动超时时间。

关于日志

HAProxy 中可以定义将日志发往专门的日志收集服务器中

注意:一个配置段,最多只能定义两个日志收集服务器。

  • log global:默认,发往 global 中定义的 log server。
  • log <address> [len <length>] <facility> [<level> [<minlevel>]]:定义把日志发往哪里的 log server。
  • no log:不记录日志。

自定义要记录的日志信息

语法:capture cookie <name> len <length>

  • <name>:指定要记录的 name
  • <length:指定记录的信息长度。
从请求报文中记录指定的信息

语法:capture request header <name> len <length>

  • <name>:指定要记录的 name
  • <length:指定记录的信息长度。

示例:

1
capture request header X-Forwarded-For len 15
从响应报文中记录指定的信息

语法:capture response header <name> len <length>

  • <name>:指定要记录的 name
  • <length:指定记录的信息长度。

示例:

1
2
capture response header Content-length len 9
capture response header Location len 15

使用 rsyslog 记录 HAProxy 日志

默认情况下,HAProxy 中定义的是将日志发往本机的 rsyslog 服务来记录日志,如下:

vim /etc/haproxy/haproxy.cfg

1
2
3
...
log 127.0.0.1 local2
...

但是 rsyslog 中没有 local2 这个区域,如果想生效此日志配置,需要配置并启用 rsyslog

1、编辑 rsyslog 的配置文件,取消注释 几行配置来启用 TCP/UDP 端口,并添加一行配置。

vim /etc/rsyslog.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
...

$ModLoad imudp // 取消注释后
$UDPServerRun 514 // 取消注释后

...

$ModLoad imtcp // 取消注释后
$InputTCPServerRun 514 // 取消注释后

...

local2.* /var/log/haproxy.log # 添加一行,名字为 local2,和 HAProxy 中的配置对应

2、重启 rsyslog 服务。

1
systemctl restart rsyslog

3、就能看到日志了。

tail -f /var/log/rsyslog.log

1
2
3
4
Aug  9 01:26:10 localhost haproxy[11080]: 192.168.50.3:10025 [09/Aug/2019:01:26:10.168] web webcon/con1 0/0/0/0/0 200 247 - - ---- 2/2/0/1/0 0/0 "GET / HTTP/1.1"
Aug 9 01:26:10 localhost haproxy[11080]: 192.168.50.3:10025 [09/Aug/2019:01:26:10.169] web webcon/con2 688/0/0/0/688 200 247 - - ---- 2/2/0/1/0 0/0 "GET / HTTP/1.1"
Aug 9 01:26:11 localhost haproxy[11080]: 192.168.50.3:10025 [09/Aug/2019:01:26:10.858] web webcon/con1 453/0/0/0/453 200 247 - - ---- 2/2/0/1/0 0/0 "GET / HTTP/1.1"
Aug 9 01:26:11 localhost haproxy[11080]: 192.168.50.3:10025 [09/Aug/2019:01:26:11.310] web webcon/con2 446/0/0/0/446 200 247 - - ---- 2/2/0/1/0 0/0 "GET / HTTP/1.1"

注意:HAProxy 日志最多可以定义两个,超出无效。所以可以一个发往本地,另一个发往日志中心。

四、ACL

HAProxy 能够从请求报文、响应报文、客户端或者服务端信息,从表、环境信息等等中提取数据。提取这样的数据的动作我们称之为获取样本。进行检索时,这些样本可以用来实现各种目的,最常用的用途是,根据预定义的模式来进行匹配。

访问控制列表(ACL) 提供了一个灵活方案进行内容切换,可以从请求,响应,任何环境中提取数据,并做出响应动作。

控制列表的工作步骤很简单

  1. 从数据流,表,环境中提取数据样本;
  2. 对提取的样本可选地应用格式转换;
  3. 对一个样本应用一个或多个的模式匹配;
  4. 当模式匹配到样本时执行动作。

而可以执行的动作通常有

  • 阻断匹配的请求;
  • 调度选择一个后端服务器;
  • 添加一个 HTTP 首部。

而且,获取的样本数据不光可以使用在 ACL 中,也可以使用别处,例如记录在 log 中。

总的来说,ACL 其实只对特定数据进行比较并过滤,而过滤后的内容如何来操作,是其他参数工作的。

定义 ACL 的语法

语法:acl <aclname> <criterion> [flags] [operator] [<value>] ...

  • <aclname>:自定义一个 ACL 的名称,可使用字母、数字、:.-_,区分大小写。不同的 ACL 默认可以重名,重名的两个 ACL 规则之间是 or 关系,满足其一即可。
  • <criterion>:定义要比较什么类型的数据,如 urisource ip 等。
  • flags:定义一些额外的要求,如“不区分大小写”。
  • operator:定义比较的运算方法,如“数值比较”,“字符串匹配”等。
  • <value>:定义要比较此类型的什么值。

由于 ACL 可以控制的非常细致,所以参数特别多,这里分类介绍一些可能会用到的参数。

1. flags 的可用参数

定义一些额外的要求。

  • -i:忽略大小写。
  • -m:指定特殊匹配模式。
  • -n:禁止做 DNS 解析。
  • -u:不允许两个 ACL 使用的名字相同。
  • --:强制结束 flag,避免了字符串中含有的 - 引起混淆。

2. operator 的可用参数

定义比较的运算方法。

  • 匹配整数值:eq(=), ge(>=), gt(>), le(<=), lt(<)
  • 匹配字符串:
    • -m str:精确比较 exact
    • -m sub:字串比较 substring
    • -m end:后缀比较 suffix
    • -m beg:前缀比较 prefix
    • -m dir:对 uri 中以 / 分割的各子目录做精确比较 subdir
    • -m dom:对域名中以 . 分割的字符串做精确比较 domain

3. value 的可用参数

定义要比较什么值,如 /images/*.jpg192.168.0.0/24 等,可用类型有:

  • 布尔型;
  • 一个整数或整数范围;
  • 网络地址或 IP 地址;
  • 字符串;
  • 正则表达式匹配模式;
  • 十六进制的数据块。

4. criterion 的可用参数

定义要比较什么数据类型,可用参数如下:

网络地址
  • dst:目标 IP
  • dst_port:目标端口
  • src:源 IP
  • src_port:源端口
path(URI)

基于字符串检查 URI 路径 /path;<params>,两种表达方式,path_end = path -m end,效果一样。

  • path:exact string match(精确比较)
  • path_sub:substring match(字串比较)
  • path_end:suffix match(后缀比较)
  • path_beg:prefix match(前缀比较)
  • path_dir:subdir match(子目录精确比较)
  • path_dom:domain match(域名字符串精确比较)
  • path_len:length match (长度比较)
  • path_reg:regex match (正则表达式模式比较)

示例:

1
2
3
4
5
6
7
path_beg /images/
path_end .jpg .jpeg .png .gif
path_reg ^/images.*\.jpeg$
path_sub image
path_dir jpegs
path_dom ilinux // 不匹配
/images/jpegs/20180312/logo.jpg
URL

基于字符串检查 URL,比 path 范围更广,两种表达方式,url_end = url -m end,效果一样。

  • url:exact string match(精确比较)
  • url_sub:substring match(字串比较)
  • url_end:suffix match(后缀比较)
  • url_beg:prefix match(前缀比较)
  • url_dir:subdir match(子目录精确比较)
  • url_dom:domain match(域名字符串精确比较)
  • url_len:length match (长度比较)
  • url_reg:regex match (正则表达式模式比较)
req.hdr

基于字符串检查请求报文首部,两种表达方式,hdr_end = hdr -m end,效果一样。

  • hdr([<name>[,<occ>]]):exact string match(精确比较)
  • hdr_sub([<name>[,<occ>]]):substring match(字串比较)
  • hdr_end([<name>[,<occ>]]):suffix match(后缀比较)
  • hdr_beg([<name>[,<occ>]]):prefix match(前缀比较)
  • hdr_dir([<name>[,<occ>]]):subdir match(子目录精确比较)
  • hdr_dom([<name>[,<occ>]]):domain match(域名字符串精确比较)
  • hdr_len([<name>[,<occ>]]):length match (长度比较)
  • hdr_reg([<name>[,<occ>]]):regex match (正则表达式模式比较)

示例:

1
2
acl bad_curl hdr_sub(User-Agent) -i curl
block if bad_curl
status

根据响应报文中的状态码进行匹配,应该是一个整数。
status <integer>

5.一些预定义的 ACL

不必提前声明即可使用,为了避免混淆,名字都用大写字母,如下所示。

ACL name Equivalent to Usage
FALSE always_false never match
HTTP req_proto_http match if protocol is valid HTTP
HTTP_1.0 req_ver 1.0 match HTTP version 1.0
HTTP_1.1 req_ver 1.1 match HTTP version 1.1
HTTP_CONTENT hdr_val(content-length) gt 0 match an existing content-length
HTTP_URL_ABS url_reg ^[^/:]*:// match absolute URL with scheme
HTTP_URL_SLASH url_beg / match URL beginning with “/”
HTTP_URL_STAR url * match URL equal to “*”
LOCALHOST src 127.0.0.1/8 match connection from local host
METH_CONNECT method CONNECT match HTTP CONNECT method
METH_GET method GET HEAD match HTTP GET or HEAD method
METH_HEAD method HEAD match HTTP HEAD method
METH_OPTIONS method OPTIONS match HTTP OPTIONS method
METH_POST method POST match HTTP POST method
METH_TRACE method TRACE match HTTP TRACE method
RDP_COOKIE req_rdp_cookie_cnt gt 0 match presence of an RDP cookie
REQ_CONTENT req_len gt 0 match data in the request buffer
TRUE always_true always match
WAIT_END wait_end wait for end of content analysis

动作

在匹配命中的这些数据的基础上,做什么动作。

首先了解一下,ACL 在作为条件时,逻辑关系有如下 3 种

  • AND 与运算
  • OR 或运算
  • ! 取反,优先级高
    可使用德摩根定律

例如

1
2
3
if invalid_src invalid_port     // 必须同时匹配 src 和 port
if invalid_src || invalid_port // 匹配 src 或 port 其中一个即可
if ! invalid_src invalid_port // 匹配 src 取反后的结果,并同时匹配 port

可用动作

  • use_backend <backend> [{if | unless} <condition>]
    基于 ACL 的条件,如果 匹配 | 不匹配,就调度到指定后端。

  • block { if | unless } <condition>
    如果匹配 | 如果不匹配,就阻塞第 7 层请求。

  • http-request { allow | deny } [ { if | unless } <condition> ]
    也是阻塞第 7 层请求,不过和 block 比,可以自定义控制方式是 allow 还是 deny。省略 { if | unless } 的话代表全部。

  • tcp-request connection {accept|reject} [{if | unless} <condition>]
    可以自定义 4 层的访问控制方式。

五、HAProxy 在企业中的实现

负载均衡 4 层 sshd 服务

1
2
3
4
5
6
listen sshd
bind *:222
mode tcp
balance roundrobin
server sshdcon1 172.17.0.4:22 check
server sshdcon2 172.17.0.5:22 check

基于 ACL 实现动静分离的配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
frontend  web *:80
acl url_static path_beg -i /static /images /javascript /stylesheets
acl url_static path_end -i .jpg .gif .png .css .js .html .txt .htm

use_backend staticsrvs if url_static
default_backend appsrvs

backend staticsrvs
balance roundrobin
server stcsrv1 172.16.100.6:80 check

backend appsrvs
balance roundrobin
server app1 172.16.100.7:80 check
server app1 172.16.100.7:8080 check

listen stats
bind :9091
stats enable
stats auth admin:admin
stats admin if TRUE

配置 HAProxy 支持 https 协议

1、支持 ssl 会话

1
bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE

2、crt 后的证书文件要求 PEM 格式,且同时包含证书和与之匹配的所有私钥,把二者合一。

1
cat  demo.crt demo.key > demo.pem

3、把 80 端口的请求重向定 443

1
2
bind *:80
redirect scheme https if !{ ssl_fc }
  • 另一种配置:对非 ssl 的任何 url 的访问统统定向至 https 主机的主页。
1
redirect location https://172.16.0.67/ if !{ ssl_fc }

4、向后端传递用户请求的真实协议和端口。(看业务需求,可不配置)

1
2
http_request set-header X-Forwarded-Port %[dst_port]
http_request add-header X-Forwared-Proto https if { ssl_fc }