Configurando Alta Disponibilidade com Keepalived e VRRP

O Keepalived é uma solução robusta para implementar alta disponibilidade (HA) de serviços, especialmente em conjunto com o LVS (Linux Virtual Server). Ele utiliza o protocolo VRRP (Virtual Router Redundancy Protocol) para eliminar pontos únicos de falha, garantindo que um serviço continue acessível mesmo que um servidor falhe.

Em um cenário típico com Keepalived, dois servidores operam em um esquema mestre-backup. O servidor mestre (MASTER) gerencia um endereço IP virtual (VIP) e envia mensagens de "heartbeat" (pulso de vida) ao servidor de backup (BACKUP). Se o backup deixar de receber essas mensagens, ele assume que o mestre falhou, toma posse do VIP e continua a fornecer o serviço, assegurando a continuidade operacional. O Keepalived também monitora a saúde dos serviços nos servidores, removendo aqueles que apresentam falhas e reintegrando-os quando a operação normal é restabelecida.

Instalação do Keepalived

Para configurar o Keepalived em sistemas baseados em RHEL/CentOS, siga os passos abaixo:

# Instalar o repositório EPEL e o Keepalived (e Nginx para um exemplo de serviço)
sudo dnf install -y epel-release # Ou `yum install -y epel-release` em sistemas mais antigos
sudo dnf install -y keepalived nginx

Configuração Básica e Ativação

Após a instalação, configure um arquivo simples no Nginx para testar e inicie os serviços. Este exemplo demonstra a configuração em um servidor de backup:

# Cria um arquivo index.html simples para o Nginx no servidor de backup
echo "Servidor de Backup: Conteúdo NGINX" | sudo tee /usr/share/nginx/html/index.html

# Ativa e inicia os serviços Keepalived e Nginx
sudo systemctl enable --now keepalived.service
sudo systemctl enable --now nginx.service

Verificação do IP Virtual

Para verificar se o IP virtual foi atribuído corretamente, use o comando ip a. No servidor mestre, você deve ver o VIP listado na interface de rede. Em caso de falha do mestre, o backup assumirá o VIP. Para simular, pare o Keepalived no mestre e observe o VIP migrar para o backup:

# Exemplo de saída 'ip a' no servidor MASTER (192.168.115.111) com VIP (192.168.115.250)
ip a
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:c8:dc:33 brd ff:ff:ff:ff:ff:ff
    inet 192.168.115.111/24 brd 192.168.115.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet 192.168.115.250/32 scope global ens33 # VIP atribuído ao MASTER

# Parar o serviço Keepalived no MASTER para forçar o failover
sudo systemctl stop keepalived.service

# Exemplo de saída 'ip a' no servidor BACKUP (192.168.115.112) após o failover
ip a
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:8a:4a:79 brd ff:ff:ff:ff:ff:ff
    inet 192.168.115.112/24 brd 192.168.115.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet 192.168.115.250/32 scope global ens33 # VIP agora atribuído ao BACKUP

Estrutura do Arquivo de Configuração do Keepalived

O arquivo principal de configuração do Keepalived é geralmente localizado em /etc/keepalived/keepalived.conf. Abaixo estão as seções chave e seus parâmetros.

global_defs {
    # Configurações globais para notificação por e-mail em caso de transição de estado
    notification_email {
        admin@exemplo.com
    }
    notification_email_from keepalived@exemplo.com # Endereço do remetente
    smtp_server 127.0.0.1 # Servidor SMTP para envio de e-mails
    smtp_connect_timeout 30 # Tempo limite de conexão SMTP em segundos
    router_id NOME_DO_ROTEADOR # Identificador único para a máquina Keepalived (ex: LVS_PROD)
}

# Define um grupo de instâncias VRRP para sincronização de estado
vrrp_sync_group VRRP_GRUPO_1 {
    group {
        instancia_rede_interna # Nome da instância VRRP
        instancia_rede_externa # Outra instância VRRP
    }
    # Scripts a serem executados em diferentes transições de estado
    notify_master "/caminho/para/script_master.sh" # Executado ao se tornar MASTER
    notify_backup "/caminho/para/script_backup.sh" # Executado ao se tornar BACKUP
    notify_fault "/caminho/para/script_fault.sh VRRP_GRUPO_1" # Executado em caso de falha
    notify "/caminho/para/script_geral.sh" # Executado em qualquer transição de estado
    smtp_alert # Envia alertas por e-mail usando as configurações de global_defs
}

