Linux服务篇--反向代理及负载均衡器Haproxy

本章概要

  • HAProxy介绍
  • HAProxy配置
  • ACL

1、HAProxy介绍

HAProxy介绍

  • 前言
    lvs性能强,功能弱;nginx(haproxy)功能多,性能相对较弱,因此,一般情况下,在前端使用LVS四层调度器加haproxy七层调度的结构
  • HAProxy: 是法国人Willy Tarreau开发的一个开源软件,是一款应对客户
    端10000以上的同时连接的高性能的TCP和HTTP负载均衡器。其功能
    是用来提供基于cookie的持久性,基于内容的交换,过载保护的高级流
    量管制,自动故障切换,以正则表达式为基础的控制运行时间,基于
    Web的报表,高级日志记录以帮助排除故障的应用或网络及其他功能
  • LB Cluster:
      四层:lvs, nginx(stream),haproxy(mode tcp)
      七层:http: nginx(http), haproxy(mode http), httpd…
  • 官网:
      http://www.haproxy.org
      https://www.haproxy.com
  • 文档:https://cbonte.github.io/haproxy-dconv/

HAProxy功能

  • HAProxy是TCP / HTTP反向代理服务器,尤其适合于高可用性环境
      可以针对HTTP请求添加cookie,进行路由后端服务器
      可平衡负载至后端服务器,并支持持久连接
      支持基于cookie进行调度
      支持所有主服务器故障切换至备用服务器
      支持专用端口实现监控服务
      支持不影响现有连接情况下停止接受新连接请求
      可以在双向添加,修改或删除HTTP报文首部
      支持基于pattern实现连接请求的访问控制
      通过特定的URI为授权用户提供详细的状态信息

  • 版本:1.4、1.5、1.6、1.7、1.8、1.9

  • HAProxy结构

  • 支持http反向代理

  • 支持动态程序的反向代理

  • 支持基于数据库的反向代理

2、HAProxy配置

HAProxy组成

  • 程序环境:
      主程序:/usr/sbin/haproxy
      配置文件:/etc/haproxy/haproxy.cfg
      Unit file:/usr/lib/systemd/system/haproxy.service
  • 配置段:
      global:全局配置段
        进程及安全配置相关的参数
        性能调整相关参数
        Debug参数
      proxies:代理配置段
        defaults:为frontend, backend, listen提供默认配置
        frontend:前端,相当于nginx中的server {}
        backend:后端,相当于nginx中的upstream {}
        listen:同时拥有前端和后端,适用于一对一环境
    示例1:
frontend web
    bind *:80
    default_backend websrvs
backend websrvs
    balance roundrobin
    server srv1 192.168.0.101:80 check
    server srv2 192.168.0.102:80 check

示例2:

RS1:
    [root@rs1 conf.d]# vim vhosts.conf 
    <VirtualHost *:80>
        ServerName www.a.com
        DocumentRoot "/var/www/html"
        <Directory "/var/www/html">
            Require all granted
        </Directory>
    </VirtualHost>
RS2:
    [root@rs1 conf.d]# vim vhosts.conf 
    <VirtualHost *:80>
        ServerName www.a.com
        DocumentRoot "/var/www/html"
        <Directory "/var/www/html">
            Require all granted
        </Directory>
    </VirtualHost>
    
haproxy服务器:
删除或注释defaults以下的所有配置,重新配置haproxy配置文件
vim /etc/haproxy/haproxy.cfg    
    frontend web
        bind *:80
        default_backend websrvs
    backend websrvs
        balance roundrobin      轮询调度算法
        server srv1 192.168.32.130:80 
        server srv2 192.168.32.131:80 
重新加载服务
    systemctl reload haproxy
查看端口号,发现默认5000端口消失,而80端口被监听,这里的80端口就是frontend定义的80端口,即frontend定义哪个端口,系统将会自动监听该端口
测试:while true ;do curl www.a.com;sleep 0.5 ;done;

注意:haproxy即使在server后不加check,也具有健康监测功能,当关闭后端服务器RS1和RS2中的某一台服务器时,会自动调度到另外一台服务器上,且返回代码为503

global配置

  • global配置参数:
  • 进程及安全管理:chroot, deamon,user, group, uid, gid
      nbproc <number> 要启动的haproxy的进程数量,系统默认单进程,要求使用daemon模式
      ulimit-n <number> 每个haproxy进程可打开的最大文件数,系统自动会指定,不建议设置
      daemon 后端方式运行,建议使用
      log 定义全局的syslog服务器;最多可以定义两个
      log <address> [len <length>] <facility> [max level [min level]]
        address: rsyslog服务器地址
        len: 记录日志的长度,默认1024

日志系统

  • log:
      log global
      log <address> [len <length>] <facility> [<level> [<minlevel>]]
        length 日志行的长度,默认1024
      no log
      注意:
        默认发往本机的日志服务器
        (1) local2.* /var/log/local2.log
        (2) M o d L o a d i m u d p             ModLoad imudp        ModLoadimudpUDPServerRun 514
  • log-format <string>:
      课外实践:参考文档实现combined格式的记录
    示例:
    haproxy配置文件中,日志配置如下: 
    global
     log         127.0.0.1 local2   
    注意:local2是指保存本地日志local0-loca7文件中的一个,由于指定的日志路径为本地ip地址127.0.0.1,因此必须开启网络功能才能保存haproxy日志
    在rsyslog日志配置文件中配置haproxy日志:
    vim /etc/rsyslog.conf 
    $ModLoad imudp    启用日志模块
    $InputTCPServerRun 514   监听udp/514端口,接收日志
    local2.*          /var/log/haproxy.log    设置保存日志的文件
    重启日志服务
    systemctl restart rsyslog
    查看日志:
    cat /var/log/haproxy.log
    注意:由于haproxy的日志是基于网络指向其他主机来保存日志,
    因此当改变日志保存位置时,需要把ip地址指向保存日志的主机ip,
    并开启网络日志功能以及监听514端口

