Networking, Security, Protocols

haproxy 개념 및 구성 가이드

Somaz 2024. 4. 9. 12:01
728x90
반응형

Overview

오늘은 HAProxy에 대해 알아보려고 한다.

 

HAProxy (High Availability Proxy)오픈소스 기반의 TCP/HTTP 로드 밸런서 및 프록시 솔루션으로, 고성능, 안정성, 낮은 메모리 사용량을 특징으로 한다. 특히 수만 개의 동시 연결을 처리할 수 있어, 대규모 웹 서비스 및 API Gateway, 데이터베이스 로드 밸런싱 등에 널리 사용된다.

 

이번 글에서는 HAProxy의 주요 기능 및 아키텍처, 로드 밸런싱 알고리즘, 설정 및 구성 방법, 운영 팁 및 트러블슈팅 방법 등을 다룬다. 또한, Ingress Controller와의 비교, GCP 환경에서 HAProxy를 활용한 MultiPath 구성 사례도 살펴볼 예정이다.

 

 

출처 : https://bizsecure-apac.com/haproxy-load-balancer/

 

 

 

 

 

 


 

 

 

haproxy란?

High Availability Proxy(고가용성 프록시)를 의미하는 HAProxy는 널리 사용되는 오픈 소스 소프트웨어인 TCP/HTTP 로드 밸런서 및 프록싱 솔루션이다. 고성능, 안정성, 낮은 메모리 공간은 물론 수만 개의 동시 연결을 처리할 수 있는 능력으로 잘 알려져 니다. HAProxy는 Linux, Solaris 및 FreeBSD 운영 체제에서 실행할 수 있다.

 

 

 


 

 

 

주요 특징

출처 : https://webhostinggeeks.com/blog/haproxy-features-functions-benefits/

  1. 로드 밸런싱(Load Balancing): HAProxy는 워크로드를 여러 서버에 분산하여 단일 서버가 요청으로 인해 압도당하지 않도록 함으로써 웹 애플리케이션의 성능과 안정성을 향상시킬 수 있다.
  2. 고가용성(High Availability): 장애 조치 기능을 제공하여 오류 발생 시 운영 서버로 트래픽을 자동으로 다시 라우팅하여 서비스의 지속적인 가용성을 지원한다.
  3. SSL/TLS 종료(SSL/TLS Termination): HAProxy는 SSL/TLS 연결을 종료하여 애플리케이션 서버에서 이 작업을 오프로드할 수 있다. 이를 통해 SSL 인증서를 중앙 집중식으로 관리할 수 있으며 성능이 향상된다.
  4. 상태 점검(Health Checks): 백엔드 서버에서 상태 점검을 수행하여 트래픽이 정상 서버로만 전송되는지 확인할 수 있다.
  5. 세션 지속성(Session Persistence): HAProxy는 세션 지속성을 유지하는 다양한 방법을 지원하여 세션 기간 동안 사용자 세션이 동일한 백엔드 서버로 유지되도록 보장한다.
  6. 보안 기능(Security Features): 다양한 기준에 따라 액세스를 제한할 수 있는 ACL(액세스 제어 목록) 및 DDoS 보호 메커니즘과 같은 여러 보안 기능을 제공한다.
  7. 모니터링 및 통계(Monitoring and Statistics): HAProxy는 자세한 모니터링 및 통계를 제공하여 트래픽 패턴, 성능 및 서버 상태에 대한 실시간 통찰력을 제공한다.

 

사용 사례

  • 웹 애플리케이션 로드 밸런싱(Web Application Load Balancing): HTTP 요청을 서버 풀에 분산하여 로드 밸런싱을 조정하고 고가용성을 보장한다.
  • 데이터베이스 부하 분산(Database Load Balancing): 여러 데이터베이스 서버에 걸쳐 데이터베이스 쿼리를 분산하여 성능과 가용성을 향상시킨다.
  • SSL 오프로딩(SSL Offloading): HAProxy 계층에서 SSL/TLS 트래픽을 해독하여 웹 서버의 암호화 부하를 줄인다.
  • GSLB(Global Server Load Balancing): 사용자 경험을 개선하기 위해 가장 가깝거나 성능이 가장 좋은 데이터 센터로 사용자 트래픽을 라우팅한다.
  • 콘텐츠 캐싱 및 압축(Content Caching and Compression): 자주 액세스하는 콘텐츠를 캐싱하고 데이터를 압축하여 로드 시간과 대역폭 사용량을 줄인다.

 