O Keepalived invoca scripts específicos conforme as mudanças de estado:

  • notify_master: Chamado quando o nó se torna MASTER.
  • notify_backup: Chamado quando o nó se torna BACKUP.
  • notify_fault: Chamado quando o nó entra em estado de falha.

Configuração da Instância VRRP

A seção vrrp_instance define o comportamento de alta disponibilidade para um IP virtual.

vrrp_instance INSTANCIA_WEB_FRONT {
    state BACKUP # Estado inicial: MASTER ou BACKUP. A prioridade decide quem será o MASTER.
    interface eth0 # Interface de rede onde o VRRP opera e o VIP será vinculado.
    dont_track_primary # Ignora erros na interface primária (padrão: não definido).
    track_interface { # Define interfaces adicionais para monitoramento. Se qualquer uma falhar, ocorre failover.
        eth1
        eth2
    }
    # mcast_src_ip # Endereço IP de origem para pacotes multicast (padrão: IP primário da interface).
    # garp_master_delay # Atraso para enviar ARP Gratuitos após se tornar MASTER.
    virtual_router_id 50 # Identificador do roteador virtual (VRID). Deve ser o mesmo para todos os nós do grupo.
    priority 99 # Prioridade do nó. O nó com maior prioridade geralmente se torna MASTER.
    advert_int 1 # Intervalo (em segundos) entre o envio de pacotes VRRP (heartbeats).

    nopreempt # Desabilita a preempção. Um nó BACKUP com 'nopreempt' e maior prioridade não assumirá como MASTER se o MASTER atual estiver saudável.
              # Esta opção é geralmente configurada no nó BACKUP. Para desabilitar o failback automático, defina 'nopreempt' em todos os nós e defina 'state BACKUP' em todos.
    # preempt_delay 300 # Atraso (em segundos) antes da preempção, se 'nopreempt' não estiver ativado (padrão: 5 minutos).
    # debug # Nível de depuração.

    authentication { # Configura a autenticação para pacotes VRRP.
        auth_type PASS # Tipo de autenticação (PASS ou AH).
        auth_pass minha_senha_secreta # Senha de autenticação (somente os primeiros 8 caracteres são significativos).
    }

    virtual_ipaddress { # Define o IP virtual (VIP) que será gerenciado pelo Keepalived.
        192.168.202.200/24
    }
}

Configuração do Servidor Virtual (LVS)

Esta seção é usada para integrar o Keepalived com o LVS, definindo como o tráfego será balanceado entre os real_servers.

virtual_server 192.168.202.200 80 { # VIP e porta do serviço virtual
    delay_loop 6 # Intervalo (em segundos) para verificações de saúde nos real_servers.
    lb_algo rr # Algoritmo de balanceamento de carga (ex: round-robin (rr), weighted round-robin (wrr), least-connection (lc)).
    lb_kind DR # Modo de encaminhamento do LVS (NAT, DR - Direct Routing, TUN - IP Tunneling).
    persistence_timeout 5 # Tempo (em segundos) para manter a sessão do cliente no mesmo real_server.
    protocol TCP # Protocolo do serviço virtual (TCP ou UDP).
    # persistence_granularity <NETMASK> # Granularidade da persistência de sessão.
    # virtualhost <string> # Cabeçalho Host HTTP para verificação de saúde.
    # sorry_server 192.168.1.100 8080 # Servidor de fallback quando todos os real_servers falham.

    real_server 192.168.200.5 80 { # Um dos servidores reais para balanceamento
        weight 1 # Peso do servidor para algoritmos ponderados (0 significa inativo).
        inhibit_on_failure # Se definido, o peso do servidor é definido para 0 em caso de falha, em vez de removê-lo completamente do pool.
        notify_up "/caminho/para/script_server_up.sh" # Script executado quando o real_server está ativo.
        notify_down "/caminho/para/script_server_down.sh" # Script executado quando o real_server está inativo.

        TCP_CHECK { # Verificação de saúde baseada em conexão TCP
            connect_timeout 3 # Tempo limite de conexão em segundos.
            nb_get_retry 3 # Número de tentativas de conexão.
            delay_before_retry 3 # Atraso (em segundos) entre as tentativas de reconexão.
            connect_port 80 # Porta para verificação de saúde.
            # bindto <ip> # Endereço IP para ligar a conexão de verificação.
        }

        # HTTP_GET | SSL_GET { # Verificação de saúde HTTP/HTTPS
        #     url { # Múltiplas URLs podem ser especificadas
        #         path /
        #         digest <string> # Hash MD5 do conteúdo da página para validação (gerado com 'genhash').
        #         status_code 200 # Código de status HTTP esperado (ex: 200, 301, 302).
        #     }
        #     connect_port 80
        #     bindto <IPADD>
        #     connect_timeout 5
        #     nb_get_retry 3
        #     delay_before_retry 2
        # }

        # SMTP_CHECK { # Verificação de saúde SMTP
        #     host {
        #         connect_ip <IP ADDRESS>
        #         connect_port 25 # Porta padrão para SMTP
        #         bindto <IP ADDRESS>
        #     }
        #     connect_timeout 5
        #     retry 3
        #     delay_before_retry 2
        #     helo_name <string> # Parâmetro do comando HELO SMTP.
        # }

        # MISC_CHECK { # Verificação de saúde usando um script externo
        #     misc_path "/caminho/para/script_custom.sh" # Caminho para o script ou programa externo.
        #     misc_timeout 10 # Tempo limite para a execução do script.
        #     misc_dynamic # Ajusta dinamicamente o peso do servidor com base no código de saída do script:
        #                  # 0: Sucesso (sem alteração de peso); 1: Falha (peso 0); 2-255: Sucesso (peso = código_saída - 2).
        # }
    }
}