日志管理

  • 将特定信息记录在日志中
  • capture cookie <name> len <length>
      捕获请求和响应报文中的 cookie并记录日志
  • capture request header <name> len <length>
      捕获请求报文中指定的首部并记录日志
    示例:
      capture request header X-Forwarded-For len 15
  • capture response header <name> len <length>
      捕获响应报文中指定的首部并记录日志
    示例:
      capture response header Content-length len 9
      capture response header Location len 15

性能调整

  • 性能调整:
    maxconn <number>:设置每个haproxy进程所能接受的最大并发连接数
    maxconnrate <number>:设置每个进程每秒种所能建立的最大连接数量
    maxsessrate <number>:设置每个进程每秒种所能建立的最大会话数量
      注意:连接数和会话数的区别在于,连接属于OSI七层参考模型的传输层,会话属于ISO参考模型的应用层
    maxsslconn <number>: 每进程支持SSL的最大连接数量
    spread-checks <0…50, in percent> 健康检测延迟时长百分比,建议2-5之间
      健康检测延迟时长百分比,建议2-5之间
      注意:当进行健康监测时,会向后端服务器发送健康监测数据,如果后端服务器数量较多,并且同时发送检测数据,会对haproxy服务器造成较大的负载压力,因此可以把检测延时发送,分开来发即可减轻haproxy的压力
      另外,如果延时设置为50%,那么前一个延时50%,后一个提前50%,会造成检测数据发送时间正好相连接,也会造成瞬间数据的负载压力,因此推荐延时为2%-5%之间

配置段

  • 代理配置段:
  • defaults <name>
  • frontend <name>
  • backend <name>
  • listen <name>
  • Frontend段:指定接收客户端连接侦听套接字设置
  • Backend段:指定将连接请求转发至后端服务器的相关设置
  • Listen段:指定完整的前后端设置
  • proxy 名称:使用字母 数字 - _ . : 并区分字符大小写

配置参数

  • 配置参数:
  • bind:指定一个或多个前端侦听地址和端口
      bind [<address>]:<port_range> [, ...] [param*]
    示例:
listen http_proxy
    bind :80,:443
    bind 10.0.0.1:10080,10.0.0.1:10443
    bind /run/ssl-frontend.sock user root mode 600 accept-proxy

Balance配置

  • balance:后端服务器组内的服务器调度算法
    balance <algorithm> [ <arguments> ]
    balance url_param <param> [check_post]
  • 调度算法:
    (1) roundrobin:基于权重轮询,动态算法,支持权重的运行时调整,支持慢启动;每个后端backend中最多支持4095个server
      server options: weight #
      动态算法,更改配置文件后,无需重启服务,只需重新加载服务即可
      慢启动,当新上线一台服务器后,把集群中其他服务器的访问量缓慢的调度到该服务器上,让该服务器动态平滑的负载访问数据,避免把大量的访问量瞬间调度到该服务器而导致服务器崩溃
    示例:roundrobin算法
frontend web
    bind 172.20.120.255:80
    default_backend websrvs
backend websrvs
    balance roundrobin
    server srv1 192.168.32.130:80 check
    server srv2 192.168.32.131:80 check
重新加载服务(动态算法,无需重启,只需重新加载即可)
systemctl reload haproxy.service 

(2) static-rr:基于权重轮询,静态算法,不支持权重的运行时调整及慢启动;后端主机数量无上限
(3) leastconn:加权最少连接,动态算法,最少连接的后端服务器优先分配接收新连接,相同连接时轮询,推荐在较长会话的场景使用,例如MySQL,LDAP等,不适合http
(4) first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务,不支持权重
(5) source:源地址hash,新连接先按权重分配,后续连接按source分配请求,实现会话绑定
  需要维护客户端ip地址hash值与服务器的对应关系表,消耗服务器内存,因此先把hash值对权重取模,按照取模所得到的值进行调度,无需记录对应关系表
  缺点:(1)源地址通过snat转换,可能存在大量私网ip客户端,无法精确进行调度。(2)一旦权重发生变化,会对服务器调度产生很大影响,需要使用一致性hash算法解决
(6) uri:
  对URI的左半部分或整个uri做hash计算,并除以服务器总权重取模,以后派发至某挑出的服务器,适用于后端缓存服务器
  <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
  左半部分:/<path>;<params>
  整个uri:/<path>;<params>?<query>#<frag>
示例:

在后端服务器生成不同的html页面,请求不同的html页面可能会调度到不同的服务器
注意:uri调度算法可以跟上hash算法   
frontend web
    bind 172.20.120.255:80
    default_backend websrvs
backend websrvs
    balance uri
    hash-type consistent   一致性hash算法
    server srv1 192.168.32.130:80 check
    server srv2 192.168.32.131:80 check
重新加载服务(动态算法,无需重启,只需重新加载即可)
    systemctl reload haproxy.service 

(7) url_param:
  对用户请求的uri中的<params>部分中的参数的值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个Backend Server
  http://www.magedu.com/bbs/hello;type=title
(8) hdr(<name>):对于每个http请求,此处由<name>指定的http首部将会被取出做hash计算;并由服务器总权重相除以后派发至某挑出的服务器;无有效值的会被轮询调度
  hdr(Cookie)
