상세 컨텐츠

본문 제목

HAProxy L4 이중화 구축 with Keepalived

카테고리 없음

by Keunwoo.LEE 2022. 10. 13. 13:41

본문

반응형

목표 구성

  • 두대의 Linux 서버(VM)를 이용하여 Active/Standby 구조의 이중화 L4 Load Balancer 구축
  • 운영환경에서 사용
  • Open Source 무료 소프트웨어만 이용
  • HAProxy 와 Keepalived 에서 발생하는 로그를 하나의 종류로 통합 관리
  • 중요 로그는 외부의 Syslog 서버로 전송하여 즉시 알림

설치 정보

OS : Centos 7.8

Spec : CPU 4 Core / Memory 4 GB / HDD 200 GB

Network IP :

  • Gateway : 10.10.10.200
    - LB를 이용할 서버들은 이 IP를 Gateway로 설정해야 한다. One-Arm 구성이기 때문에...
    - 하지만, HAProxy는 Client Source IP를 리얼 서버로 전달하지 않기 때문에 꼭 필요하지는 않음
  • HAProxy_L4_A : 10.10.10.201
  • HAProxy_L4_B : 10.10.10.202
  • Service VIP : 10.10.10.203

HAProxy Version : 2.2.2

Keepalived Version : 2.1.5

 

시스템 기본 설정 변경

firewalld disable

서버 앞단에 별도의 방화벽이 있어 서버 방화벽은 disable 했다.

> systemctl stop firewalld.service 
> systemctl disable firewalld.service     
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.

selinux disable

> setenforce 0               # 끄기

> vi /etc/sysconfig/selinux  # 부팅시 적용
SELINUX=disabled

HAProxy 설치

haproxy.org에서 2.2.2 download (당시 최신버전)

> wget http://www.haproxy.org/download/2.2/src/haproxy-2.2.2.tar.gz
> tar -zxvf haproxy-2.2.2.tar.gz 
> cd haproxy-2.2.2

필수 소프트트웨어 설치

> yum install pcre-static pcre-devel openssl-devel systemd-devel

Compile

> make TARGET=linux-glibc USE_OPENSSL=1 USE_PCRE=1 USE_ZLIB=1 USE_SYSTEMD=1
> make install

directory 생성

> mkdir -p /etc/haproxy/certs
> mkdir -p /etc/haproxy/errors
> mkdir -p /var/log/haproxy
> mkdir /var/lib/haproxy

haproxy 계정 생성

> useradd -r haproxy

syslog 설정

HAProxy는 기본적으로 messages 파일에 로그를 생성한다. 별도의 로그파일로 관리하기 위해 아래 syslog 설정 진행.

로그를 통합하려는 목적이 없으면 아래는 진행하지 않아도 된다.

> vi /etc/rsyslog.conf
# Provides UDP syslog reception (haproxy가 log 전송시 127.0.0.1:514로 보내서 필요...)
$ModLoad imudp
$UDPServerRun 514

# messages 파일에 haproxy 관련 로그 쓰지 않도록 messages 설정줄에 local2.none 추가
*.info;mail.none;authpriv.none;cron.none;local2.none    /var/log/messages

> vi /etc/rsyslog.d/haproxy.conf
# 모든 log
local2.*   /var/log/haproxy/haproxy.log

# local2.=info info2인 등급
local2.=info    /var/log/haproxy/haproxy-info.log

# local2.notice notice 등급 이상
local2.notice   /var/log/haproxy/haproxy-notice.log

# syslog 서버로 전송
local2.notice   @10.10.10.114

> systemctl restart rsyslog.service

logrotate 설정

별도로 관리하는 로그파일이 30일만 보관될 수 있도록 설정 진행. 이 역시 별도의 로그를 사용하지 않는다면 진행할 필요 없음.

