오픈스택 연구하기 : Octavia를 활용한 로드밸런싱

반응형

오픈스택 연구하기 : Octavia를 활용한 로드밸런싱

안녕하세요 김민욱입니다.

 

이번 포스팅에서는 오픈스택 연구하기의 주제 중 하나로 Octavia를 이용한 로드밸런싱에 대해 말씀드리고자 합니다. 먼저 로드밸런싱이란, 여러 대의 서버를 두고 앞 단에 로드밸런서(Loadbalancer)를 배치하여 클라이언트로부터 요청이 오면 이를 분산시켜 주는 역할을 합니다. 예를 들어 동일한 기능을 하는 여러 대의 웹서버가 있으면, 가장 앞단에서 로드밸런서가 클라이언트의 요청을 받은 후 이를 각각의 웹서버에게 골고루 분산시켜 주면서 각 웹서버의 부하를 줄일 수 있습니다.

 

뿐만 아니라, 로드밸런싱을 통해 여러 대의 서버를 연결한 뒤 한 서버가 다운되더라도 다른 서버에게 요청을 보내기 때문에 지속적으로 서비스를 유지하도록 할 수도 있습니다. 이러한 기능을 통해 지속적으로 스트리밍 서비스를 유지하는 백업 기반의 VNF 고가용성 기술[1] 연구 개발을 진행하기도 하였습니다. 

 

오픈스택에서 제공하는 로드밸런서는 초기 Neutron 로드밸런서 v1으로 시작하여 Neutron 로드밸런서 v2로 업데이트 된 뒤 일정 기간의 업데이트를 거쳐 Queens부터 지원이 종료되면서, Train부터는 완전히 종료됩니다. 이는 Neutron의 규모가 너무 커졌을 뿐만 아니라 별도의 프로젝트로 Octavia가 존재하기 때문입니다. 따라서 Train이 릴리즈 된 현재 시점에서는 오픈스택 로드밸런서 = Octavia라고 생각해도 무방 할 것 같습니다. 

 

그림 1. Ocatavia 로고(참조 : [2])

Architecture

 

본 포스팅에서 구조에 대한 설명은 오픈스택 Octavia를 기준으로 설명합니다. 따라서 구체적으로 설명하기보다는  큰 그림으로 Octavia를 구성하는 컴포넌트들을 이해하고 이들이 각각 어떤 역할을 하는지 서술할 예정입니다. 그 후 Octavia를 Devstack을 통해 직접 설치하고 테스트를 진행해보겠습니다.

 

Octavia를 설명하기에 앞서 일반적인 로드밸런싱을 위한 공통적인 구조를 살펴보도록 하겠습니다. Octavia는 그림 2에서 보시는 것처럼 Neutron 로드밸런서 v2의 구조와 동일하게 로드밸런싱을 진행합니다. 

 

그림 2. 로드밸런싱 구조

그림 2에서는 로드밸런싱 구조를 나타냅니다. 기존 Neutron 로드밸런서는 Neutron 자체의 프로세스로 존재하였지만, Octavia에서는 Amphora라고 불리는 로드밸런서를 인스턴스 형태로 배포합니다. 물론 해당 인스턴스를 생성하는데 필요한 이미지, 네트워크 등 기본으로 모두 생성되어 있습니다. 

 

로드밸런서는 Listener를 통해 특정 포트를 수신하여 Pool에서 지정 된 로드밸런싱 방식(e.g. 라운드 로빈)에 따라 Pool 속한 Member들에게 데이터를 전달하게 됩니다. 만약 라운드 로빈이라면, 순서대로 Member들에게 전달합니다.  Health Monitor는 이름 그대로 Member의 상태 및 동작을 확인합니다. 만약 Pool에 속한 2개의 Member 중 하나가 죽어 있다면, 데이터는 살아있는 Member에게 전달됩니다. 

 

결론적으로, 인스턴스로 구성 된 로드밸런서는 각 리스너의 포트에 맞게 데이터를 수신하고 이를 Pool로 전달합니다. Pool은 라우드 로빈과 같은 자신의 로드밸런싱 규칙에 따라 Member들에게 이를 전달하고 Member들은 자신이 수행하는 기능에 따라 데이터를 처리하거나, 회신합니다. 

 

 

 

그림 3. Octavia 구조(참조:[3])

그림 3에서는 Octavia의 구조를 나타냅니다.  크게 Amphora, Controller(Octavia Server), Network로 나뉘게 됩니다. 

 

Amphora : Amphora는 가상 머신, 컨테이너 등으로 구성된 로드밸런서입니다. 아무래도 인스턴스이기 때문에 별도의 운영체제를 가지고 있으며, 이는 Octavia를 설치할 때 자동으로 등록됩니다. (공식문서에서는 Ubuntu라고 합니다.) 이들 내부에는 HAProxy가 동작하면서 Listener를 통해 적합한 Pool에 데이터를 전달합니다. Amphora는 여러 개로 구성될 수 있습니다.

 