示例:hdr算法

    根据请求报文头部信息做hash运算进行调度
    frontend web
        bind 172.20.120.255:80
        default_backend websrvs
    backend websrvs
        balance hdr(Host)   根据请求报文主机头信息进行调度
        server srv1 192.168.32.130:80 check
        server srv2 192.168.32.131:80 check
请求报文头部信息包括:
    Host  主机头   请求同一个域名,调度到固定的服务器
    User-Agent  浏览器类型   同一个浏览器类型,调度到固定的服务器
        curl命令可以模拟浏览访问服务器
        curl -A ie10  http://www.a.com
        curl -A chrome  http://www.a.com
        好处:可以根据不同的浏览器类型,把请求调度到不同的服务器,如可以把手机浏览器和PC浏览的访问请求分开调度到不同的服务器
    cookie  根据cookie调度,绑定session会话,进行会话保持
        会话保持的三种方案:
            记录调度选择
                根据源ip地址判断
                根据cookie信息判断用户信息,把用户调度到固定的服务器上,cookie属于应用层,因此需要应用层反向代理服务器
            复制会话    把cookie复制到全部的服务器,会造成数据冗余
            会话服务器   设置专门的session服务器
        缺点:后端服务器出现故障,仍然会向该服务器调度访问
        因此,一般情况下,session信息不会存放到后端服务器上,会单独设置存储session信息的服务器,目前主流的解决方案:redis服务器集群

(9) rdp-cookie 远程桌面相关
(10) rdp-cookie(<name>)

哈希算法

  • hash-type:哈希算法
    hash-type <method> <function> <modifier>
      method:
        map-based:除权取余法,哈希数据结构是静态数组
        consistent:一致性哈希,哈希数据结构是一棵树
      function : 哈希函数,取值:sdbm,djb2,wt6
      modifier: 取值avalanche时,将修改哈希值,而非直接使用
  • default_backend <backend>
      无use_backend 匹配时,使用默认的backend,用于frontend中
  • default-server [param*]
      为backend中的各server设定默认选项
      支持配置段:defaults,listen,backend
    示例1:default_backend
    frontend web
        bind 172.20.120.255:80
        default_backend websrvs   收到请求报文,默认发送给websrvs服务器组
    backend websrvs
        balance hdr(Host)   
        server srv1 192.168.32.130:80 check
        server srv2 192.168.32.131:80 check
    注意:可以根据条件判断,把满足条件的请求数据发送到默认后端服务器,不满足条件的请求数据发送到其他非默认的后端服务器,这样就可以对数据进行分流,即一个调度规则可对应多个服务器组

示例2:default-server

frontend web
    bind 172.20.120.255:80
    default_backend websrvs
backend websrvs
    default-server inter 1000 weight 10   为服务器组设置默认值
    balance roundrobin
    server srv1 192.168.32.130:80 check weight 2
    server srv2 192.168.32.131:80 check   没有设置权重,默认为10

示例3:listen指令

使用listen指令,可以把调度规则和后端服务器形成一一对应关系,而无需使用前端frontend和后端backend,不推荐这种写法
    listen http
    #frontend web
        bind 172.20.120.255:80
        #default_backend websrvs
    #backend websrvs
        balance roundrobin
        server srv1 192.168.32.130:80 check
        server srv2 192.168.32.131:80 check

配置

  • server <name> <address>[:[port]] [param*]
    定义后端主机的各服务器及其选项
    server <name> <address>[:port] [settings …]
    default-server [settings …]
    <name>:后端服务器在haproxy上的内部名称;出现在日志及警告信息
    <address>:后端服务器地址,支持使用主机名
    [:[port]]:端口映射;省略时,表示同bind中绑定的端口
    [param*]:参数
      weight <weight>:权重,默认为1
      maxconn <maxconn>:当前后端server的最大并发连接数
      backlog <backlog>:当server的连接数达到上限后的后援队列长度
      backup:设定当前server为备用服务器Sorry Server
    示例:设置backup服务器,即sorryserver
frontend web
    bind 172.20.120.255:80
    default_backend websrvs
backend websrvs
    default-server inter 1000 weight 10
    balance roundrobin
    server srv1 192.168.32.130:80 check weight 2
    server srv2 192.168.32.131:80 check
    server backupsrv 127.0.0.1:8080 check backup
注意:设置backup服务器时不能添加backlog参数,即后援队列,否则本机将无法监听80端口,另外,backup服务器的ip地址可以设置为haproxy服务器的本地回环网口的ip,内网ip地址或外网ip地址,推荐设置为内网或本地lo网卡的ip地址

健康状态检测

  • check:对当前server做健康状态检测,只用于四层检测
    注意:httpchk,“smtpchk”, “mysql-check”, “pgsql-check” and “ssl-hello-chk” 用于定义应用层检测方法
      addr :检测时使用的IP地址
      port :针对此端口进行检测
      inter <delay>:检测之间的时间间隔,默认为2000ms
      rise <count>:连续多少次检测结果为“成功”才标记为可用;默认为2
      fall <count>:连续多少次检测结果为“失败”才标记为不可用;默认为3
  • disabled:标记为不可用
      应用程序版本升级,系统维护时使用
        蓝绿发布 两套相同的环境,相互替换使用
        金丝雀发布 应用程序升级时,先升级一部分服务器供vip使用,待应用程序稳定运行一段时间后,再全部切换
        灰度发布 部分切换,逐步完成全部切换
  • redir <prefix>:将发往此server的所有GET和HEAD类的请求重定向至指定的URL
    示例:redir 重定向
    frontend web
        bind 172.20.120.255:80
        default_backend websrvs
    backend websrvs
        balance roundrobin
        server srv1 192.168.32.130:80 check
        server srv2 192.168.32.131:80 check redir http://172.20.120.255:8080
    注意:使用curl命令测试时,由于redir为把请求重定向到其他链接,因此需要使用-L选项才能显示重定向的内容
    另外,重定向指定的主机ip地址必须为客户端能够访问的ip地址(即外网地址),否则客户端将无法访问而造成重定向失败