Conceitos Chave do Keepalived/VRRP

  • Roteador Virtual: Um grupo lógico de roteadores (um Master e um ou mais Backups) que atua como um único roteador.
  • VRID (Virtual Router ID): Um identificador único que agrupa roteadores em um roteador virtual.
  • Roteador Master: O roteador ativo que encaminha pacotes e possui o VIP.
  • Roteador Backup: Roteadores em espera que assumem a função de Master se o Master falhar.
  • Endereço IP Virtual (VIP): O endereço IP compartilhado que os clientes usam para acessar o serviço de alta disponibilidade.
  • Prioridade: Um valor numérico que determina a preferência de um roteador para se tornar Master. Prioridades mais altas indicam maior preferência.
  • Modo Não-Preemptivo (Nopreempt): Se configurado, um roteador Backup não tentará assumir a função de Master mesmo que tenha uma prioridade mais alta, desde que o Master atual esteja saudável.
  • Modo Preemptivo: O comportamento padrão. Um Backup com prioridade mais alta tentará se tornar Master se o Master atual tiver uma prioridade menor ou falhar.

Uso Avançado e Monitoramento de Saúde

O Keepalived é empregado principalmente em dois cenários: para alta disponibilidade de servidores LVS (LVS+Keepalievd) e para failover de serviços críticos, como bancos de dados (ex: MySQL em configuração mestre-mestre ou mestre-escravo). O foco principal aqui será nas capacidades de monitoramento de saúde e notificação de estado do Keepalived.

Mecanismo de Alta Disponibilidade

O Keepalived utiliza o VRRP para criar um grupo de failover (master-backup). O nó Master detém o VIP e atende às requisições. Se o Keepalived detectar uma falha no Master (seja por um crash do sistema ou falha do serviço monitorado), o nó Backup assume automaticamente o VIP e se torna o novo Master. Quando o nó original se recupera, ele pode opcionalmente retomar a função de Master (comportamento padrão) ou permanecer como Backup, dependendo da configuração de nopreempt.

Princípios de Funcionamento em Diferentes Camadas

O Keepalived pode monitorar a saúde dos serviços em diferentes camadas do modelo OSI:

  • Camada 3 (Rede): O Keepalived envia pacotes ICMP (ping) periodicamente aos servidores para verificar sua acessibilidade básica. Se um servidor não responder, é considerado inativo.
  • Camada 4 (Transporte): Monitores de porta TCP verificam se um serviço está escutando em uma porta específica (ex: MySQL na porta 3306). A falha na conexão TCP indica um problema com o serviço.
  • Camada 7 (Aplicação): Verificações mais complexas podem ser realizadas usando HTTP/SSL (verificando URLs e códigos de status) ou scripts personalizados (MISC_CHECK) que validam a lógica da aplicação, como a presença de processos, a resposta de APIs, etc.

Exemplos de Verificação de Saúde e Notificação

Segue um exemplo de configuração para monitorar um serviço MySQL e enviar notificações.

! Configuration File for keepalived
global_defs {
    notification_email {
        seu_email@dominio.com
    }
    notification_email_from keepalived@dominio.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id MYSQL_HA_CLUSTER
}

