Docker HAproxy 配置 & rsyslog 日誌處理

環境

CentOS Linux release 7.9.2009 (Core)
HAProxy version 2.3.6-7851701, released 2021/03/03
IP: 192.168.0.1

Docker 安裝

Docker 安裝

建立haproxy設定檔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 新建目錄
mkdir -p /etc/haproxy

# 備份設定檔
cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.`date +%Y%m%d_%H%M%S`

# 寫入設定檔
cat << EOF > /etc/haproxy/haproxy.cfg
global # 全域引數配置
  daemon # 後台執行
  nbthread 16 # 執行緒數,新版本已拋棄nbproc引數
  log 127.0.0.1 local3 info # 定義日誌分別輸出到local3、4
  log 127.0.0.1 local4 warning # 日誌級別不同

defaults # 預設引數配置
  mode tcp # 代理人模式tcp、http
  retries 3 # 檢測次數
  maxconn 32768 # 每一個代理的最大連接數
  timeout connect 5s # 成功連接到一台伺服器的最長等待時間
  timeout client 5s # 連接客戶端發送資料時的成功連接最長等待時間
  timeout server 5s # 伺服端回應客戶度資料發送的最長等待時間

listen proxy01 # 代理01,名字自定義
  bind *:5000 # 偵聽IP和連接埠,單一IP或多個,0.0.0.0:5000 | 192.168.0.1:5000
  mode http  # 代理人模式,覆蓋了上面預設配置
  balance roundrobin # 負載均衡方式,輪詢
  option httplog # 日誌紀錄HTTP請求
  option dontlognull # 日誌中將不會紀錄空連接
  option forwardfor # 啟用X-Forwarded-For,在requests頭部寫入客戶端IP發送給後端的server,使後端server取得到客戶端的真實IP
  http-request set-header Host www.examplesite.com # 設定頭,有時候後端伺服器需要,不需要可不設定
 
  # HAProxy持久連接方式,最後說明
  option http-server-close
  option http-pretend-keepalive

  # 日誌格式
  #log-format %ci:%cp %si:%sp %B %U %ST %r %b %f %bi %hrl %hsl
  log-format {<!-- -->"haproxy_clientIP":"%ci","haproxy_clientPort":"%cp","haproxy_dateTime":"%t","haproxy_frontendNameTransport":"%ft","haproxy_backend":"%b","haproxy_serverName":"%s","haproxy_Tw":"%Tw","haproxy_Tc":"%Tc","haproxy_Tt":"%Tt","haproxy_bytesRead":"%B","haproxy_terminationState":"%ts","haproxy_actconn":,"haproxy_FrontendCurrentConn":,"haproxy_backendCurrentConn":,"haproxy_serverConcurrentConn":%sc,"haproxy_retries":%rc,"haproxy_srvQueue":%sq,"haproxy_backendQueue":%bq,"haproxy_backendSourceIP":"%bi","haproxy_backendSourcePort":"%bp"}

  # 後端伺服器
  server website01 192.168.1.10:80 weight 1 maxconn 10000 check inter 10s
  server website02 192.168.1.20:80 weight 1 maxconn 10000 check inter 10s

listen proxy02 # 代理02,名字自定義
  bind 192.168.0.1:10881
  mode tcp
 
  option httpchk GET /test/index.php # 檢測後端伺服器頁面是否正常,預設是檢測連接埠
  balance leastconn # 負載均衡方式,見最後說明
  log-format {<!-- -->"haproxy_clientIP":"%ci","haproxy_clientPort":"%cp","haproxy_dateTime":"%t","haproxy_frontendNameTransport":"%ft","haproxy_backend":"%b","haproxy_serverName":"%s","haproxy_Tw":"%Tw","haproxy_Tc":"%Tc","haproxy_Tt":"%Tt","haproxy_bytesRead":"%B","haproxy_terminationState":"%ts","haproxy_actconn":,"haproxy_FrontendCurrentConn":,"haproxy_backendCurrentConn":,"haproxy_serverConcurrentConn":%sc,"haproxy_retries":%rc,"haproxy_srvQueue":%sq,"haproxy_backendQueue":%bq,"haproxy_backendSourceIP":"%bi","haproxy_backendSourcePort":"%bp"}
  server server1 192.168.2.10:10000 weight 1 maxconn 10000 check inter 5s
  server server2 192.168.2.20:10000 weight 1 maxconn 10000 check inter 5s