cookie配置

  • cookie <value>:为当前server指定cookie值,实现基于cookie的会话黏性
    cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
      <name>:cookie名称,用于实现持久连接
        rewrite:重写
        insert:插入
        prefix:前缀
        nocache:当client和hapoxy之间有缓存时,不缓存cookie
          当client和hapoxy之间有缓存时,如果cookie被缓存,当客户端访问时,会根据缓存的cookie信息把所有的请求调度到同一台服务器上,nocache是指不缓存cookie信息
          注意:每个后端服务器的cookie是固定的,后端服务器有多少个,cookie值就有多少个
    示例1:基于cookie的session sticky的实现
    backend websrvs
        cookie WEBSRV insert nocache   定义cookie的名称,相当于K/V中的key,通过调用此名称,调用cookie值
        server srv1 172.16.0.6:80 weight 2 check rise 1 fall 2 maxconn 3000 cookie srv1   给cookei赋值,相当于K/V中的value
        server srv2 172.16.0.7:80 weight 1 check rise 1 fall 2 maxconn 3000 cookie srv2   给cookei赋值,相当于K/V中的value

示例2:

frontend web
    bind 172.20.120.255:80
    default_backend websrvs
backend websrvs
    cookie WEBSRV insert nocache
    server srv1 192.168.32.130:80 check cookie rs1
    server srv2 192.168.32.131:80 check cookie rs2
    server srv1 192.168.32.130:80 check
    server srv2 192.168.32.131:80 check redir http://172.20.120.255:8080
使用curl命令测试,使用-b选项在测试时添加cookie
curl -I 172.20.120.255  查看cookie值
curl -b WEBSRV=rs1 172.20.120.255   根据cookie值进行调度到固定服务器

统计接口启用相关的参数

  • stats enable
      启用统计页;基于默认的参数启用stats page
  • stats hide-version 隐藏版本
  • stats refresh <delay>
      设定自动刷新时间间隔
  • stats uri <prefix>
      自定义stats page uri,默认值:/haproxy?stats
  • stats realm <realm>
      认证时的realm,示例:stats realm : HAProxy\ Statistics
  • stats auth <user>:<passwd>
      认证时的账号和密码,可使用多次,默认:no authentication
  • stats admin { if | unless } <cond>
      启用stats page中的管理功能
    示例:
listen stats
    bind :9527
    stats enable
    stats hide-version
    stats uri /hastats
    stats realm HAPorxy\ Stats\ Page
    stats auth admin1:password1
    stats auth admin1:password2
    stats refresh 3s
    stats admin if TRUE

知识扩展:

启用状态页
    frontend web
        bind 172.20.120.255:80
        default_backend websrvs
        stats enable       启用状态页
        stats hide-version    隐藏状态页haproxy的版本号
        stats refresh 3     设置自动刷新间隔为3s
        stats uri /hastatus   自定义访问状态页的uri
        stats realm HAproxy\ statistics   设置验证提示信息,注意在配置文件中空格要进行转义才能被识别,因此HAproxy\ statistics中的\是指转义字符,是对空格进行转义,而且每一个空格都要用转义字符进行转义
        stats auth root:centos       设置验证用户名密码
        stats admin if TRUE    开启状态页管理功能,并可以设置acl权限,即什么条件下才会开启管理功能,if TRUE是指永远成立,注意TRUE为大写
    backend websrvs
        cookie WEBSRV insert nocache
        server srv1 192.168.32.130:80 check cookie rs1
        server srv2 192.168.32.131:80 check cookie rs2    
默认访问路径:http://haproxy服务器ip/haproxy?stats
注意:haproxy服务器的ip是指配置文件中监听的ip地址,即bind指令绑定的ip地址
另外,如果状态页的ip地址为公网地址,为了确保安全,除了可以改变状态的uri,还可以对状态页进行验证

DRAIN  排干状态,把访问逐渐清除,清除完毕后再把机器安全下线,如果直接把服务器标记为下线会对正在访问的用户造成影响
MAINT  维护状态

haproxy状态页并不需要调度到后台服务器,因此状态页可以单独定义
可将ip地址绑定在内网地址并监听一个不常用的端口如9527,只用于内部人员管理服务器,以增加安全性
listen haproxy
    bind 192.168.32.129:9527
    stats enable
    stats hide-version
    stats refresh 30
    stats uri /hastatus
    stats realm HAproxy\ statistics
    stats auth root:centos
    stats admin if TRUE
frontend web
    bind 172.20.120.255:80
    default_backend websrvs
backend websrvs
    cookie WEBSRV insert nocache
    server srv1 192.168.32.130:80 check cookie rs1 maxconn 5000
    server srv2 192.168.32.131:80 check cookie rs2

工作模式

  • maxconn <conns>:为指定的frontend定义其最大并发连接数;默认为3000
  • mode { tcp|http|health }
      定义haproxy的工作模式
      tcp:基于layer4实现代理;可代理mysql, pgsql, ssh, ssl等协议,https时使用此模式,默认模式
      http:仅当代理协议为http时使用,CentOS中haproxy实际的默认模式
      health:工作为健康状态检查的响应模式,当连接请求到达时回应“OK”后即断开连接,较少使用
    示例:TCP模式
    listen ssh        
        bind :22222    定义监听端口,由于没有绑定具体ip地址,该端口会发布外网,为了防止外网访问,因此使用不常用的端口
        balance leastconn   最少连接算法适用于长连接,ssh远程连接属于长连接
        mode tcp     defaults配置段默认为http协议,使用四层调度,必须指定为tcp协议
        server sshsrv1 192.168.32.130:22 check  调度到后端服务器的22端口
        server sshsrv2 192.168.32.131:22 check  调度到后端服务器的22端口
