WEB应用

Haproxy安装部署文档及多配置文件管理方案

Jager · 9月2日 · 2017年 · · 2947次已读

最近我在负责一个统一接入层的建设项目,涉及到 Haproxy 和 ospf 的运维部署,本文分享一下我在部署 Haproxy 之后整理的运维部署规范,并实现了Haproxy 的多配置文件管理方案Haproxy安装部署文档及多配置文件管理方案

一、部署安装

1、下载源码包

最新 stable 版本下载地址:http://www.haproxy.org/download/1.7/src/haproxy-1.7.9.tar.gz

2、编译安装

tar zxf haproxy-1.7.9.tar.gz
cd haproxy-1.7.9
make TARGET=linux31 prefix=/usr/local/haproxy
make install PREFIX=/usr/local/haproxy

3、创建目录

mkdir -p /usr/local/haproxy/conf/ready/tcp
mkdir -p /usr/local/haproxy/conf/ready/http
mkdir -p /usr/local/haproxy/conf/enabled/tcp
mkdir -p /usr/local/haproxy/conf/enabled/http
mkdir -p /usr/local/haproxy/logs
mkdir -p /data/wwwlogs/logs

二、软件配置

熟悉 Nginx 和 Apache 的朋友都知道,这两个 Webservice 都支持 include 加载多个配置文件的语法,但是 Haproxy 并不支持!如果现网映射规则非常多,那么 haproxy.cfg 这个配置文件就跟臭袜子一样,又臭又长!

因此,我也是翻遍了国外的各种论坛帖子,终于发现一种变相实现 Haproxy 多配置文件的方案。其实,Hparoxy 是支持多配置文件的,但是不是 include 语法,而是在启动的时候多次使用-f 拼接配置文件,比如:

cd /usr/local/haproxy/sbin
./haproxy -f ../conf/haproxy.cfg -f ../conf/ext1.cfg -f ../conf/ext2.cfg

因此,我们可以在配置文件目录以及启动脚本上做点改变,让 Haproxy 支持多配置文件。

1、路径约定:

  • 待上线的 tcp 映射规则存放目录:/usr/local/haproxy/conf/ready/tcp
  • 待上线的 http 映射规则存放目录:/usr/local/haproxy/conf/ready/http
  • 已上线的 tcp 映射规则存放目录:/usr/local/haproxy/conf/enabled/tcp
  • 已上线的 http 映射规则存放目录:/usr/local/haproxy/conf/enabled/http
  • Ps:本文为多配置模式,enabled 里面的配置为软链接形式,软链接至 ready 对应配置文件,方便管理。

2、配置模板

①、主配置:haproxy.cfg

#configure haproxy.cfg
global
    log 127.0.0.1   local0
    maxconn 4096              #最大连接数
    chroot /usr/local/haproxy #安装目录
    uid 99                    #用户 nobody
    gid 99                    #组 nobody
    daemon                    #守护进程运行
    nbproc 1                  #进程数量
    pidfile /usr/local/haproxy/logs/haproxy.pid #haproxy pid

defaults
   log     global
   mode    http               #7 层 http;4 层 tcp  如果要让 haproxy 支持虚拟主机,mode 必须设为 http 
   option  httplog            #http 日志格式
   log 127.0.0.1 local6
   option  httpclose          #主动关闭 http 通道
   option  redispatch         #serverId 对应的服务器挂掉后,强制定向到其他健康的服务器
   retries 1
   option  dontlognull
   maxconn 2000                     #最大连接数
   timeout connect      3600000     #连接超时(毫秒)
   timeout client      3600000      #客户端超时(毫秒)
   timeout server      3600000      #服务器超时(毫秒)

frontend default   
        option  httplog
        option  httpclose
        bind 0.0.0.0:80
        # 状态页面规则
        acl haproxy_stats   path_beg /haproxy
        use_backend haproxy_stats if haproxy_stats
        # 其他
        # default_backend default_server
        # 提升失败的时候的用户体验
        #errorfile 502 /usr/local/haproxy/html/maintain.html
        #errorfile 503 /usr/local/haproxy/html/maintain.html
        #errorfile 504 /usr/local/haproxy/html/maintain.html

# 状态页面
backend haproxy_stats
    stats uri /haproxy
    stats enable
    stats refresh 60s
    #stats auth admin:admin  # 状态页面认证配置
    stats admin if TRUE

②、http 扩展配置文件模板

frontend demo
        option httplog
        option httpclose
        bind 192.168.1.10:80 # 扩展
        # 域名匹配范例
        acl is_demo hdr_beg(host) -i demo.oa.com
        # 正则范例范例
        acl is_demo_rex hdr_reg(host) -i ^demo[0-9].oa.com$
        # 路径匹配范例
        acl is_demo_path path_beg /demo/path
        use_backend demo_oa_com if is_demo || is_demo_rex ||  is_demo_path