vrrp_instance VI_MYSQL {
    state BACKUP # Estado inicial
    interface eth1 # Interface de rede
    virtual_router_id 50
    nopreempt # Desativa preempção (se este nó tiver prioridade maior, não assume a menos que o MASTER falhe)
    priority 100 # Prioridade (maior no MASTER, menor no BACKUP)
    advert_int 1 # Intervalo de heartbeat

    authentication {
        auth_type PASS
        auth_pass minha_senha_vrrp
    }

    virtual_ipaddress {
        192.168.1.200/24 # O IP Virtual para o MySQL
    }

    # Scripts de notificação para transições de estado da instância VRRP
    notify_master "/etc/keepalived/scripts/to_master_mysql.sh"
    notify_backup "/etc/keepalived/scripts/to_backup_mysql.sh"
    notify_fault "/etc/keepalived/scripts/to_fault_mysql.sh"
}

virtual_server 192.168.1.200 3306 { # Monitora o VIP na porta 3306 (MySQL)
    delay_loop 6 # Intervalo de verificação de saúde

    persistence_timeout 50
    protocol TCP

    real_server 192.168.1.201 3306 { # Exemplo de Real Server (o próprio MySQL local ou remoto)
        weight 1
        notify_up "/etc/keepalived/scripts/mysql_up_alert.sh" # Script ao detectar MySQL UP
        notify_down "/etc/keepalived/scripts/mysql_down_failover.sh" # Script ao detectar MySQL DOWN

        TCP_CHECK { # Verificação de saúde TCP
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 3306
        }
    }
}

Scripts de Exemplo para Monitoramento de Processos

Aqui estão exemplos de scripts para monitorar processos de serviços como Nginx ou MySQL, que podem ser usados com vrrp_script ou MISC_CHECK.

Script para verificar Nginx e tentar reiniciar (/etc/keepalived/scripts/check_nginx_restart.sh):

#!/bin/bash
# Script para verificar o status do Nginx e tentar reiniciá-lo
NGINX_SVC="nginx"
KEEPALIVED_SVC="keepalived"
LOG_PATH="/var/log/keepalived_nginx_check.log"

if ! pgrep -x "$NGINX_SVC" > /dev/null; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') [$(hostname)] Nginx não detectado. Tentando iniciar..." | sudo tee -a "$LOG_PATH"
    sudo systemctl start "$NGINX_SVC"
    sleep 3 # Aguarda o serviço Nginx iniciar

    if ! pgrep -x "$NGINX_SVC" > /dev/null; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') [$(hostname)] Falha ao iniciar Nginx. Forçando failover do Keepalived." | sudo tee -a "$LOG_PATH"
        sudo systemctl stop "$KEEPALIVED_SVC" # Para o Keepalived para forçar o failover
        exit 1 # Sinaliza falha
    else
        echo "$(date '+%Y-%m-%d %H:%M:%S') [$(hostname)] Nginx iniciado com sucesso." | sudo tee -a "$LOG_PATH"
        exit 0 # Sinaliza sucesso
    fi
else
    exit 0 # Nginx já está em execução
fi

Script simples para verificar Nginx (/etc/keepalived/scripts/check_nginx_simple.sh):

#!/bin/bash
# Verifica se o processo Nginx está em execução
if pgrep -x "nginx" > /dev/null; then
    exit 0 # Nginx está ativo
else
    exit 1 # Nginx não está ativo
fi

Script para verificar MySQL e tentar reiniciar (/etc/keepalived/scripts/check_mysql_restart.sh):

#!/bin/bash
# Script para verificar o status do MySQL e tentar reiniciá-lo
MYSQL_SVC="mysqld"
KEEPALIVED_SVC="keepalived"
LOG_PATH="/var/log/keepalived_mysql_check.log"

if ! pgrep -x "$MYSQL_SVC" > /dev/null; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') [$(hostname)] MySQL não detectado. Tentando iniciar..." | sudo tee -a "$LOG_PATH"
    sudo systemctl start "$MYSQL_SVC"
    sleep 5 # Aguarda o serviço MySQL iniciar

    if ! pgrep -x "$MYSQL_SVC" > /dev/null; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') [$(hostname)] Falha ao iniciar MySQL. Sinalizando falha para Keepalived." | sudo tee -a "$LOG_PATH"
        exit 1 # Sinaliza falha
    else
        echo "$(date '+%Y-%m-%d %H:%M:%S') [$(hostname)] MySQL iniciado com sucesso." | sudo tee -a "$LOG_PATH"
        exit 0 # Sinaliza sucesso
    fi