Controller : Controller는 Octavia의 동작에 대한 전반적인 관리를 담당하고 있습니다. 특히 Driver의 경우 Nova에게 요청하여 Amphora 인스턴스를 생성하고, Amphora에 접근하기 위한 네트워크를 요청하는 등 여러 프로젝트 및 Amphora에게 명령을 내리기 위한 Driver 들이 구성 포함 되어 있습니다.  또한 Amphora의 상태를 점검하는 Health Manager, API를 처리하는 Controller Worker, 데이터베이스 및 인증서 관리를 담당하는 Housekeeping Manager 등을 포함하고 있습니다. 

 

Network : Amphora는 Octavia의 설정 파일에 등록 된 네트워크 서브넷을 통해 연결됩니다. 이에 따라 Octavia가 Amphora에 명령을 내릴 수 있는 접근 가능한 네트워크 서브넷이 필요하며, 본인의 네트워크 환경에 따라 Octavia의 구성 파일에서 이를 변경해주는 것이 필요합니다. 이는 뒤에서 설치 과정에서 설명이 되어 있으니 참고하시면 될 것 같습니다.

 

여기까지 Octavia의 구조에 대해 간단하게 알아보았고, 지금부터는 Octavia를 직접 설치한 뒤 테스트를 진행해보겠습니다. 

 

Install

* 오픈스택 구성 with Octavia

 

설치에 앞서 물리적 네트워크 구조는 앞서 포스팅한 "오픈스택 연구하기 : Devstack으로 오픈스택 빠르게 설치하기"[4]와 동일한 네트워크 구조를 가지기 때문에 이점 참조하시기 바랍니다. 

 

이번 포스팅에서는 오픈스택 Train 버전을 기준으로 작성합니다. 따라서 다른 포스팅에서도 설명드렸지만, 아래와 같이 Devstack을 위한 User를 생성하고 권한을 부여한 뒤 Stack 유저로 로그인합니다. 

root@openstack-controller:~# useradd -s /bin/bash -d /opt/stack -m stack
root@openstack-controller:~# echo "stack ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/stack
root@openstack-controller:~# sudo su - stack

 

아래의 명령은 Devstack을 다운 git clone을 이용해 받아주는데 이때 -b 옵션을 이용하여 train 버전 브랜치를 받습니다.  다음은 devstack 폴더로 이동하고 vi 명령어를 통해 local.conf를 열어줍니다. 

stack@openstack-controller:~$ git clone https://git.openstack.org/openstack-dev/devstack -b stable/train
stack@openstack-controller:~$ cd devstack
stack@openstack-controller:~/devstack$ vi local.conf

 

local.conf 파일은 아래와 같이 작성해주시면 됩니다. 해당 내용은 Octavia의 정식 문서를 기준으로 참고하여 작성한 것입니다.

[[local|localrc]]
# USB LAN CARD IP ADDRESS
HOST_IP=192.168.0.101

# MANUAL INTERFACE NAME
FLAT_INTERFACE=eno1
FLOATING_RANGE=192.168.11.224/27
FIXED_RANGE=10.10.10.0/20
FIXED_NETWORK_SIZE=256

#PASSWORD CONFIGURATION
ADMIN_PASSWORD=root
DATABASE_PASSWORD=$ADMIN_PASSWORD
RABBIT_PASSWORD=$ADMIN_PASSWORD
SERVICE_PASSWORD=$ADMIN_PASSWORD


#COMPUTE NODE
MULTI_HOST=True

#LOG CONFIGURATION
LOGFILE=/opt/stack/devstack.log
LOGDAYS=2
LOG_COLOR=True


LIBS_FROM_GIT=python-qinlingclient
QINLING_INSTALL_K8S=False

# Nova
ENABLED_SERVICES+=,n-api,n-crt,n-cpu,n-cond,n-sch,n-api-meta,n-sproxy
ENABLED_SERVICES+=,placement-api,placement-client

# Glance
ENABLED_SERVICES+=,g-api,g-reg

# Neutron
ENABLED_SERVICES+=,q-svc,q-agt,q-dhcp,q-l3,q-meta,neutron
ENABLED_SERVICES+=,octavia,o-cw,o-hk,o-hm,o-api

# Tempest
ENABLED_SERVICES+=,tempest
ENABLED_SERVICES+=,barbican

#Octavia
enable_plugin octavia https://opendev.org/openstack/octavia stable/train
enable_plugin octavia-dashboard https://opendev.org/openstack/octavia-dashboard.git stable/train