backend http_demo_ext
        mode http
        # 额外的一些设置,按需使用
        option forwardfor
        option forwardfor header Client-IP
        option http-server-close
        option httpclose
        #balance roundrobin    #负载均衡的方式,轮询方式
        #balance leastconn     #负载均衡的方式,最小连接
        balance source         #负载均衡的方式,根据请求的源 IP
        cookie SERVERID insert nocache indirect  # 插入 serverid 到 cookie 中,serverid 后面可以定义
        # 健康检查
        option httpchk HEAD /index.html HTTP/1.1\r\nHost:\ demo.oa.com
        server x.x.x.x x.x.x.x:80 cookie server1 check inter 2s rise 3 fall 3 weight 3 
        server x.x.x.x x.x.x.x:80 cookie server1 check inter 2s rise 3 fall 3 weight 3

③、tcp 扩展配置文件模板

listen tcp_demo_ext
    bind 0.0.0.0:3306
    mode tcp
    server x.x.x.x x.x.x.x:3306 weight 1 check inter 1s rise 2 fall 2
    server x.x.x.x x.x.x.x:3306 weight 1 check inter 1s rise 2 fall 2

Ps:多配置模式中,多个 frontend 必须绑定不同的 IP 或者端口,否则数据会串,导致映射到不同的后端而报错。因此,同一个 IP+端口下的映射务必配置到同一个 frontend 模块内。

三、系统服务

1、服务脚本

对比已有的 Haproxy 脚本,我编写的时候新增了如下实用功能:

  • 支持配置文件语法测试
  • 支持进程的监控(自拉起)功能
  • 重启之前会先检测配置语法,规避因配置错误导致重启后进程挂掉
  • 支持多配置文件模式(按照前文约定目录存放拓展配置,脚本将自动识别)

下面是服务脚本代码:

#!/bin/bash
###################################################################
#  Haproxy Service Script 1.0.0 Author: Jager <[email protected]>    #
#  Common Operations(start|stop|restart|mon|test)                 #
#-----------------------------------------------------------------#
#  For more information please visit https://zhang.ge/5125.html #
#  Copyright @2017 zhang.ge. All rights reserved.              #
###################################################################
# chkconfig: 35 10 90 
export PATH=/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:$PATH
PROCESS_NAME=haproxy
BASE_DIR=/usr/local/haproxy
EXEC=$BASE_DIR/sbin/haproxy
PID_FILE=$BASE_DIR/logs/haproxy.pid
DEFAULT_CONF=$BASE_DIR/conf/haproxy.cfg
MONLOG_PATH="$BASE_DIR/logs/${PROCESS_NAME}_mon.log"

# COLOR print
COLOR_RED=$(    echo -e "\e[31;49m" ) 
COLOR_GREEN=$(  echo -e "\e[32;49m" )
COLOR_RESET=$(  echo -e "\e[0m"     )
info() { echo "${COLOR_GREEN}$*${COLOR_RESET}"   ;}
warn() { echo "${COLOR_RED}$*${COLOR_RESET}"     ;}

do_log()
{
    local log_fpath=$1
    local log_content=$2
    echo "$(date '+%F %T') $log_content" >> $log_fpath
}

print_usage()
{
    echo
    info " Usage: $(basename $0) [start|stop|restart|mon|test]"
    echo 
}

#get Expanding configuration
ext_configs()
{
    CONFIGS=
    if [[ -d $BASE_DIR/conf/enabled ]];then
        for FILE in $(find $BASE_DIR/conf/enabled -type l | sort -n)
        do
                CONFIGS="$CONFIGS -f $FILE";
        done
        echo $CONFIGS
    else
        echo
    fi
}
# check process status
check_process()
{
    PID=`get_pid`
    if ps aux | awk '{print $2}' | grep -qw $PID 2>/dev/null ;then
        true
    else
        false
    fi
    
}
# check Configuration file
check_conf()
{
    $EXEC -c -f $DEFAULT_CONF `ext_configs` >/dev/null 2>&1
    return $?
}
get_pid()
{
    if [[ -f $PID_FILE ]];then
        cat $PID_FILE
        else
            warn " $PID_FILE not found!"
                exit 1
        fi
}
start()
{
    echo
    if check_process;then
        warn " ${PROCESS_NAME} is already running!"
    else
        $EXEC -f $DEFAULT_CONF `ext_configs` && \
        echo -e " ${PROCESS_NAME} start                        [ `info OK` ]" || \
        echo -e " ${PROCESS_NAME} start                        [ `warn Failed` ]" 
    fi
    echo
}

stop()
{
    echo
    if check_process;then
        PID=`get_pid`
        kill -9 $PID >/dev/null 2>&1
        echo -e " ${PROCESS_NAME} stop                         [ `info OK` ]"
    else
        warn " ${PROCESS_NAME} is not running!"
    fi
    echo
}