在客户端进行访问测试
    ssh 172.20.120.255 -p 22222   -p选项指定端口
注意:haproxy的tcp四层调度属于伪四层调度,因为一般真正的tcp四层调度会直接转发报文,而不会更改报文中的ip地址信息代替客户端访问服务器,
但haproxy把客户端的请求报文解封装,然后把自己的ip地址封装进报文,代替客户端访问后端服务器,实现四层调度,
这就改变了请求报文中源ip地址,而后端服务器看到的源ip地址就是haproxy服务器的内网地址。

健康状态检测

  • 对后端服务器做http协议健康状态检测:通常用于backend
      option httpchk 默认向后端服务器发请求:OPTIONS / HTTP/1.0
      option httpchk <uri>
      option httpchk <method> <uri>
      option httpchk <method> <uri> <version>
        定义基于http协议的7层健康状态检测机制
      http-check expect [!] <match> <pattern>
        http协议健康状态检测响应内容或指定响应码
      注意:haproxy默认自带健康检测功能,但却是基于四层的健康检测,只针对ip地址,端口号等信息进行检测,无法识别应用层的数据。如果数据不存在,但ip地址和端口没有问题,仍然会向该服务器调度数据,因此并不完善。
      因此需要对应用层进行健康检测,即基于七层的健康检测
      关闭后端服务器网页,使用tcpdump命令抓包查看:
      tcpdump -nn -i ens33 port 80
    示例:
frontend web
    bind 172.20.120.255:80
    default_backend websrvs
backend websrvs
    option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www    定义健康检测的内容和方法,注意每一个空格都要用转义字符
    http-check expect status 200   定义获取200状态码表示服务器处于健康状态,继续后续的调度
    server srv1 192.168.32.130:80 check
    server srv2 192.168.32.131:80 check
注意:option httpchk是基于http模式进行健康检测,因此defaults配置段中的mode必须是http模式,才能够进行健康检测

forwardfor配置

  • option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
    在由haproxy发往后端主机的请求报文中添加“X-Forwarded-For”首部,其值为前端客户端的地址;用于向后端主发送真实的客户端IP
      [ except <network> ]:请求报请来自此处指定的网络时不予添加此首部,如haproxy自身所在网络
      [ header <name> ]:使用自定义的首部名称,而非“X-Forwarded-For”
      [ if-none ] 如果没有首部才添加首部,如果有使用默认值
  • 为指定的MIME类型启用压缩传输功能
      compression algo <algorithm> …:启用http协议的压缩机制,指明压缩算法gzip, deflate
      compression type <mime type> …:指明压缩的MIMI类型
    示例:
客户端的请求报文到达haproxy服务器后,haproxy会代替客户端访问后端服务器,
因此后端服务器看到的源ip地址是haproxy服务器的ip地址,无法看到真正的客户端ip地址。
在由haproxy发往后端主机的请求报文中添加“X-Forwarded-For”首部,其值为前端客户端的地址;用于向后端主发送真实的客户端IP。
haproxy配置文件中defaults配置段中,已经默认添加“X-Forwarded-For”首部信息:
option forwardfor     except 127.0.0.0/8    本机访问后端服务器时不添加首部信息
在后端服务器http配置文件日志格式中添加“X-Forwarded-For”字段,记录日志时能够显示该字段
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Ag
ent}i\" \"%{clientip}i\" \"{X-Forwarded-For}\"" combined

也可以自定义“X-Forwarded-For”字段的名称
 option forwardfor       except 127.0.0.0/8 header testheader   把“X-Forwarded-For”更改为testheader
在后端服务器http配置文件日志格式中调用该名称即可
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Ag
ent}i\" \"%{clientip}i\" \"{testheader}\"" combined

重启httpd服务
systemctl reload httpd
查看日志:
tail -f /var/log/httpd/access_log 
192.168.32.129 - - [13/Nov/2018:21:19:07 +0800] "GET / HTTP/1.1" 200 11 "-" 
"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-" 172.20.120.193

错误页配置

  • errorfile <code> <file> 自定义错误页
      <code>:HTTP status code.
        支持200, 400, 403, 408, 500, 502, 503, 504.
      <file>:错误页文件路径
  • errorloc <code> <url>
    相当于errorloc302 <code> <url>,利用302重定向至指URL

示例1:

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

示例2:errorloc 503 http://www.magedu.com/error_pages/503.html
示例3:

自定义错误页
[root@centos7 ~]# mkdir errorfile
[root@centos7 ~]# cd errorfile/
[root@centos7 errorfile]# vim 503.html
<h1>503,forbidden</h1>

errorloc  重定向调度
    当返回错误码时,调度到指定的服务器上,把错误页面集中存放在某个服务器上
构建503错误进行测试
示例:
    backend websrvs
        server srv1 192.168.32.130:80 check
        server srv2 192.168.32.131:80 check
        errorloc 503 http://192.168.32.129:9527 
        errorfile 503 /etc/haproxy/errorfiles/403.http

注意:503.html  需要关闭全部的后端服务器,才能够现实503错误页面

修改报文首部

  • 在请求报文尾部添加指定首部
      reqadd <string> [{if | unless} <cond>]
  • 在响应报文尾部添加指定首部
      rspadd <string> [{if | unless} <cond>]
      示例:rspadd X-Via:\ HAPorxy
  • 从请求报文中删除匹配正则表达式的首部
      reqdel <search> [{if | unless} <cond>]
      reqidel <search> [{if | unless} <cond>] 不分大小写
  • 从响应报文中删除匹配正则表达式的首部
      rspdel <search> [{if | unless} <cond>]
      rspidel <search> [{if | unless} <cond>] 不分大小写
      示例: rspidel server.*
    示例1:添加请求报文头部信息
