[Docker] HAProxy를 이용한 로드 밸런싱

이번 포스트는 지난 포스트에 이어 HAProxy를 이용한 로드 밸런싱을 다뤄보도록 하겠습니다.

 

 

What is HAProxy ?

이름만 놓고 보면 프록시의 역할을 하는 소프트웨어인 듯 보입니다. 맞습니다. HAProxy의 본래 기능은 Reverse Proxy 역할을 수행하는 소프트웨어이고, 본래는 High Availbility Proxy의 약자입니다. 그러나 이 소프트웨어를 가지고 TCP / HTTP Load Balancer로 사용할 수도 있습니다.

nginx랑 다른 점은 무엇일까요? nginx에서도 물론 Reverse Proxy, Load Balancer 기능을 제공하지만 HAProxy는 여기에 Active Health Check 기능을 무료로 제공합니다. (nginx에서도 Active Health Check 기능은 있지만 nginx plus인 유료 버전에서만 제공한다는 점이 아쉬웠죠.)

 

 

HAProxy의 동작 방식

HAProxy는기본적으로 Reverse Proxy 형태로 동작합니다. 우리가 보통 평범하게 부르는 프록시라는 단어는 Forward Proxy라고 하는데, Forward Proxy는 출발지(Source)에서 목적지(Destination) 사이에 존재하고, 클라이언트 앞에 존재하는 녀석입니다. 

Reverse Proxy는 그의 반대라고 보시면 됩니다. 실제 서버 요청에 대해 서버 앞 단에 존재하여 서버로 들어오는 요청을 대신 받아 실제 서버에 전달하고, 요청한 곳에 그 결과를 다시 전달하는 기술입니다. 실제로 nginx를 이용해 로드 밸런싱을 구성할 때도 이와 같은 방법을 사용했었죠. HAProxy 또한 이와 동일합니다.

HAProxy의 흐름은 위와 같이 이루어집니다. 최초 접근시에는 일반적인 HTTP 요청으로 전달하다가, HAProxy가 새로운 사용자임을 인식하고, 이 사용자가 연결한 전용 인스턴스를 쿠키 이름으로 전달해주고, 재요청시 클라이언트가 주어주는 쿠키를 가지고 처음 연결했던 인스턴스로 연결해주는 방식입니다.

순서대로 나열하면 다음과 같습니다.

  • 최초 접속시에는 쿠키 없이 일반 요청(Request) 전달
  • 응답(Response)시 쿠키에 서버 정보를 추가한 후 반환
  • 재요청시에는 HAProxy에서 쿠키 정보 확인 후, 최초 요청 서버로 전달
  • 다시 접근시에는 쿠키 추가 없이 전달 (클라이안트가 가지고 있는 쿠키로 대체)

이 외에도 다양한 옵션들이 많이 존재하지만 이번 포스트에서는 기본적인 로드 밸런싱 기능만 다루고, 그 외의 기능들에 대해서는 다른 포스트에서 다뤄보도록 하겠습니다.

 

 

How to install

HAProxy는 Linux, OS X에서 사용할 수 있고, 아쉽게도 Windows에서는 사용할 수 없다는 것이 단점입니다. RHEL에서 사용하는 YUM 패키지 매니저, Ubuntu/Debian에서 사용하는 APT 패키지 매니저를 이용해 HAProxy를 설치할 수 있고, 패키지 매니저를 이용할 수 없는 환경에서는 Source 설치를 이용할 수 있습니다.

여기에서는 APT 패키지 매니저를 이용하여 HAProxy를 설치해보도록 하겠습니다.

$ sudo apt install haproxy

위 명령어로 설치가 끝나면 아래와 같이 Active 상태를 확인할 수 있습니다.

APT 패키지 매니저로 설치했을 때, 설정값은 /etc/haproxy/haproxy.cfg 파일인 것을 알 수 있습니다. 따라서 우리는 세부 설정을 위해 위 cfg 파일을 건드려야 합니다.

 

 

Configuration