restart()
{
    echo
    if check_process;then
        :
    else
        warn " ${PROCESS_NAME} is not running! Starting Now..."
    fi
    if `check_conf`;then
        PID=`get_pid`
        $EXEC -f $DEFAULT_CONF `ext_configs` -st $PID && \
        echo -e " ${PROCESS_NAME} restart                      [ `info OK` ]" || \
        echo -e " ${PROCESS_NAME} restart                      [ `warn Failed` ]" 
    else
        warn " ${PROCESS_NAME} Configuration file is not valid, plz check!"
        echo -e " ${PROCESS_NAME} restart                      [ `warn Failed` ]"
    fi
    echo
}

mon()
{
    if check_process;then
        info "${PROCESS_NAME} is running OK!"
        do_log $MONLOG_PATH "${PROCESS_NAME} is running OK!"
    else
        start
        warn " ${PROCESS_NAME} not running, start it!"
        do_log $MONLOG_PATH "${PROCESS_NAME} not running, plz check"
    fi
}

if [[ $# != 1 ]]; then
    print_usage
    exit 1
else
    case $1 in
        "start"|"START")
            start
        ;;
        "stop"|"STOP")
            stop
        ;;
        "restart"|"RESTART"|"-r")
            restart
        ;;
        "status"|"STATUS")
            if check_process;then
                info "${PROCESS_NAME} is running OK!"
            else
                warn " ${PROCESS_NAME} not running, plz check"
            fi
        ;;
        "test"|"TEST"|"-t")
            echo
            if check_conf ;then
                info " Configuration file test Successfully."
            else
                warn " Configuration file test failed."
            fi
            echo
        ;;
        "mon"|"MON"|"-m")
            mon
        ;;
        *)
        print_usage
        exit 1
    esac
fi

保存为 /usr/local/haproxy/sbin/ctrl.sh,赋可执行权限,如下注册系统服务:

chmod +x /usr/local/haproxy/sbin/ctrl.sh
ln -sf /usr/local/haproxy/sbin/ctrl.sh  /etc/init.d/haproxy
chkconfig haproxy on

服务控制:

启动:service haproxy start
停止:service haproxy stop
重载:service haproxy restart
状态:service haproxy status
检查:service haproxy test
监控:service haproxy mon  # 进程自拉起,如有告警通道可自行加入

2、配置自拉起

* * * * * bash /usr/local/haproxy/ctrl.sh mon >/dev/null 2>&1

全部完成后,最终目录结构如下:

[root@locahost:/usr/local/haproxy]# tree
.
├── conf
│   ├── enabled  # 正式使用的拓展配置
│   │   ├── http  
│   │   │   └── demo.cfg -> /usr/local/haproxy/conf/ready/http/demo.cfg# 此处软链到可以上线的配置
│   │   └── tcp
│   │       └── demo.cfg -> /usr/local/haproxy/conf/ready/tcp/demo.cfg
│   ├── haproxy.cfg
│   └── ready     # 存在预发布的拓展配置
│       ├── http
│       │   └── demo.cfg
│       │   └── other.cfg
│       └── tcp
│           └── demo.cfg
│           └── other.cfg
├── doc
│    .....
├── logs
│   └── haproxy.pid
├── sbin
│   ├── ctrl.sh
│   └── haproxy
└── share
    └─...
14 directories, 24 files

四、日志配置

配置 rsyslog

mkdir -p /data/wwwlogs
vim /etc/rsyslog.conf  或 /etc/syslog.conf

#新增配置
local6.* /data/wwwlogs/haproxy.log

#取消如下 2 行注释
$ModLoad imudp
$UDPServerRun 514

#重启 syslog 服务
service rsyslog restart

五、小结

以上内容就是我对 Haproxy 部署规范的整理,并通过拼接方式变相实现了 Haproxy 的多配置文件管理。当然,略遗憾的是未能实现 Haproxy 的 WEB 管理方案,这个有待继续研究实现,敬请期待!

8 条回应
  1. 济南SEO 2017-9-3 · 21:25

    谢谢博主分享,学习到了

  2. 技术宅 2017-9-3 · 23:17

    张大官人,最近忙啥捏,好久没有来本店坐坐了! :lol:

  3. RaresNote 2017-9-4 · 12:40

    今日终于赶上更新了,输入的时候一震一震的,我还以为是地震了呢。

  4. 筑楼 2017-9-5 · 18:42

    看的不是很明白!有点笨

  5. 林锋 2017-11-14 · 14:36

    1.Haproxy的进程数可以优化,提高性能;
    2.Haproxy的WEB管理方案,可以考虑etcd

    • avatar
      Jager 2017-11-19 · 12:03

      哇,锋哥亲自指点,受宠若惊了。
      进程数方面有点争议,现网生产环境发现开2个进程以上,进行压测会出现问题,单个进程却没有问题,待深究下。
      恩,目前已经在测试etcd+confd的解决方案了。

  6. 林锋 2017-11-14 · 14:42

    还有一点。frontend 可配置如下:
    frontend http_server
    bind :80
    bind :443 ssl crt XXX.pem

    • avatar
      Jager 2017-11-19 · 12:04

      恩,作为模板得补充下,不过我们这边内部还没实现https