listen admin_stats # 狀態頁
        bind *:1080
        bind-process 1 # 狀態頁行程數,預設會有警告
        mode http
        option httplog
        option dontlognull

        log-format {<!-- -->"haproxy_clientIP":"%ci","haproxy_clientPort":"%cp","haproxy_dateTime":"%t","haproxy_frontendNameTransport":"%ft","haproxy_backend":"%b","haproxy_serverName":"%s","haproxy_Tw":"%Tw","haproxy_Tc":"%Tc","haproxy_Tt":"%Tt","haproxy_bytesRead":"%B","haproxy_terminationState":"%ts","haproxy_actconn":,"haproxy_FrontendCurrentConn":,"haproxy_backendCurrentConn":,"haproxy_serverConcurrentConn":%sc,"haproxy_retries":%rc,"haproxy_srvQueue":%sq,"haproxy_backendQueue":%bq,"haproxy_backendSourceIP":"%bi","haproxy_backendSourcePort":"%bp"}
       
        maxconn 10 # 狀態頁的最大連接數
        stats refresh 30s # 重新整理時間
        stats uri /hastats # 狀態頁位置 uri
        stats realm XXX-XXX # 登入框提示
        stats auth admin:qR49cRBNY5H # 登入訊息
        stats hide-version # 隱藏狀態頁的版本訊息,顯示有安全風險
EOF

rsyslog日誌配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 配置haproxy日誌

# 設定檔生效引數 UDP 接收日誌資料 /etc/rsyslog.conf
# $ModLoad imudp
# $UDPServerRun 514
# 取代Rsyslog設定檔註解掉的引數
sed -i 's/#$ModLoad imudp/$ModLoad imudp/' /etc/rsyslog.conf
sed -i 's/#$UDPServerRun 514/$UDPServerRun 514/' /etc/rsyslog.conf

# 在local3收info的日誌寫入檔案
echo "local3.*   /var/log/haproxy.log" >> /etc/rsyslog.conf
# 在local4收warning的日誌寫入檔案
echo "local4.*   /var/log/haproxy_warning.log" >> /etc/rsyslog.conf


systemctl restart rsyslog

日誌切割神器 logrotate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 這個配置將會每天轉儲/var/log/haproxy.log檔案
# /etc/logrotate.conf 設定檔有 include /etc/logrotate.d
# 在/etc/logrotate.d下面寫入一個設定檔
cat << EOF > /etc/logrotate.d/haproxy
/var/log/haproxy.log {<!-- --> # 處理的日誌檔案
    missingok # 在日誌輪循期間,任何錯誤將被忽略,例如 「檔案無法找到」 之類的錯誤
    daily # 每日
    compress # 壓縮
    minsize 10M # 最小size
    rotate 7 # 保留份數
    notifempty # 如果是空檔案的話,不轉儲
    dateext # 轉儲檔案加日期,效果:haproxy.log-20210320.gz
}
EOF

# 同上,處理warning日誌
cat << EOF > /etc/logrotate.d/haproxy
/var/log/haproxy_warning.log {<!-- -->
    missingok
    daily
    compress
    minsize 10M
    rotate 7
    notifempty
    dateext
}
EOF

Docker執行

1
2
3
4
5
6
docker pull haproxy
docker run -d -it --name haproxy --restart=always
  --net=host
  -v /etc/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg  # 對映設定檔
  -v /etc/localtime:/etc/localtime  # 同步容器時間
haproxy:latest

作業系統調校

1
2
3
4
5
6
7
8
9
10
11
12
13
# 作業系統引數調校
cat << EOF >> /etc/sysctl.conf
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_port_range="1024 65024"
net.ipv4.tcp_max_syn_backlog=100000
net.core.netdev_max_backlog=100000
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout = 10
fs.file-max=500000
EOF