frontend web
    bind 172.20.120.255:80
    default_backend websrvs
backend websrvs
    server srv1 192.168.32.130:80 check
    server srv2 192.168.32.131:80 check
    reqadd X-Via:\ HAPorxy    注意:空格要用转义字符,每一个空格都要用一个转义字符
重启服务
    systemctl restart haproxy
在后端服务器配置文件日志格式中调用该头部字段“X-Via”
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Ag
    ent}i\" \"%{clientip}i\" %{testheader}i %{X-Via}i" combined
查看日志:
    192.168.32.129 - - [13/Nov/2018:22:17:25 +0800] "GET / HTTP/1.1" 200 11 "-" 
    "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-" 172.20.120.193 HAPorxy

示例2:删除响应报文头部信息

配置端:前端后端都支持
frontend web
    bind 172.20.120.255:80
    default_backend websrvs
    rspidel server  删除响应报文中的server信息,rspidel指不区分大小写
    rspadd  server:\ testapache   自定义服务器名
backend websrvs
    server srv1 192.168.32.130:80 check
    server srv2 192.168.32.131:80 check
    reqadd X-Via:\ HAPorxy
重启服务
    systemctl restart haproxy
查看响应报文头部信息,不存在server头部信息,并显示自定义的服务器名称
    [root@centos6 ~]# curl -I 172.20.120.255
    HTTP/1.1 200 OK
    Date: Tue, 13 Nov 2018 14:35:19 GMT
    Last-Modified: Mon, 12 Nov 2018 00:38:15 GMT
    ETag: "b-57a6ceaa55e56"
    Accept-Ranges: bytes
    Content-Length: 11
    Content-Type: text/html; charset=UTF-8
    server: testapache    自定义服务器名称

连接超时

  • timeout client <timeout>
      客户端最长空闲连接超时时长 默认单位是毫秒
  • timeout server <timeout>
      后端服务器最长空闲连接超时时长
  • timeout http-keep-alive <timeout>
      持久连接的持久时长
  • timeout http-request <timeout>
      一次完整的HTTP请求的最大等待时长
  • timeout connect <timeout>
      成功连接后端服务器的最大等待时长
  • timeout client-fin <timeout>
      客户端半连接的空闲时长
  • timeout server-fin <timeout>
      后端服务器半连接的空闲时长

3、ACL

ACL

  • acl:访问控制列表(ACL)的使用提供了一个灵活的解决方案来执行内容交换,并且通常基于从请求中提取的内容、响应或任何环境状态进行决策
    acl <aclname> <criterion> [flags] [operator] [<value>] …
      <aclname>:ACL名称,可使用字母 数字 : . - _ ,区分字符大小写
      <criterion>: 比较的标准和条件
  • <value>的类型:
      - boolean
      - integer or integer range
      - IP address / network
      - string (exact, substring, suffix, prefix, subdir, domain)
      - regular expression
      - hex block
  • <flags>
      -i 不区分大小写
      -m 使用指定的pattern匹配方法
      -n 不做DNS解析
      -u 强制每个ACL必须唯一ID,否则多个同名ACL或关系
      – 强制flag结束. 当字符串和某个flag相似时使用
  • [operator]
      匹配整数值:eq、ge、gt、le、lt
      匹配字符串:
      - exact match (-m str) :字符串必须完全匹配模式
      - substring match (-m sub) :在提取的字符串中查找模式,如果其中任何一个被发现,ACL将匹配
      - prefix match (-m beg) :在提取的字符串首部中查找模式,如果其中任何一个被发现,ACL将匹配
      - suffix match (-m end) :将模式与提取字符串的尾部进行比较,如果其中任何一个匹配,则ACL进行匹配
      - subdir match (-m dir) :查看提取出来的用斜线分隔(“/”)的字符串,如果其中任何一个匹配,则ACL进行匹配
      - domain match (-m dom) :查找提取的用点(“.”)分隔字符串,如果其中任何一个匹配,则ACL进行匹配
  • acl作为条件时的逻辑关系:
      - 与:隐式(默认)使用
      - 或:使用“or” 或 “||”表示
      - 否定:使用“!“ 表示
    示例:
    if invalid_src invalid_port 与关系
    if invalid_src || invalid_port 或
    if ! invalid_src 非
  • <criterion> :各种条件
      dst 目标IP
      dst_port 目标PORT
      src 源IP
      src_port 源PORT
      示例:acl invalid_src src 172.16.100.200
    示例:
listen haproxy
    bind 192.168.32.129:9527
    acl valid_src src 192.168.32.1   定义acl规则valid_src
    stats enable
    stats hide-version
    stats refresh 30
    stats uri /hastatus
    stats realm HAproxy\ statistics
    stats auth root:centos
    stats admin if valid_src   调用acl规则valid_src,只有满足该规则才能查看状态页
取反:
    stats admin if ! valid_src   对该命令取反是指不满足条件的主机无法使用管理功能,即图形界面下的可选框功能
  • base : string
      返回第一个主机头和请求的路径部分的连接,该请求从第一个斜杠开始,并在问号之前结束,对虚拟主机有用
      <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
      base : exact string match
      base_beg : prefix match
      base_dir : subdir match
      base_dom : domain match
      base_end : suffix match
      base_len : length match
      base_reg : regex match
      base_sub : substring match
  • path : string
      提取请求的URL路径,该路径从第一个斜杠开始,并在问号之前结束(无主机部分)
      <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
      path : exact string match
      path_beg : prefix match
      path_dir : subdir match
      path_dom : domain match
      path_end : suffix match
      path_len : length match
      path_reg : regex match
      path_sub : substring match
    示例:ACL path