아키텍처

출처 : https://webhostinggeeks.com/blog/haproxy-features-functions-benefits/

 

 

 

 

Haproxy 로드벨런싱 알고리즘

출처 : https://webhostinggeeks.com/blog/haproxy-features-functions-benefits/

 

 

  • HAProxy는 여러 로드 밸런싱 알고리즘을 지원하므로 애플리케이션의 특정 요구 사항과 동작을 기반으로 적절한 알고리즘을 선택할 수 있다.
  • 이러한 알고리즘은 들어오는 요청이 백엔드 서버에 분산되는 방식을 결정한다.
  • 그리고 전역적으로 또는 백엔드별로 적용할 수 있으므로 다양한 유형의 트래픽이 균형을 이루는 방식에 유연성을 제공한다.
  • 알고리즘 선택은 애플리케이션의 요구 사항, 서버 용량 및 클라이언트 요청의 성격을 고려해야 한다.

 

 

# HAProxy 전역 설정
global
    log stdout format raw local0

# 모든 프론트엔드/백엔드를 위한 기본 설정
defaults
    log global
    option httplog
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

# 들어오는 요청을 위한 프론트엔드
frontend http_front
    bind *:8080
    mode http
    stats uri /haproxy?stats

    # health check 확인
    acl health_check path /health
    # 경로가 /game 인지 확인하는 ACL
    acl path_game path_beg /game

    # 조건에 따라 적절한 백엔드로 요청 라우팅
    use_backend health_check_backend if health_check
    use_backend game_back if path_game

# "/game" 경로를 처리하는 백엔드
backend game_back
    mode http
    balance roundrobin
    # /game/x 요청이 /x로 변환되어 game 서비스로 전송됩니다.
    http-request set-path %[path,regsub(^/game,/)]
    server game game.dev1-game.svc.cluster.local:80 check

# 헬스 체크를 위한 백엔드 설정
backend health_check_backend
    mode http
    http-request return status 200 content-type text/plain string "OK"
  1. Round Robin (roundrobin): 가장 간단하고 가장 일반적인 로드 밸런싱 알고리즘이다. 들어오는 요청은 나열된 순서대로 백엔드 서버 전체에 순차적으로 배포된다. 목록이 끝나면 처음부터 다시 시작된다. 이 방법은 모든 서버가 처리 속도와 로드 처리 측면에서 동일하다고 가정한다.
  2. Least Connections (leastconn): 이 알고리즘은 활성 연결이 가장 적은 서버에 요청을 보낸다. 이는 라운드 로빈보다 더 정교하며 세션 처리 시간이 매우 다양한 상황에 더 적합하다. 이는 특히 교통량이 많은 상황에서 부하를 보다 균일하게 분산시키는 데 도움이 된다.
  3. Source (source): 소스 알고리즘은 소스 IP 주소의 해시를 기반으로 백엔드 서버를 선택한다. 이렇게 하면 백엔드 서버가 다운되거나 켜지지 않는 한 동일한 클라이언트 IP 주소의 요청이 항상 동일한 서버로 전달된다. 세션 지속성에 도움이 된다.
  4. URI(uri): 이 방법은 요청의 URI(Uniform Resource Identifier) 해시를 사용하여 사용할 백엔드 서버를 결정한다. 이렇게 하면 동일한 URI에 대한 모든 요청이 동일한 서버로 전송되므로 캐싱에 유용하다.
  5. Header (hdr): 헤더 알고리즘은 요청 헤더 중 하나의 해시를 기반으로 서버를 선택한다. 해시할 헤더를 지정할 수 있으므로 특정 헤더 값이 있는 요청이 동일한 서버에 고정되도록 하는 다목적 옵션이 된다.
  6. Random (random): 이 알고리즘은 각 요청에 대해 서버를 무작위로 선택한다. 특정 서버에 유리하도록 가중치를 적용할 수 있다. 이는 단순한 형태의 로드 분산을 제공하지만 서버 전체에 균일한 로드 분산을 보장하는 데는 효과적이지 않을 수 있다.
  7. Consistent Hashing (consistent): 일부 요청 속성(예: 소스 IP 또는 URI)의 해시를 기반으로 하는 이 알고리즘은 동일한 해시 값을 초래하는 요청이 항상 동일한 서버로 라우팅되도록 보장한다. 이는 캐시 지역성에 특히 유용하지만 서버 추가 또는 제거를 처리하려면 신중한 관리가 필요하다.
  8. First (first): 이 알고리즘은 특정 임계값 미만의 로드가 있는 것으로 식별된 첫 번째 서버로 요청을 라우팅한다. 특정 서버의 과부하를 방지하는 간단한 방법이다.
  9. Static-RR (static-rr): 서버의 정적 가중치를 허용하는 라운드 로빈의 변형이다. 가중치가 높은 서버는 더 많은 연결 비율을 받는다.

 

 

 

 


 

 

 

 