echo '*  -  nofile  500000' >> /etc/security/limits.conf

負載均衡方式

balance url_param [check_post]
定義後端使用的負載演算法。可用區域:
defaults | frontend | listen | backend
yes | no | yes | yes
.
1、 roundrobin:表示簡單的輪詢,每個伺服器根據權重輪流使用,在伺服器的處理時間平均分配的情況下這是最流暢和公平的演算法。該演算法是動態的,對於例項啟動慢的伺服器權重會在執行中調整。
2、static-rr:每個伺服器根據權重輪流使用,類似roundrobin,但它是靜態的,意味著執行期修改許可權是無效的。另外,它對伺服器的數量沒有限制。該演算法一般不用;
3、first:可用連接槽的第一個伺服器接收連接。並且在第一個伺服器恢復之後,能夠主動切回來,對於MySQL主主代理來說,絕對是一個福音。
4、 leastconn:連接數最少的伺服器優先接收連接。leastconn建議用於長會話服務,例如LDAP、SQL、TSE等,而不適合短會話協定。如HTTP.該演算法是動態的,對於例項啟動慢的伺服器權重會在執行中調整。
5、source:對請求源IP地址進行雜湊,用可用伺服器的權重總數除以雜湊值,根據結果進行分配。只要伺服器正常,同一個客戶端IP地址總是訪問同一個伺服器。如果雜湊的結果隨可用伺服器數量而變化,那麼客戶端會定向到不同的伺服器;該演算法一般用於不能寫入cookie的Tcp模式。它還可以用於廣域網路上為拒絕使用會話cookie的客戶端提供最有效的粘連;該演算法預設是靜態的,所以執行期修改伺服器的權重是無效的,但是演算法會根據「hash-type」的變化做調整。
6、uri:表示根據請求的URI左端(問號之前)進行雜湊,用可用伺服器的權重總數除以雜湊值,根據結果進行分配。只要伺服器正常,同一個URI地址總是訪問同一個伺服器。一般用於代理快取和反病毒代理,以最大限度的提高快取的命中率。該演算法只能用於HTTP後端;該演算法一般用於後端是快取伺服器;該演算法預設是靜態的,所以執行期修改伺服器的權重是無效的,但是演算法會根據「hash-type」的變化做調整。
7、url_param:在HTTP GET請求的搜尋串中搜尋中指定的URL引數,基本上可以鎖定使用特製的URL到特定的負載均衡器節點的要求;該演算法一般用於將同一個使用者的訊息發送到同一個後端伺服器;該演算法預設是靜態的,所以執行期修改伺服器的權重是無效的,但是演算法會根據「hash-type」的變化做調整。
8、hdr(name):在每個HTTP請求中搜尋HTTP標頭,HTTP標頭將被看作在每個HTTP請求,並針對特定的節點;如果缺少頭或者頭沒有任何值,則用roundrobin代替;該演算法預設是靜態的,所以執行期修改伺服器的權重是無效的,但是演算法會根據「hash-type」的變化做調整。
9、rdp-cookie(name):為每個進來的TCP請求搜尋並雜湊RDP cookie;該機制用於退化的持久模式,可以使同一個使用者或者同一個會話ID總是發送給同一台伺服器。如果沒有cookie,則使用roundrobin演算法代替;該演算法預設是靜態的,所以執行期修改伺服器的權重是無效的,但是演算法會根據「hash-type」的變化做調整。

HAProxy持久連接方面的引數

By default HAProxy operates in a tunnel-like mode with regards to persistent connections: for each connection it processes the first request and forwards everything else (including additional requests) to selected server.
Once established, the connection is persisted both on the client and server sides.
Use 「option http-server-close」 to preserve client persistent connections while handling every incoming request individually, dispatching them one after another to servers, in HTTP close mode.
Use 「option httpclose」 to switch both sides to HTTP close mode.
「option forceclose」 and 「option http-pretend-keepalive」 help working around servers misbehaving in HTTP close mode.

