Networking, Security, Protocols

haproxy 개념 및 구성 가이드

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

Overview

haproxy에 대해서 알아본다.

출처 : 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

 

구조는 아래와 같다.

graph LR
    A[HAProxy] -->|/health| B[Health Check Backend]
    A -->|/game/*| C[Game Backend]
    A -->|/auth/*| D[Auth Backend]
    A -->|/log/*| E[Log Backend]
    B -->|200 OK| F["Return 'OK'"]
    C -->|Round Robin| G[Game Service]
    D -->|Round Robin| H[Auth Service]
    E -->|Round Robin| I[Log Service]
    
    G --> J(( ))
    G --> K(( ))
    G --> L(( ))
    
    H --> M(( ))
    H --> N(( ))
    H --> O(( ))
    
    I --> P(( ))
    I --> Q(( ))
    I --> R(( ))
    
    style A fill:#f9f,stroke:#333,stroke-width:4px
    style B fill:#bbf,stroke:#333,stroke-width:2px
    style C fill:#bbf,stroke:#333,stroke-width:2px
    style D fill:#bbf,stroke:#333,stroke-width:2px
    style E fill:#bbf,stroke:#333,stroke-width:2px
    style F fill:#bfb,stroke:#333,stroke-width:2px
    style G fill:#ddf,stroke:#333,stroke-width:2px
    style H fill:#ddf,stroke:#333,stroke-width:2px
    style I fill:#ddf,stroke:#333,stroke-width:2px
    style J fill:#fff,stroke:#333,stroke-width:1px
    style K fill:#fff,stroke:#333,stroke-width:1px
    style L fill:#fff,stroke:#333,stroke-width:1px
    style M fill:#fff,stroke:#333,stroke-width:1px
    style N fill:#fff,stroke:#333,stroke-width:1px
    style O fill:#fff,stroke:#333,stroke-width:1px
    style P fill:#fff,stroke:#333,stroke-width:1px
    style Q fill:#fff,stroke:#333,stroke-width:1px
    style R fill:#fff,stroke:#333,stroke-width:1px

 


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/

728x90
반응형

'Networking, Security, Protocols' 카테고리의 다른 글

Reverse Proxy(역방향 프록시)란?  (2) 2024.11.13
Cilium이란?  (2) 2024.02.06
Vault 설치와 사용법  (2) 2024.01.24
Curl(Client URL)이란?  (0) 2023.05.26
SSID(Service Set Identifier)란?  (0) 2023.04.05