Haproxy 구성 실습

GCP에 Haproxy를 사용해서 하나의 도메인으로 2개의 Application을 MultiPath 구성을 해보려고 한다. GKE Autopilot을 사용하여 구성하였다. 아래와 같이 구성하면, 하나의 도메인으로 2개의 Application을 `/mario` `/tetris` 이렇게 배포가 가능하다.

apiVersion: v1
kind: Namespace
metadata:
  name: mario-ns
---
apiVersion: v1
kind: Namespace
metadata:
  name: tetris-ns
---
apiVersion: v1
kind: Namespace
metadata:
  name: haproxy-ns
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mario
  namespace: mario-ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mario
  template:
    metadata:
      labels:
        app: mario
    spec:
      containers:
        - name: mario
          image: pengbai/docker-supermario
---
apiVersion: v1
kind: Service
metadata:
  name: mario
  namespace: mario-ns
spec:
  selector:
    app: mario
  ports:
    - port: 80
      targetPort: 8080
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tetris
  namespace: tetris-ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tetris
  template:
    metadata:
      labels:
        app: tetris
    spec:
      containers:
        - name: tetris
          image: bsord/tetris
---
apiVersion: v1
kind: Service
metadata:
  name: tetris
  namespace: tetris-ns
spec:
  selector:
    app: tetris
  ports:
    - port: 80
      targetPort: 80
  type: ClusterIP
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: haproxy-config
  namespace: haproxy-ns
data:
  haproxy.cfg: |
    # HAProxy 전역 설정
    global
        log stdout format raw local0

    # 모든 프론트엔드/백엔드를 위한 기본 설정
    defaults
        log global
        option httplog
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms

    # 들어오는 요청을 위한 프론트엔드
    frontend http_front
        bind *:8080
        mode http
        stats uri /haproxy?stats

        # 헬스 체크 경로를 위한 ACL
        acl health_check path /health
        # 경로가 /mario 또는 /tetris로 시작하는지 확인하는 ACL
        acl path_mario path_beg /mario
        acl path_tetris path_beg /tetris

        # /health 경로에 대한 헬스 체크 백엔드 사용
        use_backend health_check_backend if health_check
        # 조건에 따라 적절한 백엔드로 요청 라우팅
        use_backend mario_back if path_mario
        use_backend tetris_back if path_tetris

    # "mario" 서비스를 제공하는 백엔드
    backend mario_back
        mode http
        balance roundrobin
        http-request set-path %[path,regsub(^/mario,/)]
        server mario mario.mario-ns.svc.cluster.local:80 check

    # "tetris" 서비스를 제공하는 백엔드
    backend tetris_back
        mode http
        balance roundrobin
        http-request set-path %[path,regsub(^/tetris,/)]
        server tetris tetris.tetris-ns.svc.cluster.local:80 check

    # 헬스 체크를 위한 백엔드 설정
    backend health_check_backend
        mode http
        http-request return status 200 content-type text/plain string "OK"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: haproxy
  namespace: haproxy-ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: haproxy
  template:
    metadata:
      labels:
        app: haproxy
    spec:
      containers:
      - name: haproxy
        image: haproxy:latest
        ports:
        - containerPort: 8080  # 컨테이너 포트를 8080으로 변경
        volumeMounts:
        - name: config-volume
          mountPath: /usr/local/etc/haproxy/haproxy.cfg
          subPath: haproxy.cfg
      volumes:
      - name: config-volume
        configMap:
          name: haproxy-config