path_beg /images/
path_end .jpg .jpeg .png .gif
path_reg ^/images.\*\.jpeg$
path_sub image
path_dir jpegs
path_dom magedu

/images/jpegs/20180123/logo.jpg
  • url : string
      提取请求中的URL。一个典型的应用是具有预取能力的缓存,以及需要从数据库聚合多个信息并将它们保存在缓存中的网页门户入口,推荐使用path
      url :exact string match
      url_beg : prefix match
      url_dir : subdir match
      url_dom : domain match
      url_end : suffix match
      url_len : length match
      url_reg : regex match
      url_sub : substring match
  • req.hdr([<name>[,<occ>]]) : string
      提取在一个HTTP请求报文的首部
      hdr([<name>[,<occ>]]) : exact string match
      hdr_beg([<name>[,<occ>]]) : prefix match
      hdr_dir([<name>[,<occ>]]) : subdir match
      hdr_dom([<name>[,<occ>]]) : domain match
      hdr_end([<name>[,<occ>]]) : suffix match
      hdr_len([<name>[,<occ>]]) : length match
      hdr_reg([<name>[,<occ>]]) : regex match
      hdr_sub([<name>[,<occ>]]) : substring match
    示例:
acl bad_agent hdr_sub(User-Agent) -i curl wegt
block if bad_agent
  • status : integer
      返回在响应报文中的状态码

示例:

自定义错误页
[root@centos7 ~]# mkdir errorfile
[root@centos7 ~]# cd errorfile/
[root@centos7 errorfile]# vim 503.html
<h1>503,forbidden</h1>
客户端ip:172.20.120.193
(1)定义acl规则为无效的源ip地址
    frontend web
        bind 172.20.120.255:80
        default_backend websrvs
        rspidel server
        rspadd  server:\ testapache
        acl invalid_src src 172.20.120.193   定义acl规则无效的源ip地址
        block if invalid_src      调用acl规则,block意为阻止该acl规则
        errorfile 403 /etc/haproxy/errorfiles/403.http

(2)定义acl规则为阻止以test为前缀的访问页面
    frontend web
        bind 172.20.120.255:80
        default_backend websrvs
        rspidel server
        rspadd  server:\ testapache
        acl invalid_page path_beg /test  定义acl规则为以test为前缀的访问请求
        block if invalid_page  调用acl规则,block意为阻止该acl规则
        errorfile 403 /etc/haproxy/errorfiles/403.http
(3)定义浏览器类型
    frontend web
        bind 172.20.120.255:80
        default_backend websrvs
        rspidel server 
        rspadd  server:\ testapache
        acl bad_agent hdr_sub(User-Agent) -i curl wegt   定义acl规则为curl和wget浏览器类型,并且不区分大小写
        block if bad_agent    调用acl规则,block意为阻止该acl规则
    backend websrvs
        server srv1 192.168.32.130:80 check
        server srv2 192.168.32.131:80 check
测试:
wget -O - -q  http://www.a.com/index.html
curl   http://www.a.com

预定义ACL

ACL名称等价于说明
TRUEalways_true总是匹配
FALSEalways_false从不匹配
HTTPreq_proto_http匹配HTTP协议
HTTP_1.0req_ver 1.0匹配HTTP协议1.0
HTTP_1.1req_ver 1.1匹配HTTP协议1.1
HTTP_CONTENThdr_val(content-length) gt 0匹配已存在内容长度
HTTP_URL_ABSurl_reg [/:]*?/匹配URL绝对路径
HTTP_URL_SLASHurl_beg /匹配URL相对路径
HTTP_URL_STARurl *匹配 URL 等于 “*”
LOCALHOSTsrc 127.0.0.1/8匹配从localhost来的连接
METH_CONNECTmethod CONNECT匹配HTTP CONNECT方法
METH_GETmethod GET HEADmatch HTTP GET or HEAD method
METH_HEADmethod HEAD matchHTTP HEAD method
METH_OPTIONSmethod OPTIONSmatch HTTP OPTIONS method
METH_POSTmethod POSTmatch HTTP POST method
METH_TRACEmethod TRACEmatch HTTP TRACE method
RDP_COOKIEreq_rdp_cookie_cnt gt 0match presence of an RDP cookie
REQ_CONTENTreq_len gt 0match data in the request buffer
WAIT_ENDwait_endwait for end of content analysis

示例:

frontend web
    bind 172.20.120.255:80
    default_backend websrvs
    block if METH_HEAD    调用并阻止预定义aclMETH_HEAD
backend websrvs
    server srv1 192.168.32.130:80 check
    server srv2 192.168.32.131:80 check

使用curl命令测试:
可以查看页面内容,但不能查看报文头部信息
[root@centos6 ~]# curl 172.20.120.255
RS1 Server
[root@centos6 ~]# curl -I 172.20.120.255
HTTP/1.0 403 Forbidden
Cache-Control: no-cache
Connection: close
Content-Type: text/html

配置

  • use_backend <backend> [{if | unless} <condition>]
      当if/unless一个基于ACL的条件匹配时切换指定backend
  • block { if | unless } <condition>
      阻止7层请求if/unless一个条件匹配
    示例:
    acl invalid_src src 172.16.200.2
    block if invalid_src
    errorfile 403 /usr/share/haproxy/403.http
  • http-request { allow | deny |add-header <name> <fmt> |set-header <name> <fmt> } [ { if | unless } <condition> ]
      对7层请求的访问控制
    示例:基于ACL的动静分离
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 staticsrv1 192.168.32.129:80 check
backend appsrvs
    balance roundrobin
    server app1 192.168.32.130:80 check
    server app1 192.168.32.131:8080 check