預設情況下,HAProxy在持久連接方面以類似於隧道的模式執行:對於每個連接,HAProxy處理第一個請求並將其他所有內容(包括其他請求)轉發到選定的伺服器。
建立後,連接將在客戶端和伺服端均保持不變。
使用「選項http-server-close」可保留客戶端持久連接,同時分別處理每個傳入請求,並以HTTP關閉模式將它們一個接一個地分派給伺服器。
使用「 option httpclose」將雙方都切換到HTTP關閉模式。
「 option forceclose」和「 option http-pretend-keepalive」有助於解決在HTTP關閉模式下行為異常的伺服器。

logrotate

logrotate 是一個 linux 系統日誌的管理工具。可以對單個日誌檔案或者某個目錄下的檔案按時間 / 大小進行切割,壓縮操作;指定日誌儲存數量;還可以在切割之後執行自定義命令。

logrotate 是基於 crontab 執行的,所以這個時間點是由 crontab 控制的,具體可以搜尋 crontab 的設定檔 /etc/anacrontab。 系統會按照計劃的頻率執行 logrotate,通常是每天。在大多數的 Linux 發行版本上,計劃每天執行的腳本位於 /etc/cron.daily/logrotate。

主流 Linux 發行版上都預設安裝有 logrotate 包,如果你的 linux 系統中找不到 logrotate, 可以使用 apt-get 或 yum 命令來安裝。

執行檔案: /usr/sbin/logrotate
主設定檔: /etc/logrotate.conf
自定義設定檔: /etc/logrotate.d/*.conf
修改設定檔後,並不需要重啟服務。
由於 logrotate 實際上只是一個執行檔,不是以 daemon 執行。

常見引數
daily :指定轉儲週期為每天
weekly :指定轉儲週期為每周
monthly :指定轉儲週期為每月
rotate count :指定日誌檔案刪除之前轉儲的次數,0 指沒有備份,5 指保留 5 個備份
tabooext [+] list:讓 logrotate 不轉儲指定副檔名的檔案,預設的副檔名是:.rpm-orig, .rpmsave, v, 和~
missingok:在日誌輪循期間,任何錯誤將被忽略,例如 「檔案無法找到」 之類的錯誤。
size size:當日誌檔案到達指定的大小時才轉儲,bytes (預設) 及 KB (sizek) 或 MB (sizem)
compress: 透過 gzip 壓縮轉儲以後的日誌
nocompress: 不壓縮
copytruncate:用於還在開啟中的日誌檔案,把當前日誌備份並截斷
nocopytruncate: 備份日誌檔案但是不截斷
create mode owner group : 轉儲檔案,使用指定的檔案模式建立新的日誌檔案
nocreate: 不建立新的日誌檔案
delaycompress: 和 compress 一起使用時,轉儲的日誌檔案到下一次轉儲時才壓縮
nodelaycompress: 覆蓋 delaycompress 選項,轉儲同時壓縮。
errors address : 專儲時的錯誤訊息發送到指定的 Email 地址
ifempty :即使是空檔案也轉儲,這個是 logrotate 的預設選項。
notifempty :如果是空檔案的話,不轉儲
mail address : 把轉儲的日誌檔案發送到指定的 E-mail 地址
nomail : 轉儲時不發送日誌檔案
olddir directory:儲後的日誌檔案放入指定的目錄,必須和當前日誌檔案在同一個檔案系統
noolddir: 轉儲後的日誌檔案和當前日誌檔案放在同一個目錄下
prerotate/endscript: 在轉儲以前需要執行的命令可以放入這個對,這兩個關鍵字必須單獨成行

參考資料

https://blog.csdn.net/vanexph/article/details/106719157
https://github.com/kunpengcompute/kunpengcompute.github.io/issues/38
https://blog.51cto.com/liuzhengwei521/1927984
https://blog.51cto.com/leejia/1421882
http://www.haproxy.org/download/1.4/doc/configuration.txt
https://wsgzao.github.io/post/logrotate/