---
apiVersion: v1
kind: Service
metadata:
  name: haproxy
  namespace: haproxy-ns
  annotations:
    cloud.google.com/neg: '{"ingress": true}'
    cloud.google.com/backend-config: '{"default": "haproxy-backend-config"}'
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: haproxy
  type: ClusterIP
---
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: games-managed-certificate
  namespace: haproxy-ns
spec:
  domains:
    - game.somaz.link
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: haproxy-ns
  name: ingress-games
  annotations:
    kubernetes.io/ingress.global-static-ip-name: "mgmt-gke-game-lb-ip"
    networking.gke.io/v1beta1.FrontendConfig: "games-frontend-config"
    networking.gke.io/managed-certificates: "games-managed-certificate"
    kubernetes.io/ingress.class: "gce"
spec:
  rules:
  - host: game.somaz.link
    http:
      paths:
      - path: /mario
        pathType: Prefix
        backend:
          service:
            name: haproxy 
            port:
              number: 80
      - path: /tetris
        pathType: Prefix
        backend:
          service:
            name: haproxy  
            port:
              number: 80
---
apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
  name: games-frontend-config
  namespace: haproxy-ns
spec:
  redirectToHttps:
    enabled: true
---
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: haproxy-backend-config
  namespace: haproxy-ns
spec:
  healthCheck:
    checkIntervalSec: 30
    timeoutSec: 5
    healthyThreshold: 1
    unhealthyThreshold: 2
    type: HTTP
    requestPath: /health
    port: 8080

 

 

helm으로 작성하면 아래와 같다.

configs:
  - name: haproxy-configmap
    namespace: haproxy
    datas:
      haproxy.cfg: |
        # HAProxy 전역 설정
        global
            log stdout format raw local0

        # 모든 프론트엔드/백엔드를 위한 기본 설정
        defaults
            log global
            option httplog
            timeout connect 5000ms
            timeout client 50000ms
            timeout server 50000ms

        # 들어오는 요청을 위한 프론트엔드
        frontend http_front
            bind *:8080
            mode http
            stats uri /haproxy?stats

            # 경로가 /game, /auth, /log, /health 인지 확인하는 ACL
            acl health_check path /health
            acl path_game path_beg /game
            acl path_auth path_beg /auth
            # acl path_log path_beg /log

            # 조건에 따라 적절한 백엔드로 요청 라우팅
            use_backend health_check_backend if health_check
            use_backend game_back if path_game
            use_backend auth_back if path_auth
            # use_backend log_back if path_log

        # 헬스 체크를 위한 백엔드 설정
        backend health_check_backend
            mode http
            http-request return status 200 content-type text/plain string "OK"

        # "/game" 경로를 처리하는 백엔드
        backend game_back
            mode http
            balance roundrobin
            # /game/x 요청이 /x로 변환되어 game 서비스로 전송됩니다.
            http-request set-path %[path,regsub(^/game,/)]
            server game game.dev1-game.svc.cluster.local:80 check

        # "/auth" 경로를 처리하는 백엔드
        backend auth_back
            mode http
            balance roundrobin
            # /auth/x 요청이 /x로 변환되어 auth 서비스로 전송됩니다.
            # http-request set-path %[path,regsub(^/auth/,/)]
            # /auth/x 요청이 /auth/x로 변환되어 auth 서비스로 전송됩니다.
            http-request set-path %[path,regsub(^/auth/auth/,/auth/)]
            server auth auth.dev1-auth.svc.cluster.local:80 check

        # "/log" 경로를 처리하는 백엔드
        backend log_back
            mode http
            balance roundrobin
            # /log/x 요청이 /x로 변환되어 log 서비스로 전송됩니다.
            # http-request set-path %[path,regsub(^/log/,/)]
            # /log/x 요청이 /log/x로 변환되어 log 서비스로 전송됩니다.
            http-request set-path %[path,regsub(^/log/log/,/log/)]
            server log log.dev1-log.svc.cluster.local:80 check
 
 volumes:
  - name: haproxy-config
    configMap:
      name: haproxy-configmap
      items:
        - key: haproxy.cfg
          path: haproxy.cfg

 

 