配置

  • tcp-request connection {accept|reject} [{if | unless} <condition>]
      根据第4层条件对传入连接执行操作
    示例:
listen ssh        
    bind :22222    定义监听端口,由于没有绑定具体ip地址,该端口会发布外网,为了防止外网访问,因此使用不常用的端口
    balance leastconn   最少连接算法适用于长连接,ssh远程连接属于长连接
    mode tcp     defaults配置段默认为http协议,使用四层调度,必须指定为tcp协议
    server sshsrv1 192.168.32.130:22 check  调度到后端服务器的22端口
    server sshsrv2 192.168.32.131:22 check  调度到后端服务器的22端口
在客户端进行访问测试
ssh 172.20.120.255 -p 22222   -p选项指定端口
注意:haproxy的tcp四层调度属于伪四层调度,因为一般真正的tcp四层调度会直接转发报文,而不会更改报文中的ip地址信息代替客户端访问服务器,
但haproxy把客户端的请求报文解封装,然后把自己的ip地址封装进报文,代替客户端访问后端服务器,实现四层调度,
这就改变了请求报文中源ip地址,而后端服务器看到的源ip地址就是haproxy服务器的内网地址。

支持https协议

  • 配置HAProxy支持https协议:
  • 支持ssl会话;
      bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE
      crt 后证书文件为PEM格式,且同时包含证书和所有私钥
        cat demo.crt demo.key > demo.pem
  • 把80端口的请求重向定443
      bind *:80
      redirect scheme https if !{ ssl_fc }
  • 向后端传递用户请求的协议和端口(frontend或backend)
      http_request set-header X-Forwarded-Port %[dst_port]
      http_request add-header X-Forwared-Proto https if { ssl_fc }
      注意:haproxy服务器对外使用https进行加密传输确保安全,对内则使用http协议传输即可(由于内网能够确保安全性),因此haproxy服务器也可以称为https的卸载器
    示例:HAProxy支持https协议
生成自签名证书:
cd  /etc/pki/tls/certs
[root@centos7 certs]# make a.pem
umask 77 ; \
PEM1=`/bin/mktemp /tmp/openssl.XXXXXX` ; \
PEM2=`/bin/mktemp /tmp/openssl.XXXXXX` ; \
/usr/bin/openssl req -utf8 -newkey rsa:2048 -keyout $PEM1 -nodes -x509 -days 365 -out $PEM2  ; \
cat $PEM1 >  a.pem ; \
echo ""    >> a.pem ; \
cat $PEM2 >> a.pem ; \
rm -f $PEM1 $PEM2
Generating a 2048 bit RSA private key
...............................................................................................................................................................................................................................+++
.................+++
writing new private key to '/tmp/openssl.vZ5uCN'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:beijing
Locality Name (eg, city) [Default City]:beijing
Organization Name (eg, company) [Default Company Ltd]:magedu
Organizational Unit Name (eg, section) []:opt
Common Name (eg, your name or your server's hostname) []:www.a.com
Email Address []:

cp a.pem /etc/haproxy/
vim /etc/haproxy/haproxy.cfg
    listen haproxy
        bind 192.168.32.129:9527
        acl valid_src src 192.168.32.1
        stats enable
        stats hide-version
        stats refresh 30
        stats uri /hastatus
        stats realm HAproxy\ statistics
        stats auth root:centos
        stats admin if valid_src
    frontend web
        bind 172.20.120.255:80
        bind 172.20.120.255:443 ssl crt /etc/haproxy/a.pem   使用ssl加密传输,监听443端口,调用证书crt并指定证书路径
        redirect scheme https if ! { ssl_fc }   使用redirect指令把http重定向到https
        default_backend websrvs
    backend websrvs
        server srv1 192.168.32.130:80 check
        server srv2 192.168.32.131:80 check
测试:
curl -k https://www.a.com   测试访问https协议
在后端服务器查看日志,发现传输协议仍然是http协议

知识扩展:http重定向https

实现http重定向https 
vim /etc/haproxy/haproxy.cfg
    frontend web
        bind 172.20.120.255:80
        bind 172.20.120.255:443 ssl crt /etc/haproxy/a.pem   使用ssl加密传输,调用证书crt并指定证书路径
        redirect scheme https if ! { ssl_fc }   使用redirect指令把http重定向到https
        default_backend websrvs
测试:
[root@centos6 ~]# curl -I http://www.a.com    查看报文头部是否有返回重定向响应码
HTTP/1.1 302 Found        302状态码表示重定向
Cache-Control: no-cache
Content-length: 0
Location: https://www.a.com/
Connection: close

知识扩展:自定义添加报文头部信息X-Forwarded-Port

自定义添加报文头部信息X-Forwarded-Port
vim /etc/haproxy/haproxy.cfg
    frontend web
        bind 172.20.120.255:80
        bind 172.20.120.255:443 ssl crt /etc/haproxy/a.pem
        redirect scheme https if !{ ssl_fc }
        http_request set-header X-Forwarded-Port %[dst_port]
        default_backend websrvs
在后端服务器配置文件日志格式中添加自定义字段X-Forwarded-Port
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Ag
ent}i\" \"%{clientip}i\" %{testheader}i %{X-Via}i %{X-Forwarded-Port
}i" combined

测试:
在客户端测试
curl -kL http://www.a.com
curl -kL https://www.a.com
在后端服务器查看日志,是否记录80和443端口号
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值