Computer >> 컴퓨터 >  >> 시스템 >> Linux

Keepalived로 CentOS/RHEL에서 IP 페일오버 기반 고가용성(HA) 클러스터 구성하기

이 글에서는 사내 LAN에서 인터넷에 접속하기 위한 두 대의 Squid(Linux) 프록시 서버를 활용한 고가용성(HA) 페일오버 구성 방법을 다룹니다. 페일오버 구성을 위해 keepalived를 사용하여 HA 클러스터를 구축합니다.

HA 클러스터는 그룹 내 서버 중 하나에 하드웨어 또는 소프트웨어 문제가 발생하더라도 애플리케이션의 가동 중단 시간을 최소화할 수 있도록 이중화가 내장된 서버 그룹을 의미합니다. HA 클러스터가 정상적으로 동작하려면 다음 두 가지 요소가 반드시 구현되어야 합니다.

  • 서버 상태 확인(헬스체크)
  • 서버 장애 발생 시 리소스의 자동 전환

Keepalived는 이 두 가지를 모두 지원합니다. Keepalived는 Linux 시스템에서 서비스 페일오버와 로드 밸런싱을 가능하게 해주는 시스템 데몬입니다. 페일오버는 메인 서버에 장애가 발생하면 다른 서버로 전환되는 유동 IP(VIP) 주소를 통해 제공됩니다. 서버 간 IP 주소 자동 전환을 위해 keepalived는 VRRP(Virtual Router Redundancy Protocol – https://www.ietf.org/rfc/rfc2338.txt) 프로토콜을 사용합니다.

VRRP의 기본 원리

먼저 VRRP의 핵심 개념부터 살펴보겠습니다.

  • VIP(Virtual IP) — 장애 발생 시 서버 간에 자동으로 전환될 수 있는 가상 IP 주소입니다.
  • Master — 현재 VIP가 활성화되어 있는 서버입니다.
  • Backup — Master 서버에 장애가 발생했을 때 VIP가 전환될 서버들입니다.
  • VRID(Virtual Router ID) — 하나의 가상 IP(VIP)를 공유하는 서버들은 소위 '가상 라우터'를 구성하며, 이 가상 라우터의 고유 식별자는 1~255 사이의 값을 가집니다. 하나의 서버는 여러 VRID에 동시에 속할 수 있지만, 각 VRID는 반드시 고유한 가상 IP 주소를 가져야 합니다.

VRRP의 기본 동작 알고리즘

  • Master 서버는 일정한 주기마다 멀티캐스트 주소인 224.0.0.18로 VRRP 패킷(heartbeat, 하트비트)을 전송하고, 모든 Backup 서버는 이 주소를 수신 대기합니다. 멀티캐스트란 하나의 송신자가 여러 수신자에게 데이터를 보내는 방식을 의미합니다.
    참고: 서버들이 멀티캐스트 모드로 동작하려면 네트워크 장비가 멀티캐스트 트래픽을 지원해야 합니다.
  • Backup 서버가 일정 시간 동안 하트비트 패킷을 받지 못하면 Master 선출 절차를 시작합니다. 우선순위에 따라 Master가 된 서버는 VIP를 활성화하고 gratuitous ARP(무상 ARP)를 전송합니다. Gratuitous ARP는 특수한 형태의 ARP 응답으로, 네트워크 스위치의 MAC 테이블을 갱신하여 가상 IP 주소의 소유자가 변경되었음과 트래픽이 향해야 할 MAC 주소를 알려주는 역할을 합니다.

CentOS에서 keepalived 설치 및 설정

Squid가 설치된 CentOS 7 기반의 두 대의 Linux 서버(proxy-serv01, proxy-serv02)에 keepalived를 설치하고 구성합니다. 이번 구성에서는 가장 단순한 로드 밸런싱 방식인 Round Robin DNS를 사용합니다. 이 방식은 하나의 DNS 이름에 여러 개의 IP 주소를 등록하고, 클라이언트가 이 주소들을 순차적으로 받도록 하는 방식입니다. 따라서 하나의 DNS 이름(proxy-serv)에 등록된 두 개의 가상 IP 주소가 필요합니다. 네트워크 구성도는 아래와 같습니다.

각 Linux 서버에는 두 개의 물리적 네트워크 인터페이스가 있습니다. 공인(외부) IP가 할당된 eth1과 내부 네트워크에 연결된 eth0입니다.

실제(Real) IP 주소는 다음과 같습니다.

192.168.2.251 — proxy-server01
192.168.2.252 — proxy-server02

장애 발생 시 서버 간에 자동으로 전환되는 가상(Virtual) IP 주소는 다음과 같습니다.

192.168.2.101
192.168.2.102

중요: VRRP를 구성할 때 실제 서버 IP 주소를 가상 IP로 사용해서는 안 됩니다. 서버에 장애가 발생하면 해당 주소가 다른 서버로 넘어가고, 이후 복구(failback) 과정에서 원래 서버가 네트워크에서 고립될 수 있기 때문입니다. 원인은 다음과 같습니다. 원래 서버가 IP 주소를 되찾으려면 네트워크로 VRRP 패킷을 보내야 하는데, 정작 자신에게는 사용할 IP 주소가 없는 상황이 되기 때문입니다.

yum 패키지 관리자(CentOS 8에서는 dnf)를 사용하여 두 서버 모두에 keepalived를 설치합니다.

# yum install keepalived

두 서버 모두 설치가 완료되면 keepalived 설정 파일을 수정합니다.

# nano /etc/keepalived/keepalived.conf

두 서버의 설정 파일에서 서로 다른 파라미터는 state와 priority 부분입니다. proxy-serv01은 proxy_ip1 인스턴스의 MASTER(우선순위 255), proxy_ip2 인스턴스의 BACKUP(우선순위 100)으로 설정하고, proxy-serv02는 그 반대로 설정합니다.

주요 설정 옵션 설명

  1. vrrp_instance <name> — VRRP 인스턴스를 정의하는 섹션입니다.
  2. state <MASTER|BACKUP> — 시작 시 노드의 초기 상태입니다.
  3. interface <interface name> — VRRP가 동작할 인터페이스입니다.
  4. virtual_router_id <0~255 숫자> — VRRP 인스턴스의 고유 식별자로, 모든 서버에서 동일해야 합니다.
  5. priority <0~255 숫자> — 서버의 우선순위를 설정하며, 더 높은 우선순위를 가진 서버가 MASTER가 됩니다.
  6. virtual_ipaddress — MASTER 상태일 때 서버에서 활성화되는 가상 IP 주소 블록입니다. VRRP 인스턴스 내 모든 서버에서 동일하게 설정해야 합니다.

참고: VRRP 설정 예제에서 authentication 옵션을 사용하는 경우를 종종 볼 수 있습니다. 하지만 keepalived 문서에 따르면 인증 기능은 실질적인 보안을 제공하지 못한다는 이유로 2004년 RFC3768 명세(https://tools.ietf.org/html/rfc3768)에서 VRRPv2에서 제거되었습니다. 따라서 이 옵션의 사용은 권장되지 않습니다.

현재 네트워크 환경에서 멀티캐스트 사용이 어렵다면, keepalived가 제공하는 유니캐스트 옵션을 사용할 수 있습니다. 즉, VRRP 하트비트 패킷을 목록에 지정된 서버들로 직접 전송하는 방식입니다. 유니캐스트를 사용하려면 다음 옵션이 필요합니다.

  • unicast_src_ip — VRRP 패킷의 출발지 주소입니다.
  • unicast_peer — VRRP 패킷을 전송할 대상 서버 IP 주소 블록입니다.

이렇게 구성하면 두 개의 VRRP 인스턴스(proxy_ip1, proxy_ip2)가 정의됩니다. 정상 운영 시 proxy-serv01은 가상 IP 192.168.2.101의 MASTER이자 192.168.2.102의 BACKUP이며, 반대로 proxy-serv02는 192.168.2.102의 MASTER이자 192.168.2.101의 BACKUP 역할을 합니다.

서버에 방화벽이 활성화되어 있다면 iptables로 멀티캐스트 트래픽과 VRRP에 대한 허용 규칙을 추가해야 합니다.

# iptables -A INPUT -i eth0 -d 224.0.0.0/8 -j ACCEPT
# iptables -A INPUT -p vrrp -i eth0 -j ACCEPT

두 서버 모두에서 keepalived 서비스를 부팅 시 자동 시작하도록 등록하고 실행합니다.

# systemctl enable keepalived
# systemctl start keepalived

keepalived가 시작되면 설정 파일에 정의된 대로 가상 IP 주소가 인터페이스에 할당됩니다. 각 서버의 eth0 IP 주소를 확인해 보겠습니다.

# ip a show eth0

proxy-serv01에는 192.168.2.251(실제 IP)과 함께 MASTER로 활성화된 192.168.2.101(가상 IP)이 표시되고, proxy-serv02에는 192.168.2.252(실제 IP)와 함께 192.168.2.102(가상 IP)가 표시됩니다.

Keepalived로 애플리케이션·인터페이스 헬스체크 수행하기

VRRP 프로토콜은 서버 상태 모니터링을 제공합니다. 물리적 서버 장애나 스위치/서버 NIC 포트 오류 상황에서 유용하지만, 그 외에도 다음과 같은 문제가 발생할 수 있습니다.

  • 프록시 서버(또는 기타 애플리케이션) 오류 — 서버의 가상 주소로 접속한 클라이언트의 브라우저에 프록시 서버를 사용할 수 없다는 오류 메시지가 표시됩니다.
  • 두 번째 인터페이스의 인터넷 연결 실패 — 클라이언트 브라우저에 연결을 설정할 수 없다는 오류 메시지가 표시됩니다.

이러한 상황에 대응하려면 다음 옵션들을 사용합니다.

  • track_interface — 인터페이스 상태를 모니터링하며, 나열된 인터페이스 중 하나라도 DOWN 상태가 되면 해당 VRRP 인스턴스를 FAULT 상태로 전환합니다.
  • track_script — 스크립트를 통해 HA 애플리케이션의 헬스체크를 수행합니다. 스크립트는 성공 시 0, 실패 시 1을 반환해야 합니다.

VRRP 인스턴스는 기본적으로 자신이 바인딩된 인터페이스(현재 구성에서는 eth0)만 확인하므로, 외부 인터페이스인 eth1까지 모니터링하도록 설정을 업데이트합니다.

track_interface {
 eth1
}

track_script 디렉티브는 vrrp_script 블록에서 정의한 파라미터에 따라 스크립트를 실행합니다. 형식은 다음과 같습니다.

vrrp_script <name> {
 script <"실행 파일 경로">
 interval <초 단위 숫자> - 스크립트 실행 주기, 기본값 1초
 fall <횟수> - FAULT 상태로 전환하기 위해 스크립트가 0이 아닌 값을 반환해야 하는 횟수
 rise <횟수> - FAULT 상태에서 벗어나기 위해(failback) 스크립트가 0을 반환해야 하는 횟수
 timeout <초> - 스크립트 결과를 기다리는 시간 (시간 초과 시 0이 아닌 값 반환)
 weight <숫자> - FAULT 상태가 되었을 때 감소시킬 서버 우선순위 값. 기본값은 0이며, 이 경우 fall 파라미터에서 설정한 횟수만큼 스크립트 실패 후 서버가 FAULT 상태가 됩니다.
}

이제 Squid 프록시 헬스체크를 구성해 보겠습니다. 다음 명령으로 squid 프로세스가 활성 상태인지 확인할 수 있습니다.

# squid -k check

3초마다 실행되는 vrrp_script를 생성합니다. 이 블록은 vrrp_instance 블록 외부에 정의해야 합니다.

vrrp_script chk_squid_service {
 script "/usr/sbin/squid -k check"
 interval 3
}

그리고 이 스크립트를 모든 vrrp_instance 블록에 추가하여 모니터링에 포함시킵니다.

track_script {
 chk_squid_service
}

이렇게 하면 Squid에 장애가 발생했을 때 가상 IP 주소가 다른 서버로 자동 전환됩니다.

서버 상태가 변경될 때 수행할 추가 작업도 지정할 수 있습니다.

Squid가 모든 인터페이스에서 연결을 수락하도록 설정되어 있다면(예: http_port 0.0.0.0:3128), 가상 IP가 전환되어도 문제없이 새 주소로의 연결을 수락합니다. 하지만 다음과 같이 특정 IP 주소가 설정되어 있는 경우에는,

http_port 192.168.2.101:3128
http_port 192.168.2.102:3128

Squid는 시스템에 새 주소가 나타난 것을 알지 못해 해당 주소로 들어오는 클라이언트 요청을 수신하지 못합니다. 이처럼 가상 IP 전환 시 추가 작업이 필요한 상황을 처리하기 위해, keepalived는 서버 상태가 변경될 때(예: MASTER → BACKUP 또는 그 반대) 스크립트를 실행할 수 있게 해줍니다. 이는 다음 옵션으로 구현합니다.

notify "실행 파일 경로"

장애 상황에서 Keepalived 페일오버 테스트

가상 IP 구성을 마쳤다면 장애가 올바르게 처리되는지 반드시 확인해야 합니다. 첫 번째 테스트는 서버 장애 시뮬레이션입니다. proxy-serv01의 eth0을 비활성화하면 VRRP 하트비트 패킷 전송이 중단됩니다. 이때 proxy-serv02가 가상 IP 192.168.2.101을 활성화해야 합니다. 다음 명령으로 확인합니다.

# ip a show eth0

예상대로 proxy-serv02가 가상 IP 192.168.2.101을 활성화했습니다. 로그를 통해 어떤 일이 있었는지 살펴보겠습니다.

cat /var/log/messages | grep -i keepalived

proxy-serv01 로그proxy-serv02 로그
Kernel is reporting: interface eth0 DOWN
VRRP_Instance(proxy_ip1) Entering FAULT STATE
VRRP_Instance(proxy_ip1) removing protocol VIPs.
VRRP_Instance(proxy_ip1) Now in FAULT state
VRRP_Instance(proxy_ip1) Transition to MASTER STATE
keepalived가 eth0의 DOWN 상태 신호를 받아 proxy_ip1 VRRP 인스턴스를 FAULT 상태로 전환하고, 가상 IP 주소를 해제합니다.keepalived가 proxy_ip1 VRRP 인스턴스를 MASTER 상태로 설정하고, eth0에 IP 192.168.2.101을 활성화한 후 gratuitous ARP를 전송합니다.

이제 proxy-serv01의 eth0을 다시 활성화하면 가상 IP 192.168.2.101이 원래 서버로 되돌아오는지 확인합니다.

proxy-serv01 로그proxy-serv02 로그
VRRP_Instance(proxy_ip1) forcing a new MASTER election
VRRP_Instance(proxy_ip1) Transition to MASTER STATE
VRRP_Instance(proxy_ip1) Entering MASTER STATE
VRRP_Instance(proxy_ip1) setting protocol VIPs.
Sending gratuitous ARP on eth0 for 192.168.2.101
VRRP_Instance(proxy_ip1) Received advert with higher priority 255, ours 100
VRRP_Instance(proxy_ip1) Entering BACKUP STATE
VRRP_Instance(proxy_ip1) removing protocol VIPs.
keepalived가 eth0 복구 신호를 받고 proxy_ip1 VRRP 인스턴스의 MASTER 재선출을 시작합니다. MASTER 상태가 되면 eth0에 IP 192.168.2.101을 활성화하고 gratuitous ARP를 전송합니다.keepalived가 proxy_ip1 VRRP 인스턴스에 대해 더 높은 우선순위의 패킷을 수신하면 BACKUP 상태로 전환하고 가상 IP를 해제합니다.

두 번째 테스트는 외부 네트워크 인터페이스 장애 시뮬레이션입니다. proxy-serv01의 외부 인터페이스 eth1을 비활성화하고 로그 결과를 확인합니다.

proxy-serv01 로그proxy-serv02 로그
Kernel is reporting: interface eth1 DOWN
VRRP_Instance(proxy_ip1) Entering FAULT STATE
VRRP_Instance(proxy_ip1) removing protocol VIPs.
VRRP_Instance(proxy_ip1) Now in FAULT state
VRRP_Instance(proxy_ip1) Transition to MASTER STATE
VRRP_Instance(proxy_ip1) Entering MASTER STATE
VRRP_Instance(proxy_ip1) setting protocol VIPs.
Sending gratuitous ARP on eth0 for 192.168.2.101
keepalived가 eth1의 DOWN 신호를 받아 proxy_ip1 VRRP 인스턴스를 FAULT 상태로 전환하고 가상 IP를 해제합니다. track_interface 설정 덕분에 내부 인터페이스가 정상이더라도 외부 인터페이스 장애를 감지할 수 있습니다.keepalived가 proxy_ip1 VRRP 인스턴스를 MASTER 상태로 설정하고, eth0에 IP 192.168.2.101을 활성화한 후 gratuitous ARP를 전송합니다.

세 번째 테스트는 Squid 장애 시뮬레이션입니다. 다음 명령으로 서비스를 수동으로 중지합니다.

# systemctl stop squid

로그에서 결과를 확인합니다.

proxy-serv01 로그proxy-serv02 로그
VRRP_Script(chk_squid_service) failed
VRRP_Instance(proxy_ip1) Entering FAULT STATE
VRRP_Instance(proxy_ip1) removing protocol VIPs.
VRRP_Instance(proxy_ip1) Now in FAULT state
VRRP_Instance(proxy_ip1) Transition to MASTER STATE
VRRP_Instance(proxy_ip1) Entering MASTER STATE
VRRP_Instance(proxy_ip1) setting protocol VIPs.
Sending gratuitous ARP on eth0 for 192.168.2.101
Squid 프록시 서비스 활성 상태를 검사하는 스크립트가 오류를 반환합니다. keepalived가 proxy_ip1 VRRP 인스턴스를 FAULT 상태로 전환하고 가상 IP를 해제합니다.keepalived가 proxy_ip1 VRRP 인스턴스를 MASTER 상태로 설정하고, eth0에 IP 192.168.2.101을 활성화한 후 gratuitous ARP를 전송합니다.

세 가지 테스트가 모두 성공적으로 통과했으며, keepalived가 올바르게 구성되었음을 확인했습니다. 참고로 이후에는 Pacemaker를 사용한 HA 클러스터 구성 방법과 두 도구의 특징 비교도 다룰 예정입니다.

proxy-serv01의 최종 설정 파일(/etc/keepalived/keepalived.conf)

vrrp_script chk_squid_service {
 script "/usr/sbin/squid -k check"
 interval 3
}

vrrp_instance proxy_ip1 {
 state MASTER
 interface eth0
 virtual_router_id 1
 priority 255
 virtual_ipaddress {
  192.168.2.101/24 dev eth0 label eth0:1
 }
 track_interface {
  eth1
 }
 track_script {
  chk_squid_service
 }
}

vrrp_instance proxy_ip2 {
 state BACKUP
 interface eth0
 virtual_router_id 2
 priority 100
 virtual_ipaddress {
  192.168.2.102/24 dev eth0 label eth0:2
 }
 track_interface {
  eth1
 }
 track_script {
  chk_squid_service
 }
}

proxy-serv02의 최종 설정 파일(/etc/keepalived/keepalived.conf)

vrrp_script chk_squid_service {
 script "/usr/sbin/squid -k check"
 interval 3
}

vrrp_instance proxy_ip1 {
 state BACKUP
 interface eth0
 virtual_router_id 1
 priority 100
 virtual_ipaddress {
  192.168.2.101/24 dev eth0 label eth0:1
 }
 track_interface {
  eth1
 }
 track_script {
  chk_squid_service
 }
}

vrrp_instance proxy_ip2 {
 state MASTER
 interface eth0
 virtual_router_id 2
 priority 255
 virtual_ipaddress {
  192.168.2.102/24 dev eth0 label eth0:2
 }
 track_interface {
  eth1
 }
 track_script {
  chk_squid_service
 }
}