구조는 아래와 같다.

 

 

 

 


 

 

 

 

HAProxy의 동작 방식 간단 정리 

단계 설명
1. 클라이언트 요청 수신 클라이언트가 HAProxy로 요청 전송
2. 프론트엔드 처리 ACL을 통해 요청 경로, 헤더 등을 분석
3. 백엔드 선택 ACL 조건 충족 시 적절한 백엔드로 라우팅
4. 서버 선택 백엔드 내에서 로드밸런싱 알고리즘 적용해 서버 선택
5. 응답 전달 선택된 서버의 응답을 클라이언트로 반환

 

 

 


 

 

 

 

실제 운영 팁 

 

로그 포맷 최적화

HAProxy는 기본 로그 외에도 매우 상세한 커스텀 로그 포맷을 지원한다.


장애 분석, 성능 모니터링을 위해 아래처럼 구성 추천:

log-format "%ci:%cp [%t] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Tt %st %B %tsc %ac/%fc/%bc/%sc/%rq/%rp %hr %hs %{+Q}r"
  • `haproxy.cfg` 에 추가로 설정 가능

 

 

connection timeout, client timeout, server timeout 적절 설정

장시간 연결 유지는 성능 저하 원인될 수 있음. 서비스 특성 맞춘 튜닝 필요.

defaults
    timeout connect 3000ms
    timeout client 30000ms
    timeout server 30000ms

 

 

상태페이지 보호

`/haproxy?stats` 페이지는 보안상 외부에 노출되지 않도록 IP 제한 또는 Basic Auth 적용 추천

frontend stats_frontend
    bind *:9000
    stats enable
    stats uri /stats
    stats realm HAProxy\ Statistics
    stats auth admin:password

 

 

 


 

 

 

 

 

HAProxy vs Ingress Controller 비교

항목 HAProxy Ingress Controller (Nginx)
목적 L4/L7 로드밸런서 주로 HTTP Ingress
성능 매우 높은 성능 적당한 성능
설정 난이도 복잡 (옵션 많음) 비교적 쉬움
gRPC 지원 지원 일부 지원 (Nginx Plus)
커스텀 Health Check 강력한 편 보통
사용 사례 Web, DB, API Gateway 등 전천후 HTTP Ingress 위주

 

 

📅 관련 글

2024.06.24 - [Container Orchestration/Kubernetes] - Ingress Nginx란?

 

 

 

 

트러블슈팅 팁

 

서비스 연결 문제 발생 시 체크리스트

`haproxy.cfg` typo 체크
서비스 DNS 네임 확인 (`nslookup` 으로 확인)
ACL, Path 설정 정상 확인 (`acl path_game` 같은 부분)
백엔드 서버 상태 확인 (`server game game.dev1-game.svc.cluster.local:80 check`)
로그 확인 (`kubectl logs` 로 로그 체크)

 

 

 


 

 

 

마무리

  • HAProxy는 단순한 로드밸런서를 넘어서 강력한 트래픽 관리와 보안 기능까지 제공하는 전천후 솔루션이다.
  • 특히 GCP, AWS 같은 클라우드 환경뿐만 아니라 온프레미스에서도 매우 유용하게 사용할 수 있어, 쿠버네티스 환경에서도 Helm Chart와 함께 효과적으로 관리할 수 있다.
  • 이번 정리를 통해 HAProxy의 다양한 기능과 설정 방법을 파악하고, 자신의 서비스 특성에 맞춘 최적의 로드밸런싱 구성을 설계해보세요!

 

 

 

 


Reference

https://docs.haproxy.org/

https://www.techtarget.com/searchnetworking/definition/HAProxy

https://bizsecure-apac.com/haproxy-load-balancer/

https://github.com/somaz94/network/tree/main/haproxy

https://github.com/somaz94/helm-chart-template/tree/main/gcp/haproxy

https://webhostinggeeks.com/blog/haproxy-features-functions-benefits/

 

HAProxy 공식 Docs: https://docs.haproxy.org/

HAProxy Github: https://github.com/haproxy/haproxy

HAProxy Best Practices: https://www.haproxy.com/documentation/haproxy/latest/onepage/

 

728x90
반응형