else
    exit 0 # MySQL já está em execução
fi

Para usar esses scripts, você pode referenciá-los em vrrp_script e track_script:

vrrp_script check_nginx_app {
    script "/etc/keepalived/scripts/check_nginx_restart.sh"
    interval 2 # Executa o script a cada 2 segundos
    weight -10 # Reduz a prioridade da instância em 10 se o script falhar
}

vrrp_instance VI_1 {
    # ... outras configurações ...
    track_script { # Referencia o script na instância VRRP
        check_nginx_app
    }
}

Scripts de Notificação de Status de Instância

Estes scripts são acionados quando a instância VRRP muda de estado. Exigem que um agente de e-mail (como sendmail ou postfix) esteja configurado e funcionando no sistema.

# Instale sendmail e mailx para envio de e-mails, se necessário
# sudo dnf install -y sendmail mailx
# sudo systemctl enable --now sendmail

# Script: /etc/keepalived/scripts/to_master_mysql.sh
#!/bin/bash
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
HOSTNAME_NODE=$(hostname)
NODE_IP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1) # Ajuste 'eth1' conforme sua interface
NOTIFICATION_EMAIL="seu_email@dominio.com"
SUBJECT="Keepalived: Nó $HOSTNAME_NODE se tornou MASTER"
MESSAGE="$TIMESTAMP - O nó $HOSTNAME_NODE ($NODE_IP) assumiu o estado MASTER para o serviço MySQL HA."
echo "$MESSAGE" | mail -s "$SUBJECT" "$NOTIFICATION_EMAIL"

# Script: /etc/keepalived/scripts/to_backup_mysql.sh
#!/bin/bash
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
HOSTNAME_NODE=$(hostname)
NODE_IP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
NOTIFICATION_EMAIL="seu_email@dominio.com"
SUBJECT="Keepalived: Nó $HOSTNAME_NODE se tornou BACKUP"
MESSAGE="$TIMESTAMP - O nó $HOSTNAME_NODE ($NODE_IP) mudou para o estado BACKUP para o serviço MySQL HA."
echo "$MESSAGE" | mail -s "$SUBJECT" "$NOTIFICATION_EMAIL"

# Script: /etc/keepalived/scripts/to_fault_mysql.sh
#!/bin/bash
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
HOSTNAME_NODE=$(hostname)
NODE_IP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
NOTIFICATION_EMAIL="seu_email@dominio.com"
SUBJECT="Keepalived: Nó $HOSTNAME_NODE em estado de FALHA"
MESSAGE="$TIMESTAMP - O nó $HOSTNAME_NODE ($NODE_IP) entrou em estado de FALHA para o serviço MySQL HA."
echo "$MESSAGE" | mail -s "$SUBJECT" "$NOTIFICATION_EMAIL"

Scripts de Notificação de Status de Servidor Real

Estes scripts são acionados pelas seções real_server quando o status de um servidor real muda.

# Script: /etc/keepalived/scripts/mysql_down_failover.sh
#!/bin/bash
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
HOSTNAME_NODE=$(hostname)
NODE_IP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
NOTIFICATION_EMAIL="seu_email@dominio.com"
SUBJECT="Keepalived ALERTA: Serviço MySQL falhou no $HOSTNAME_NODE"
MESSAGE="$TIMESTAMP - O serviço MySQL no nó $HOSTNAME_NODE ($NODE_IP) está INATIVO. Forçando failover do Keepalived."
echo "$MESSAGE" | mail -s "$SUBJECT" "$NOTIFICATION_EMAIL"
sudo pkill keepalived # Encerra o Keepalived para forçar a transição de estado (failover)

# Script: /etc/keepalived/scripts/mysql_up_alert.sh
#!/bin/bash
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
HOSTNAME_NODE=$(hostname)
NODE_IP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
NOTIFICATION_EMAIL="seu_email@dominio.com"
SUBJECT="Keepalived INFO: Serviço MySQL restaurado no $HOSTNAME_NODE"
MESSAGE="$TIMESTAMP - O serviço MySQL no nó $HOSTNAME_NODE ($NODE_IP) foi RESTAURADO."
echo "$MESSAGE" | mail -s "$SUBJECT" "$NOTIFICATION_EMAIL"

Tags: Keepalived vrrp Alta Disponibilidade Failover Linux

Publicado em 7-20 08:31