안녕하세요. 오픈소스컨설팅 조철진입니다.
한동안 이런저런 일들로 블로그 포스팅을 자주 올리지 못했습니다. 최근에는 OpenStack을 집중적으로 다루고 있어 앞으로 재밌는 주제가 있으면 블로그를 통해 소식을 전해드리도록 하려고 합니다.
요즘 현장에서 가장 자주 듣는 이야기 중 하나는 VMware 대체입니다. Broadcom 인수 이후 구독 전환과 라이선스 정책 변화로 비용이 크게 뛰면서 관련 고객 문의나 RFP 또는 PoC가 부쩍 늘었습니다. 특히 서버 몇 대로 클러스터를 꾸려 쓰던 중소 규모 환경에 대한 요구가 많은데 OpenStack이 대안으로 자주 거론되곤 합니다.
동시에 HCI(Hyper-Converged Infrastructure)에 대한 요구 사항도 증가하고 있습니다. 각 서버가 하이퍼바이저이면서 스토리지 노드이기도 한 구성으로 노드별 역할을 분리하는 일반적인 형태와 정반대의 성격이죠.
소규모 환경에서는 OpenStack을 도입하려 해도 구축과 운영 부담이 커져 ‘배보다 배꼽이 크다’, ‘소규모에는 적합하지 않다’는 인식으로 이어지는 경우가 많습니다. 그래서 컨트롤러, 컴퓨트, 스토리지를 동일한 서버에 통합한 HCI 구성을 바탕으로 VMware의 핵심 기능인 호스트 HA까지 동작하는 것을 목표로 시행착오를 거치며 OpenStack을 구성해본 경험을 공유 드립니다.

저희 회사의 OpenStack 배포 기준은 kolla-ansible입니다. 역할이 인벤토리 그룹으로 결정되는 구조라, 같은 호스트를 control/network/compute 그룹에 전부 넣으면 그게 곧 통합 노드가 됩니다. 스토리지는 Ceph 스토리지를 사용하며 cephadm으로 동일 노드에 mon/mgr/osd를 구성하고 연동했습니다.
컨트롤 플레인의 HA 구성은 kolla 표준을 따릅니다. keepalived + HAProxy로 VIP를, Galera와 RabbitMQ 클러스터로 데이터/메시징 계층을 3중화합니다. 컨트롤 플레인 역할은 사실 배포만 하면 어려울 게 없이 노드 하나가 죽어도 API는 계속 뜨고, DB도 살아 있습니다.
가장 어려웠던 점은 HA를 HCI 형태에서 구현하는 것이었습니다.
OpenStack에서는 Masakari라는 프로젝트가 그 역할을 합니다.
호스트 장애를 감지하면 해당 노드의 VM들을 다른 노드에서 자동으로 evacuate 해주는 컴포넌트인데, 문제는 일반적으로 배포 시 Masakari의 동작 방식이 HCI 구조와 충돌한다는 점이었습니다.
OpenStack의 호스트 HA는 전통적으로 Pacemaker 클러스터에 기대왔습니다. 이 모델의 전제는 컨트롤러에 pacemaker 클러스터, 컴퓨트는 pacemaker-remote 원격 노드로 역할을 분리해 컨트롤러가 컴퓨트 들을 원격으로 감시하는 구조 입니다.
그런데 한 서버가 클러스터이면서 동시에 자기 자신의 원격 노드일 수는 없기 때문에 통합 노드는 배포 시 오류가 발생합니다. 따라서 3노드 전부를 클러스터로 지정하고 remote 그룹을 통째로 비워 두었습니다.
# inventory — 기본 children 상속을 끊고 직접 정의
[hacluster]
node1
node2
node3
# 의도적으로 비움
[hacluster-remote]
추가로 kolla-ansible 배포 시 기본값이 원격 노드만 감시하도록 설정되어 있기 때문에, 클러스터 멤버를 감시하도록 옵션을 변경했습니다. 이 설정이 없으면 배포는 성공하지만 노드가 죽어도 아무 일도 일어나지 않습니다.
# masakari-hostmonitor.conf
[host]
restrict_to_remotes = False
호스트 장애 판정은 corosync의 연결 상태에 의존합니다. 노드 간 상시로 생존 신호(token)를 주고받다가 일정 시간 무소식이면 장애로 판정하는 방식인데, 이후 곧바로 evacuate라는 VM 복구 단계로 이어집니다.
문제는 기본 구성에서 이 생존 신호가 API 트래픽과 같은 망을 공유한다는 점입니다. 통합 구성으로 인해 노드에는 컨트롤 플레인, 하이퍼바이저, Ceph 스토리지가 운영 되기 때문에 네트워크 트래픽이 혼잡해졌다는 이유로 오탐이 발생한다면 시스템은 매우 큰 부담에 직면하게 됩니다.
따라서 corosync 링 설정을 이중화 했습니다. API 망을 ring0, 물리적으로 분리된 전용 heartbeat 망을 ring1로 구성해, 사망 판정 조건을 더 엄격하게 조절했다고 보면 됩니다.
# corosync.conf
node {
ring0_addr: 10.10.10.181 # API 망
ring1_addr: 172.16.0.181 # 전용 heartbeat 망
name: node1
}
정상적으로 배포한 이후 감시가 동작하는 것까지 확인했는데도 정작 fail-over 테스트에서 자동 복구가 실패했습니다. Masakari의 장애 감지 후 조치 첫 단계인 nova-compute 서비스의 비활성화가 매번 정확히 60초 만에 504/502 오류로 실패 하는 현상이 존재했습니다.