> vi /etc/logrotate.d/haproxy
/var/log/haproxy/*.log {
    daily
    rotate 30
    missingok
    notifempty
    compress
    sharedscripts
    postrotate
        /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
        /bin/kill -HUP `cat /var/run/rsyslogd.pid 2> /dev/null` 2> /dev/null || true
    endscript
}

HAProxy config 설정

아래 설정은 하나의 VIP와 두개의 Service를 4대의 리얼서버로 LB 하는 구성과

HAProxy의 상태 정보를 Web UI로(9000번 포트) 확인할 수 있는 stats 환경을 포함하고 있음

> vi /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Example configuration for a possible web application.  See the
# full configuration options online.
#
#   <http://haproxy.1wt.eu/download/1.4/doc/configuration.txt>
#
#---------------------------------------------------------------------

#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    #
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog
    #
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog
    #
    #    local2.*                       /var/log/haproxy.log
    #
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
#frontend  main *:5000
#    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             app

#---------------------------------------------------------------------
# static backend for serving up images, stylesheets and such
#---------------------------------------------------------------------
#backend static
#    balance     roundrobin
#    server      static 127.0.0.1:4331 check

#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
#backend app
#    balance     roundrobin
#    server  app1 127.0.0.1:5001 check
#    server  app2 127.0.0.1:5002 check
#    server  app3 127.0.0.1:5003 check
#    server  app4 127.0.0.1:5004 check

#---------------------------------------------------------------------
# HAProxy Statistics Page (http://10.10.10.201:9000/haproxy_stats)
#---------------------------------------------------------------------
listen stats
    bind *:9000
    stats enable
    stats realm HAProxy Statistics
    stats uri /haproxy_stats
    stats auth admin:admin

#---------------------------------------------------------------------
# TCP-in
#---------------------------------------------------------------------
listen  tcp-in-33010
        bind    10.10.10.203:33010
        balance roundrobin
        log     global
        mode    tcp
        option  tcplog
        server  Server75      10.10.10.75:33010 check
        server  Server76      10.10.10.76:33010 check

listen  tcp-in-33011
        bind    10.10.10.203:33011
        balance roundrobin
        log     global
        mode    tcp
        option  tcplog
        server  Server77      10.10.10.77:33011 check
        server  Server78      10.10.10.78:33011 check

외부 IP bind를 위해 kernal parameter 수정

이 작업을 하지 않으면 haproxy에서 지정한 Service VIP를 불러오지 못하여 기동 안됨

아래 설정을 했는데도 Service VIP를 못불러 오면 keepalived 설정이 완료 된 후에 Service VIP를 설정하고 그 전에는 자신의 IP를 설정하여 테스트를 진행 한다.

> echo 'net.ipv4.ip_nonlocal_bind=1' >> /etc/sysctl.conf 
> sysctl -p

systemctl 등록

소스 파일을 컴파일 하여 설치하였기 때문에 systemctl을 통해 서비스를 시작 및 종료를 할수 없다.

소스 파일에 포함되어 있는 예제 파일을 간단히 수정하여 systemctl을 등록한다.

> cp /root/haproxy-2.2.2/contrib/systemd/haproxy.service.in /usr/lib/systemd/system/haproxy.service 

> vi /usr/lib/systemd/system/haproxy.service # @SBINDIR@ 부분만 실제 디렉토리로 수정 #
[Unit]
Description=HAProxy Load Balancer
After=network-online.target
Wants=network-online.target

[Service]
EnvironmentFile=-/etc/default/haproxy
EnvironmentFile=-/etc/sysconfig/haproxy
Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid" "EXTRAOPTS=-S /run/haproxy-master.sock"
ExecStartPre=/usr/local/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS
ExecStart=/usr/local/sbin/haproxy -Ws -f $CONFIG -p $PIDFILE $EXTRAOPTS
ExecReload=/usr/local/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS
ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed
Restart=always
SuccessExitStatus=143
Type=notify

# The following lines leverage SystemD's sandboxing options to provide
# defense in depth protection at the expense of restricting some flexibility
# in your setup (e.g. placement of your configuration files) or possibly
# reduced performance. See systemd.service(5) and systemd.exec(5) for further
# information.

# NoNewPrivileges=true
# ProtectHome=true
# If you want to use 'ProtectSystem=strict' you should whitelist the PIDFILE,
# any state files and any other files written using 'ReadWritePaths' or
# 'RuntimeDirectory'.
# ProtectSystem=true
# ProtectKernelTunables=true
# ProtectKernelModules=true
# ProtectControlGroups=true
# If your SystemD version supports them, you can add: @reboot, @swap, @sync
# SystemCallFilter=~@cpu-emulation @keyring @module @obsolete @raw-io

[Install]
WantedBy=multi-user.target

> systemctl daemon-reload

> systemctl status haproxy.service
● haproxy.service - HAProxy Load Balancer
   Loaded: loaded (/usr/lib/systemd/system/haproxy.service; disabled; vendor preset: disabled)
   Active: inactive (dead)

> systemctl enable haproxy.service       
Created symlink from /etc/systemd/system/multi-user.target.wants/haproxy.service to /usr/lib/systemd/system/haproxy.service.

> systemctl start haproxy.service

상태 확인

http://10.10.10.201:9000/haproxy_stats 으로 접속하여 상태 확인

 

Keealived 설치

Enable snapd (snap을 이용하여 설치, 의존성 파일을 모두 포함한 Package를 배포하는 Repository)

참고사이트 : https://snapcraft.io/install/keepalived/centos 

 

Install keepalived on CentOS using the Snap Store | Snapcraft

Get the latest version of keepalived for on CentOS - High availability VRRP/BFD and load-balancing for Linux

snapcraft.io

> yum install epel-release
> yum install snapd
> systemctl enable --now snapd.socket
> ln -s /var/lib/snapd/snap /snap

Install keepalived

> snap install keepalived --classic
> systemctl status snap.keepalived.daemon

keepalived log 설정

keepalived는 기본적으로 messages 파일에 log를 남기는데, messages 파일에서 keepalived 관련 로그만 별도 파일(haproxy-notice.log)에 저장하고 외부 syslog 서버로 전송

> vi /etc/rsyslog.d/keepalived.conf 
if $programname == "Keepalived_vrrp" then /var/log/haproxy/haproxy-notice.log
if $programname == "Keepalived_vrrp" then @10.10.10.114

VM Template 생성

지금까지의 상태를 VM Template으로 생성하고 HAProxy_L4_B를 만들때 불러와서 사용한다.

VM 환경이 아니라면, 지금까지의 했던 내용을 새로운 서버에 동일하게 적용하면 된다.

 

keepalived.conf 설정

아래 구성은 A 장비가 Active에서 장애가 발생하여 B 장비가 Active가 된 후, A 장비가 정상화 되었을때 다시 A 장비로 Active가 전환되는 걸 방지하기 위한 구성이다.

이 구성에서 A 장비 장애시 B 장비 Active 되면, B 장비에서 keepalived를 stop 혹은 restart 하면 A 장비가 다시 Active 된다.

> vi /etc/keepalived/keepalived.conf
global_defs {
   notification_email {
     mail@example.net
   }
   notification_email_from noreply@example.net
   smtp_server x.x.x.x
   smtp_connect_timeout 30
   router_id HAProxy_L4_A
}

# haproxy process를 체크하여 down되면 priority 값을 60 줄임 (150-60=90)
# 따라서 haproxy가 down되면 HAProxy_L4_B의 값 100 보다 10이 작게 되어 HAProxy_L4_B가 Active됨
vrrp_track_process track_haproxy {
    process haproxy
    weight -60
}

# nopreempt 옵션을 이용하여 자동 failback 안되도록 구성
# nopreempt 사용시 state를 `BACKUP` 으로 설정해야 함
# HAProxy_L4_A를 Active로 설정하려면 HAProxy_L4_B의 keepalived를 stop or restart 하면 됨
vrrp_instance VI_1 {
    state BACKUP
    interface ens192
    garp_master_delay 10
    smtp_alert
    nopreempt
    virtual_router_id 171
    priority 150
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass haproxy_171
    }
    virtual_ipaddress {
        10.10.10.200
        10.10.10.203
    }
    track_process {
        track_haproxy
    }
}

> systemctl restart snap.keepalived.daemon.service

HAProxy_L4_B 구성

위에서 작성해둔 HAProxy_L4 Template을 이용하여 HAProxy_L4_B VM 생성

 

keepalived.conf 설정

> vi /etc/keepalived/keepalived.conf
global_defs {
   notification_email {
     mail@example.net
   }
   notification_email_from noreply@example.net
   smtp_server x.x.x.x
   smtp_connect_timeout 30
   router_id HAProxy_L4_B
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens192
    garp_master_delay 10
    smtp_alert
    preempt
    virtual_router_id 171
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass haproxy_171
    }
    virtual_ipaddress {
        10.10.10.200
        10.10.10.203
    }
}

> systemctl restart snap.keepalived.daemon.service

track 옵션 참고사이트 : https://www.redhat.com/sysadmin/advanced-keepalived

 

Keepalived and high availability: Advanced topics

The opinions expressed on this website are those of each author, not of the author's employer or of Red Hat. The content published on this site are community contributions and are for informational purpose only AND ARE NOT, AND ARE NOT INTENDED TO BE, RED

www.redhat.com

HAProxy CLI 모드 사용

haproxy.cfg에 socket 추가

> vi /etc/haproxy/haproxy.cfg
stats socket /var/run/haproxy.sock mode 600 level admin
stats timeout 2m

CLI 실행 (socat이 설치되어 있지 않으면 yum install socat 으로 설치 후 진행)

> socat /var/run/haproxy.sock readline
prompt
> show info
...
>

System Parameter 수정

Linux 서버의 기본 System Parameter는 운영환경에서 사용하기엔 다소 부족한 면이 있어 아래와 같이 수정한다.

아래 값은 필자의 경험상 가장 안정적이고 성능도 잘 나오는 구성을 다년간 찾다가 최근에 정착한 구성이다.

> vi /etc/sysctl.conf

net.core.netdev_max_backlog = 30000
net.core.rmem_default = 253952
net.core.wmem_default = 253952
net.core.somaxconn = 1024
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 253952 253952 16777216
net.ipv4.tcp_wmem = 253952 253952 16777216
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_tw_reuse = 1

 

끝맺음

현재 필자는 이렇게 구성한 HAProxy L4를 운영환경에서 사용하고 있다.

아래 사진은 필자가 사용하고 있는 HAProxy의 상태 화면이다. 자세히 보면 꽤 많은 접속량을 보이고 있으며 1년 6개월 정도의 UP time을 유지하고 있다.

단 한번의 장애도 없었으며, 성능도 아무런 이슈가 없는 상태다.

다만 문제 발생시 해결은 오로지 본인의 몫이므로 이 글을 읽는 분들은 잘 판단해서 진행하길 바란다.

HAproxy stats 화면

 


 

반응형

댓글 영역