HAProxy의 Configuration은 복잡하고, 정교합니다. 그만큼 설정할 수 있는 부분이나 지원하는 부분이 많기 때문에 꼭 필요하면서 사용해야 합니다.

이 포스트에서는 간단한 로드 밸런싱에 대해서만 다룰 것이기 때문에 모든 것을 다루지 않고, 일부만 다루도록 하겠습니다.

처음 설치한 뒤에는 기본적으로 defaults 부분과 global 부분으로 설정이 되어 있습니다. global 부분은 HAProxy에 대한 기본적인 애플리케이션 설정을 수행할 수 있습니다. 예를 들면, SSL 설정, 커넥션 수 등을 지정할 수 있죠.

defaults에서는 HAProxy의 애플리케이션 설정이 아닌 부가적인 설정을 하는 데 사용하는 곳입니다. 그룹별로 나눠서 설정할 수 있지만 defaults에서는 모든 그룹이 적용되는 구간으로 로그의 포맷이나, 커넥션 유지 옵션 등을 설정할 수 있습니다.

지난 포스트에 이어서 우리는 Spring boot Application이 만들어진 Docker 컨테이너를 로드 밸런싱 시켜보도록 하겠습니다.

같은 서비스를 하는 컨테이너를 3개 만들었고, 이에 대한 로드 밸런싱을 수행하면 됩니다. 그런데, HAProxy에서는 Health check 기능도 지원하기 때문에, 우리는 이 기능을 포함하여 한 번 설정을 진행해보도록 하겠습니다.

HAProxy에서는 로드 밸런싱한 서비스 인스턴스들의 상태를 웹으로 볼 수 있는 stats 기능을 제공합니다. listen stats를 설정하면 원하는 포트 주소에 접속하여 서비스의 상태를 모니터링 할 수 있습니다. 

마지막으로 우리가 Docker에 올린 인스턴스를 로드 밸런싱 할 수 있도록 80번 포트 주소를 바인딩하고, 라운드 로빈 알고리즘을 이용하여 로드 밸런싱 해줍니다. (각 포트 주소로 정확히 통신하는지 확인하기 위해 사용합니다.) 그리고 option에 httpchk를 이용하면 각 인스턴스에 대해 Health Check를 진행하게 됩니다. 반드시 유효한 URI를 입력해줘야 하며, 유효하지 않은 URI를 입력할 경우, 인스턴스가 정상 동작하고 있음에도 불구하고 HAProxy에서 죽은 인스턴스로 확인하게 되며 접속에 장애가 발생하게 됩니다.

$ haproxy -f /etc/haproxy/haproxy.cfg -c

설정을 완료한 뒤에는 설정 검사 프로세스를 통해 내가 만든 설정 파일에 문법 오류 등이 없는지를 검사합니다. nginx에서도 nginx -t 명령어를 이용하는데, HAProxy에서도 동일한 기능을 제공하는군요.

# systemctl reload haproxy.service

문법 검사 후 문제가 없다면, haproxy 서비스 데몬을 reload 시켜줍니다. 그러면 HAProxy Master 프로세스가 재시작됩니다.

그런 다음 http://localhost:9000/haproxy_stats 페이지로 접속하면, 위와 같이 우리가 설정한 컨테이너들의 상태가 UP 상태인지, DOWN 상태인지를 확인할 수 있습니다.

 

 

Using Docker Swarm

우리는 컨테이너를 만들고, 로드 밸런싱하는 과정을 모두 수동으로 진행하였습니다. 지금까지는 3개의 컨테이너만을 생성하여 진행하였고, 그랬기 때문에 그 과정이 그다지 많은 손이 가지 않았고, 잘 진행할 수 있었습니다.

하지만 우리는 같은 서비스 인스턴스를 컨테이너로 수십개를 생성해야 한다면, 어떻게 하면 좋을까요? 가장 간단한 방법은 docker 명령어를 쉘 스크립팅하여 반복 작업을 하는 방법이 있습니다. 그런데 만약 HAProxy도 리얼 인스턴스에서 돌리지 않고 컨테이너를 해야 한다면, 그 설정까지 모두 해줘야 할텐데, 이는 쉘 스크립팅만으로는 쉽지 않겠죠?