원인은 타이머 세 개의 충돌이었습니다. Nova는 죽은 호스트를 disable 할 때 그 호스트에 RPC를 보내고 60초(rpc_response_timeout)를 기다린 뒤에야 성공 응답을 만듭니다. 그런데 그 응답이 돌아올 때 haproxy 의 Timeout 이 60초, nova-api의 웹서버인 uwsgi의 Timeout도 60초로 응답이 돌아오려는 순간 기다리던 쪽이 먼저 연결을 끊어 오류가 발생했습니다.
해결 방법은 대기 타이머들을 Timeout을 보다 길게 설정하는 것입니다.
# globals.yml
haproxy_server_timeout: "2m"
haproxy_client_timeout: "2m"
# uwsgi.ini
http-timeout = 120

이 문제는 버그로 보고 되어 있지만 (https://bugs.launchpad.net/nova/+bug/1920977) 분리된 역할 구성에서는 경험한 적이 없었습니다. Nova가 이미 그 호스트를 down으로 인식한 뒤에 disable 명령을 수행하면, 죽은 호스트에 통보할 필요가 없으니 문제 없이 즉시 성공합니다.
반면 corosync 감지는 수 초 만에 끝나서 disable을 항상 Nova의 인식보다 먼저 요청하기 때문에 감지가 빨라진 것이 오히려 버그를 발생 시키므로 통합 구성에서는 이 조치가 필수입니다.
통합 노드에서는 컨트롤 플레인, VM, Ceph 스토리지가 같은 자원을 나눠 씁니다. corosync는 token 응답이 늦으면 노드를 장애로 판정하는데, VM·스토리지 부하로 token 응답이 지연되면 문제가 발생할 수 있습니다.
그 판정은 fail-over를 동작 시켜 살아있는 노드의 VM이 다른 곳에 또 뜨는 사고로 이어질 수 있고, 그래서 자원 경합을 피하기 위한 설정이 필수적입니다.
Nova에는 컨트롤 플레인/OSD 몫의 메모리를 예약하고, Ceph의 OSD 메모리 자동 배분 스케줄링은 기본 스토리지 전용 기준(70%)에서 HCI 기준(20%)으로 낮추고, 복구·리밸런싱은 클라이언트 I/O보다 낮은 우선순위로 설정했습니다.
# nova.conf
[DEFAULT]
reserved_host_memory_mb = 32768
cpu_allocation_ratio = 4.0
# ceph
ceph config set mgr mgr/cephadm/autotune_memory_target_ratio 0.2
ceph config set osd osd_mclock_profile high_client_ops
Nova의 메모리 예약을 늘리고 오버커밋을 줄일수록 각 노드가 VM에게 내줄 수 있는 자원도 함께 줄어서, 정작 evacuate 시점에 받아줄 호스트가 없는 문제(NoValidHost)가 발생할 수 있습니다. 3노드에서 자동 복구가 성립하려면 남은 2노드가 죽은 노드의 VM까지 받아야 하므로, 평소 사용률을 66% 이하(N-1 기준)가 유지되는 선에서 산정해야 합니다.
지금까지 HCI 형태로 OpenStack을 구축하면서 HA까지 구현했던 경험과 그 과정에서 마주쳤던 문제들을 정리해봤습니다. 대부분의 내용은 공식 문서 만으로는 찾기 어려웠던 부분들이었고, 실제 환경에서 하나씩 원인을 찾아가며 해결했던 시행착오에 가깝습니다.
물론 OpenStack이 모든 VMware 환경을 그대로 대체할 수 있는 만능 해답은 아닙니다. 운영 규모나 요구 사항에 따라 적합한 아키텍처는 달라질 수 있으며, 대규모 환경에서는 역할을 분리한 전통적인 구성이 여전히 더 적합한 경우가 많습니다.
다만 서버 수가 많지 않은 환경에서도 OpenStack을 운영할 수 있고, 적절한 설계와 튜닝를 통해 HCI 구조에서도 호스트 장애 시 자동 복구까지 구현할 수 있다는 점은 이번 검증을 통해 확인할 수 있었습니다. 특히 최근 라이선스 비용 증가로 VMware 대안을 검토하는 분들이라면 하나의 선택지가 될 수 있다고 생각합니다.
감사합니다.