配置目录结构:
HAProxy学习路径:
http://www.haproxy.org
http://www.haproxy.com
文档:http://cbonte.github.io/haproxy-dconv/
程序环境:
主程序:/usr/sbin/haproxy
主配置文件:/etc/haproxy/haproxy.cfg
Unit file:/usr/lib/systemd/system/haproxy.service
配置段类型:
global:全局配置段
进程及安全配置相关的参数
性能调整相关参数
Debug参数
用户列表
peers
proxies:代理配置段
defaults:为frontend, listen, backend提供默认配置;
fronted:前端,相当于nginx, server {}
backend:后端,相当于nginx, upstream {}
listen:同时拥前端和后端
默认配置文件参数详解:
grep -Ev "^$|#" /etc/haproxy/haproxy.cfg
#######################################################################################################
global----------->#全局参数的设置(进程和安全管理:chroto、daemon、user、group、uid、pid)
log 127.0.0.1 local2----------->#log语法:log <address_1>[max_level_1]
# 最多可以定义两个,生效要先定义全局的syslog服务器
vim /etc/rsyslog.conf下消除注释并添加Local2.*
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514
# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514
local 2.* /var/log/haproxy.log 也可以指定目录
systemctl restart rsyslog;54端口的udp和tdp开启
chroot /var/lib/haproxy----------->#改变当前工作目录
pidfile /var/run/haproxy.pid----------->#当前进程id文件
maxconn 4000 ----------->#最大连接数
user haproxy ----------->#所属用户
group haproxy ----------->#所属组
daemon ----------->#以守护进程方式运行haproxy
stats socket /var/lib/haproxy/stats----------->#使用的工具:nc;socat和套接字进行通信;能看到图形化stats的文字型信息
#######################################################################################################
defaults
mode http-------------># 默认的模式mode{tcp|http|health},tcp是4层,http是7层,health只会返回OK
log global------------># 应用全局的日志配置
option httplog-----------># 启用日志记录HTTP请求,默认haproxy日志记
录是不记录HTTP请求日志
option dontlognull # 启用该项,日志中将不会记录空连接。所谓空
连接就是在上游的负载均衡器或者监控系统为
了探测该 服务是否存活可用时,需要定期的
连接或者获取某一固定的组件或页面,或者探
测扫描端口是否在监听或开放等动作被称为空
连接;官方文档中标注,如果该服务上游没有
其他的负载均衡器的话,建议不要使用该参
数,因为互联网上的恶意扫描或其他动作就不
会被记录下来
option http-server-close #每次请求完毕后主动关闭http通道
option forwardfor except 127.0.0.0/8----------->#如果服务器上的应用程序想记录发起请求的客户端的IP地址,需要在HAProxy上配置此选项,这样HAProxy会把
客户端的IP信息发送给服务器,在HTTP请求中添加"X-Forwarded-For"字段。启用X-Forwarded-For,在requests头部插入客户端IP发送给后端的server,使后端server获取到客户端的真实IP。
option redispatch----------->#当使用了cookie时,haproxy将会将其请求的后端服务器的serverID插入到cookie中,以保证会话的SESSION持久性;而此时,
如果后端的服务器宕掉了,但是客户端的cookie是不会刷新的,如果设置此参数,将会将客户的请求强制定向到另外一个后端server上,以保证服务的正常。
retries 3-----------># 定义连接后端服务器的失败重连次数,连接失败次数超过此值后将会将对应后端服务器标记为不可用
timeout http-request 10s #http请求超时时间
timeout queue 1m #一个请求在队列里的超时时间
timeout connect 10s #连接超时
timeout client 1m #客户端超时
timeout server 1m #服务器端超时
timeout http-keep-alive 10s #设置http-keep-alive的超时时间
timeout check 10s #检测超时
maxconn 3000 #每个进程可用的最大连接数
frontend main *:80 #监听地址为80
acl url_static path_beg -i /static /images /javascript /stylesheets
acl url_static path_end -i .jpg .gif .png .css .js
use_backend static if url_static
default_backend duanx_vip----------->#定义一个名为duanx_vip前端部分。此处将对于的请求转发给后端
backend static----------->##使用了静态动态分离(如果url_path匹配 .jpg .gif .png .css .js静态文件则访问此后端)
balance roundrobin----------->#负载均衡算法(#banlance roundrobin轮询,balance source 保存session值,支持static-rr,leastconn,first,uri等参数)
server static 127.0.0.1:80
check----------->#静态文件部署在本机(也可以部署在其他机器或者squid缓存服务器)
backend duanx_vip----------->#定义一个名为duanx_vip后端部分。PS:此处duanx_vip只是一个自定义名字而已,但是需要与frontend里面配置项default_backend值相一致
balance roundrobin----------->#负载均衡算法
server web01 172.20.222.1:80 check inter 2000 fall 3 weight 30----------->#定义的多个后端
server web02 172.20.222.2:80 check inter 2000 fall 3 weight 30----------->#定义的多个后端
server web03 172.20.222.3:80 check inter 2000 fall 3 weight 30---------->#定义的多个后端
#######################################################################################################
代理配置段常见参数详解
bind:指定一个或多个前端侦听地址和端口
格式:bind [<address>]:<port_range> [, ...] [param*]
listen http_proxy
bind :80,:443
bind 10.0.0.1:10080,10.0.0.1:10443
bind /var/run/ssl-frontend.sock user root mode 600accept-proxy
balance:后端服务器组内的服务器调度算法
调度算法:
roundrobin:server options: weight #
动态算法:支持权重的运行时调整,支持慢启动;每个后端中最多支持4095个server;
static-rr:
静态算法:不支持权重的运行时调整及慢启动;后端主机数量无上限;
leastconn:动态
最少连接,推荐使用在具有较长会话的场景中,例如MySQL、LDAP等;
rr适用于短连接,如:http,一个请求后响应后连接就断开了,curl
first:
根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务;优先使用第一个,节约服务器数量
source:源地址hash,新连接先按权重分配,后续连接按source分配请求
除权取余法:静态
一致性哈希:动态
uri:对缓存服务器特别有效
对URI的左半部分或整个uri做hash计算,并由服务器总权重相除以后派发至某挑出的服务器;
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
左半部分:/<path>;<params>
整个uri:/<path>;<params>?<query>#<frag>
请求相同uri都绑定到相同后端服务器上举例:
172.20.222.2:backend websrvs
balance uri
server web1 172.17.0.2:80 check
server web2 172.17.0.3:80 check
两容器中for i in {1..10};do echo "Test Page $i @web1 > ./test$i.html;done
172.20.222.1:curl http://172.20.222.2/test$i.html
172.20.222.3: curl http://172.20.222.2/test$i.html
url_param:对用户请求的uri的<params>部分中的参数的值(通常为用户ID)作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;
通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个Backend Server;
username=tom
hdr(<name>):对于每个http请求,此处由<name>指定的http首部将会被取出做hash计算; 并由服务器总权重相除以后派发至某挑出的服务器;没有有效值的会被轮询调度;
如:hdr(Cookie) hdr(host)
rdp-cookie远程桌面相关
rdp-cookie(<name>)
hash-type:哈希算法
需配合参数:hash-type <method> <function> <modifier>
method:
map-based:除权取余法,哈希数据结构是静态的数组;
consistent:一致性哈希,哈希数据结构是一个树;整体影响变为局部影响
<function> is the hash function to be used : 哈希函数
sdbm
djb2
wt6
server:定义后端主机的各服务器的相关选项
语法:
server <name> <address>[:[port]] [param*]
<name>:服务器在haproxy上的自定义名称;出现在日志及警告信息
<address>:服务器地址,支持使用主机名
[:[port]]:端口映射;省略时,表示同bind中绑定的端口
[param*]:server后可加的参数
weight <weight>:权重,默认为1
maxconn <maxconn>:当前server的最大并发连接数
backlog <backlog>:当server的连接数达到上限后的后援队列长度
backup:设定当前server为备用服务器
active,backup:
ctice都为活动的,宕机后backup再来say server
check:对当前server做健康状态检测,只用于四层检测
注意: httpchk, “smtpchk”, “mysql-check”, “pgsql-check” and “sslhello-chk” 用于定义应用层检测方法
addr :检测时使用的IP地址(检测的不一定是vip)
port :针对此端口进行检测
inter <delay>:连续两次检测之间的时间间隔,默认单位为毫秒,默认为2000ms
rise <count>:连续多少次检测结果为“成功”才标记服务器为可用;默认为2
fall <count>:连续多少次检测结果为“失败”才标记服务器为不可用;默认为3
disabled:标记为不可用
redir <prefix>:将发往此server的所有GET和HEAD类的请求重定向至指定的URL
cookie <value>:为当前server指定cookie值,实现基于cookie的会话黏性。如下:
基于cookie的session sticky的实现:网页记录一次后续会一直都有
frontend http
bind 172.20.222.1:80
default_backend websrvs
backend websrvs
cookie WEBSRV insert nocache indirect#自定义会话添加cookie信息WEBSRV,insert:插入;nocache:不缓存增加保密性
server srv1 172.20.222.1:80 weight 2 check rise 1 fall 2 maxconn 3000 cookie srv1#自定义该server添加cookie信息为srv1
server srv2 172.20.222.2:80 weight 1 check rise 1 fall 2 maxconn 3000 cookie srv2#自定义该server添加cookie信息为srv2
server sorroyserver 172.20.222.4:80 backup
统计接口启用相关的参数:(实现图形化配置参数)
stats enable
启用统计页;基于默认的参数启用stats page;
- stats uri : /haproxy?stats 默认路径位置 如:172.20.222.2/haproxy?stats
- stats realm : "HAProxy Statistics" 函数框对用户的提示信息
- stats auth : no authentication 做basic认证
- stats scope : no restriction对用户没有限制,都可以访问
stats auth <user>:<passwd>认证时的账号和密码,可使用多次;如多个用户定义多行即可,
eg:
stats auth ha1:centos1
stats auth ha2:centos2
stats realm <realm>认证时浏览器弹出对话框的提示信息
stats hide-version若想隐藏版本加上此参数即可
stats uri <prefix>自定义stats page uri默认为/haproxy?stats 可自定义uri
eg:stats uri /hastas 重启后访问http://172.18.43.62/hastas即可
stats refresh <delay>设定自动刷新时间间隔;
若服务器出现故障,默认手动刷新才能才能看到状态的变化,可设置自动刷新
eg:添加stats refresh 2s
stats admin { if | unless } <cond> cond为访问控制列表,启用stats
配置示例:
listen stats
bind :9090 放监控页面放置独立服务上
stats enable
stats uri /damin?stats 将页面自定义设置以防别人轻松访问
stats realm HAPorxy\ Stats\ Page
stats auth admin:admin
stats admin if TRUE 启用本机才能打开
default中定义的内容:
可在fronted、backend、listen中分别定义,如没有指定将默认default中设置
maxconn <conns>:为指定的frontend定义其最大并发连接数;默认为2000;
mode { tcp|http|health }
定义haproxy的工作模式;
tcp:基于layer4实现代理;可代理mysql, pgsql, ssh, ssl等协议;
http:仅当代理的协议为http时使用;
health:工作为健康状态7层检查的响应模式,当连接请求到达时回应“OK”后即断开连接;
TCP模式的健康状态检测示例:
listen ssh
bind :22022
balance leastconn
mode tcp
server sshsrv1 172.16.100.6:22 check
server sshsrv2 172.16.100.7 :22 check
forwardfor设置
语法:option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
在由haproxy发往后端主机的请求报文中添加“X-ForwardedFor”首部,其值为前端客户端的地址;用于向后端主发送真实的客户端IP
[ except <network> ]:请求报文来自此处指定的网络时不予添加此首部;
[ header <name> ]:使用自定义的首部名称,而非“X-Forwarded-For”;
[ if-none ] 如果没有首部才添加首部,如果有使用默认值
默认defaults中有一条配置option forwardfor except 127.0.0.0/8
若想后端日志记录真实请求客户端IP,需更改后端两台服务器配置文件:
vim /etc/httpd/conf/httpd.conf
LogFormat "%{x-forwarded-for}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" haformat
#添加日志格式
CustomLog logs/access_log haformat #修改记录日志
重载客户端httpd服务,浏览器刷新请求。在客户端观看日志即可看到真实请求服务器
tail -f /var/log/httpd/access_log
自定义错误页面
语法:errorfile <code> <file>
<code>:HTTP status codes,200,400,403,408,500,502,503,504.代理服务器不能合成404,后端服务器才可以
<file>:错误页文件路径
eg:errorfile 400 /etc/haproxy/errorfiles/400badreq.http
errorloc <code> <url>相当于errorloc302 <code> <url>,利用302重定向至URL
eg:errorloc 403 http://www.duanx.vip/error_pages/403.html
修改报文首部:
1)reqadd <string> [{if | unless} <cond>] 在请求报文尾部添加指定首部(用于web端区分从哪个调度器发来请求)
eg:在frontend中添加 reqadd X-via:\ haproxy1
后端修改httpd.conf中logformat添加%{X-via}i
再次访问日志就会看到是通过哪个调度器调度到本机
2)rspadd <string> [{if | unless} <cond>]在响应报文尾部添加指定首部 (用于haproxy之前的调度器查看用于排错)
eg:rspadd X-Via:\ HAPorxy
3)reqdel <search> [{if | unless} <cond>]
reqidel <search> [{if | unless} <cond>] (ignore case忽略大小写)
从请求报文中删除匹配正则表达式的首部
4)rspdel <search> [{if | unless} <cond>]
rspidel <search> [{if | unless} <cond>] (ignore case忽略大小写)
从响应报文中删除匹配正则表达式的首部
eg:rspidel Server.* 用于隐藏web服务器版本信息
reqidel User-Agent 不能通过日志来查看信息
client:172.20.222.1
curl -b "WEBSRV=web1" http://172.20.222.2/
host:172.20.222.2
docker logs web1
使用前:172.20.222.1 - - [13/Nov/2018:05:10:32 +0000] "GET / HTTP/1.1" 200 50 "-" "curl/7.29.0"
使用后:172.20.222.1 - - [13/Nov/2018:05:33:19 +0000] "GET /HTTP/1.1" 200 50 "-" "-"
定义连接超时:
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>后端服务器半连接的空闲时长
日志系统:
log:
log global调用全局定义的日志系统
log <address> [len <length>] <facility> [<level> [<minlevel>]]
no log
官网查看haproxy的日志格式!!!
Nov 13 13:50:27 localhost haproxy[4608]: 172.20.222.1:44524 [13/Nov/2018:13:50:27.075] myweb websrvs/web1 0/0/0/0/0 200 294 - - --VN 1/1/0/1/0 0/0 "GET / HTTP/1.1"
注意:
默认发往本机的日志服务器;
(1) local2.* /var/log/local2.log
(2) $ModLoad imudp
$UDPServerRun 514
log-format <string>:
capture cookie <name> len <length>
capture request header <name> len <length>
capture response header <name> len <length>
capture response header Content-length len 9
capture response header Location len 15
压缩功能:
compression algo <algorithm> ...:启用http协议的压缩机制,指明压缩算法gzip, deflate;
compression type <mime type> ...:指明压缩的MIME类型;常适用于压缩的类型为文本类型;
健康状态检测:
option httpchk
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <version>
定义基于http协议的7层健康状态检测机制;
eg:option httpchk GET /test1.html
http-check expect [!] <match> <pattern>
ACL:访问控制列表
提供了一个灵活的解决方案来执行内容交换,并且通常基于从请求中提取的内容、响应或任何环境状态进行决策,是haproxy的重要特色。
1、语法:
格式:acl <aclname> <criterion> [flags] [operator] [<value>] ...ACL名称,可使用字母数字,区分字符大小写
<criterion>:比较的标准和条件
dst 目标IP
dst_port 目标PORT
src 源IP
src_port 源PORT
示例: acl invalid_src src 172.20.222.1
<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进行匹配
<value>的类型:
- boolean
- integer or integer range
- IP address / network
- string (exact, substring字串, suffix后缀, prefix前缀, subdir,domain)
- regular expression
- hex block
2、匹配条件<criterion>进阶:
(1)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
(2)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
eg:acl adminpath path_beg ?-i ?/admin
acl imagefile ?path_end ?.jpg ?.png ? .bmp
(3)url : string提取请求中的URL。一个典型的应用是具有预取能力的缓存,以及需要从数据库聚合多个信息并将它们保存在缓存中的网页门户入口
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
(4)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
(5)status : integer返回在响应报文中的状态码
3、ACL作为条件时的逻辑关系:
- 与:隐式(默认)使用
- 或:使用“or” 或 “||”表示
- 否定:使用“!“ 表示
同一个组名可定义多次
示例: if invalid_src invalid_port 与关系
if invalid_src || invalid_port 或
if ! invalid_src 非
4、指定backend组
use_backend <backend> [{if | unless} <condition>]
当符合指定的条件时使用特定的backend;经常和ACL结合在一起使用;
5、配置block拒绝访问
block { if | unless } <condition> 阻止7层请求if/unless一个条件匹配
acl invalid_src src 172.16.200.2
block if invalid_src
errorfile 403 /etc/fstab
6、http7层访问控制
语法:http-request { allow | deny } [ { if | unless } <condition> ]
Access control for Layer 7 requests 应用窄的放上,多的放下
7、tcp4层访问控制
语法:tcp-request connection {accept|reject} [{if | unless} <condition>]
根据第4层条件对传入连接执行操作
示例:
listen ssh
bind :22022
balance leastconn
acl invalid_src src 172.20.222.1
tcp-request connection reject if invalid_src
mode tcp
server sshsrv1 172.20.222.2:22 check
server sshsrv2 172.20.222.3:22 check backup
8、配置HAProxy支持https协议:详见下文实验
502:代理服务器和后端服务器通信建立连接超时,bad gateway
问题:后端服务器连接满载(忙不过来),排查后端服务器出了什么问题?
排查思路:底层网络通信、传输层连接、应用层应用,后端服务器是不是满载(CPU/IO/内存等 )
运维三大核心职能之一:发布
灰度:排干模式(动态算法的w0),在金丝雀发布的过程中有新旧版本成为灰度
金丝雀:小白鼠,用来测试版本的试验性
蓝绿:生产和测试版本来回切换,大公司用
转载请注明:黑夜 » HAProxy系列(二)全局、代理配置详解