이럴 때는 Docker compose를 사용하여 각 컨테이너에 대한 설정을 지정하고, 원하는 컨테이너 갯수를 설정하는 방법이 있습니다. 우리가 위에서 다뤘던 것보다 더 쉽게 HAProxy를 이용해 로드 밸런싱을 쉽게 할 수 있으니 한 번 참고해보시는 것도 나쁘지 않을 것 같네요. (하지만 이를 사용하려면 엄청난 러닝 커브가 뒤따릅니다.)

docker-compose.yml 파일을 생성한 후, 위와 같이 작성합니다. 설정 파일만 봐서는 무슨 내용인지 잘 모를 것입니다. 하나씩 살펴보도록 하죠.

services 밑으로는 우리가 운영할 서비스에 대한 컨테이너를 설정하게 됩니다. 이름은 자유롭게 설정할 수 있고, 우리는 dockerexample이라는 서비스와 proxy 이렇게 두 가지를 생성할 것입니다. 이렇게 하면, 한 서비스 아래로 네트워크 영역이 생성되며, 이 서비스에 대한 공간이 하나 만들어지는 원리와 비슷합니다.

바로 이런 형태가 되는 것이죠. 여기에서 Proxy가 입구가 되고, 그 입구에 의해 컨테이너 서비스들이 부하 분산 형태로 서비스하게 되는 것입니다.

이러한 로드 밸런싱을 Ingress Load Balancing이라고 합니다. 즉, 외부에서 내부 네트워크로 접속할 때의 방침을 말하는 것이죠

# docker swarm init
# docker stack deploy --compose-file=docker-compose.yml tutorial

Docker에서 네트워크, 서비스 등의 모든 컨테이너를 Stack이라고 부르는데, 스택을 생성할 때 사용하는 명령어가 바로 docker stack 명령어입니다. 보통은 명령어 안에 모든 컨테이너를 다 넣어야 하지만, docker-compose.yml 파일 등으로 대체할 수 있습니다. 마지막으로 쓴 tutorial은 이 그룹의 이름입니다.

저는 Replica의 갯수를 5개로 설정하였습니다. 자신의 인스턴스 성능에 따라 갯수를 설정해야하므로 가능한 리소스가 많다면 20개로 설정해도 되겠지만 그렇지 않다면, Docker에서 Out of Memory 오류가 발생할 수 있으므로 이에 맞춰 지정해주셔야 합니다.

docker ps 명령어를 통해 5개의 서비스 인스턴스와 프록시 인스턴스 1개가  생성되었음을 알 수 있습니다.

 

 

마치며...

HAProxy를 이용한 로드 밸런싱은 Health Check를 통해서 인스턴스의 상태를 확인하는 추가 기능을 통해 서비스의 모니터링을 지속적으로 진행할 수 있다는 장점을 얻었습니다.

또한 Docker Swarm을 추가로 이용하여 DockerCloud에서 제공하는 HAProxy 컨테이너를 이용한다는 점은 복잡한 HAProxy 설정 없이도 쉽게 로드 밸런싱 기능을 사용할 수 있다는 장점이 있었습니다.

그러나 여전히 까다로운 점은 HAProxy의 복잡한 설정을 피하여 Docker Swarm을 통해 컨테이너 뿐 아니라 네트워크 그룹을 생성해 자체적인 서비스 그룹을 생성함으로써 리얼 인스턴스에서 동작하는 수 많은 서비스를 분리/관리하는 편리함을 주었지만 이에 따른 복잡한 설정은 피할 수 없었습니다.

그래도 오케스트레이션 툴을 사용한 방법 통해 수동으로 Docker 네트워크 설정 등을 일일이 하지 않아도 YAML 파일을 통해서 한 번에 일괄 처리할 수 있었던 부분은 굉장히 편했던 부분인 것 같네요 ^^;

 

 

참조: https://d2.naver.com/helloworld/284659

comments powered by Disqus

Tistory Comments 0