#barbican
enable_plugin barbican https://opendev.org/openstack/barbican stable/train

disable_service swift
disable_service c-api
disable_service c-sch
disable_service c-vol

아래의 명령을 통해 오픈스택 설치를 진행해주시면 됩니다.

stack@openstack-controller:~/devstack$ ./stack.sh

끝으로 인스턴스가 외부와의 통신이 가능할 수 있도록 br-ex 브릿지와 물리 인터페이스를 연결해줍니다.

stack@openstack-controller:~$ sudo ovs-vsctl add-port br-ex eno1
stack@openstack-controller:~$ reboot

 

* 네트워크 생성

Devstack을 이용하여 오픈스택 및 Octavia를 설치하게 되면, 기본적으로 "lb-mgmt-net"이라는 네트워크가 생성됩니다. 하지만 본 구성에서는 외부 네트워크로 서브넷을 구성하여 호스트에서 직접 접근이 가능하도록 구성할 예정이므로 먼저 외부 네트워크와 서브넷을 생성해 줍니다. 

 

관리 -> 네트워크 -> 네트워크 생성을 누르시면 팝업창이 뜨고, 그림 4와 같이 작성해 주시면 됩니다. 이름은 편하신 대로 external 등으로 해주시면 되고, 만약 포스팅과 동일한 물리 네트워크를 구성하셨을 경우는 아래와 같이 구성해주시면 됩니다. 

그림 4. 네트워크 구성

서브넷은 그림 5와 같이 구성해주시면 되는데, 저는 인스턴스 및 Amphora가 호스트와 물리적으로 연결된 공유기로부터 실제 IP를 할당받기 위해 네트워크 주소는 공유기의 IP 대역을 써주시면 됩니다. 

그림 5. 서브넷 설정

네트워크가 정상적으로 생성되었다면, Octavia의 기본 Amphora 네트워크를 변경해주어야 합니다.  아래의 명령어를 이용하여 octavia.conf 파일을 열어 준 뒤 controller_worker 세션에서 amp_boot_network_list에서 위에서 생성한 외부 네트워크의 아이디를 복사하여 붙여 넣어 줍니다. 

stack@openstack-controller:~/devstack$ vi /etc/octavia/octavia.conf

[controller_worker]
amp_boot_network_list = [원하는 네트워크의 ID] 0356299d-1b7f-4fc1-9e8e-3ce93d49f0e1

 

변경된 설정을 적용하기 위해 아래와 같이 Octavia를 재시작해줍니다. 

stack@openstack-controller:~$ sudo systemctl restart devstack@o-*

 

Test

이번 테스트는 Octavia의 공식 설치 문서에 진행한 테스트[5]를 참고하여 차근차근 수행해보도록 하겠습니다. 먼저 아래의 명령을 이용하여 로드밸런서 즉 Amphora를 생성하여 줍니다. 이때 이름은 LB이고 --vip-subet-id는 위에서 생성한 외부 네트워크의 서브넷 이름입니다. 

 

stack@openstack-controller:~$ source devstack/openrc admin admin
stack@openstack-controller:~$ openstack loadbalancer create --name LB --vip-subnet-id public

 

그림 6과 같이 로드밸런서가 생성된 결과를 보시면 vip_address의 주소가 보입니다. 이는 실제 공유기로부터 받아온 아이피 주소로, 같은 대역에 있는 호스트에서 쉽게 Amphora에 접근이 가능합니다.  (* 참고로 그림 6에서 보이는 vip의 주소와 Amphora 인스턴스의 아이피 주소가 다르며, 동일한 대역의 두 아이피를 동시에 가지는 이유는 하나는 로드밸런서 IP주소이고 하나는 인스턴스로써의 IP 주소입니다. )

그림 6. 로드밸런서 생성 결과

다음은 웹 테스트를 하기 위해 listener를 설정해주어야 합니다. --protocol은 HTTP이고 --protocol-port는 HTTP의 포트번호인 80을 적어줍니다. 마지막으로는 대상 로드밸런서의 이름을 작성해 줍니다. 

stack@openstack-controller:~$ openstack loadbalancer listener create --protocol HTTP --protocol-port 80 --name listener1 LB

 

앞서 설명한 로드밸런싱의 구성에 맞게 다음은 pool을 생성해 줍니다. 로드밸런싱에 대한 규칙을 설정해주고(여기서는 ROUND_ROBIN) 대상 listener의 이름과 protocol을 마찬가지로 작성해 줍니다. 

stack@openstack-controller:~$ openstack loadbalancer pool create --lb-algorithm ROUND_ROBIN --listener listener1 --protocol HTTP --name pool1

 

아래의 명령을 이용하여 테스트용 cirros 인스턴스를 2개 생성합니다이 때 "public"이라고 작성된 부분은 위에서 생성한 외부 네트워크 이름 혹은 원하는 네트워크 이름을 작성하시면 됩니다. 

stack@openstack-controller:~$ openstack server create --image $(openstack image list | awk '/ cirros-.*-x86_64-.* / {print $2}') --flavor 1 --nic net-id=$(openstack network list | awk '/ public / {print $2}') VM1
stack@openstack-controller:~$ openstack server create --image $(openstack image list | awk '/ cirros-.*-x86_64-.* / {print $2}') --flavor 1 --nic net-id=$(openstack network list | awk '/ public / {print $2}') VM2

 

최종적으로 그림 7과 같이 public이라는 외부 네트워크에 VM2, VM1, Amphora(로드밸런서)가 모두 생성되어 있습니다. 이들은 모두 실제 물리 공유기로부터 IP 주소를 할당받기 때문에 호스트에서도 쉽게 접근이 가능합니다. 

 

그림 7. 최종 생성 화면

SSH를 통해 VM1, VM2 각각의 인스턴스에 접속하여 아래의 명령어를 수행해 줍니다. 참고로 해당 명령어를 통해 각 인스턴스에 간단한 웹서버를 구축하고 요청 시 Welcom to [IP] 주소를 반환하도록 합니다.

$ MYIP=$(ifconfig eth0|grep 'inet addr'|awk -F: '{print $2}'| awk '{print $1}')
$ while true; do echo -e "HTTP/1.0 200 OK\r\n\r\nWelcome to $MYIP" | sudo nc -l -p 80 ; done&

마지막으로 생성한 두 인스턴스를 앞서 생성한 pool1에 Member로 아래의 명령을 이용하여 추가해 줍니다. 먼저 --subnet-id는 앞서 생성한 네트워크의 서브넷 이름(외부 네트워크)을 작성하시면 됩니다. --address는 생성한 인스턴스의 아이피 주소, --protocol-port는 포트번호 그리고 Pool의 이름을 작성해주시면 됩니다.

stack@openstack-controller:~$ openstack loadbalancer member create --subnet-id public --address 192.168.0.125 --protocol-port 80 pool1
stack@openstack-controller:~$ openstack loadbalancer member create --subnet-id public --address 192.168.0.115 --protocol-port 80 pool1

 

최종적으로 curl 명령어를 이용하여 로드밸런서의 VIP 주소에 curl 보내게 되면 아래와 같이 두 인스턴스가 번갈아가며 요청을 수행하는 것을 확인할 수 있습니다.

 

그림 8. 테스트 결과 화면

결론

이번 포스팅에서는 오픈스택이 로드밸런싱 기능을 제공하는 Octavia에 대해 간략히 설명하였고, 설치 및 테스트를 진행하였습니다. 사실 기본적으로 Octavia는 lb-mgmt-net이라는 네트워크를 기본적으로 제공하고 있고 이는 private 네트워크에 속합니다. 

 

따라서 외부에서 접근하기 위해서는 Router, 포워딩 등의 기능을 이용해야 하는데 이는 호스트에서 Amphora로 접속하기 위함입니다. 아마 Octavia를 구성하는 데 있어서 이렇게 Amphora 접근이 가능하도록 하는 것에서 많이 애를 먹었던 것 같습니다.

 

혹시나 Amphora가 생성되지 않는 다면 외부에서 Amphora에 접근이 가능한지 꼭 확인하시길 바랍니다.

부족한 내용이지만 읽어주셔서 감사합니다.

 

인용글

[1] [오픈스택개발] : 백업 기반의 VNF 고가용성기술 개발 : https://delightwook.tistory.com/20?category=766967

[2] Octavia 로고 : https://wiki.openstack.org/wiki/File:OpenStack_Project_Octavia_vertical.png#file

[3] Octavia 구조 : https://docs.openstack.org/octavia/latest/reference/introduction.html

[4] 오픈스택 연구하기 :  Devstack으로 오픈스택 빠르게 설치하기 : https://delightwook.tistory.com/40?category=766948

[5] Octavia 설치 문서 : https://docs.openstack.org/devstack/latest/guides/devstack-with-lbaas-v2.html

업데이트로그

----------------------------------------------------------------------------------------------------------------------------------------------------------

해당 글은 스스로 연구한 내용을 통한 주관적인 이해를 바탕으로 작성 되었습니다. 수정 할 부분이 있거나, 다른 의견이 있으시다면 언제든지 말씀해주시면 반영하도록 하겠습니다. 읽어 주셔서 감사합니다. 끝으로 불법으로 복제하는 것은 금합니다.

 

 

반응형

댓글

Designed by JB FACTORY