Quem já foi a um estabelecimento comercial – supermercado, por exemplo – e presenciou uma interrupção momentânea no fornecimento de energia elétrica, presenciou provavelmente um exemplo de alta disponibilidade. Ou seja, a rápida restauração do serviço – fornecimento de energia elétrica – minimizando nesse caso o tempo no escuro. Esse é o conceito. Para se ter alta disponibilidade é preciso redundância – rede elétrica e gerador de energia – e um mecanismo capaz de detectar falhas no fornecimento da rede elétrica e ligar o gerador automaticamente – chave de transferência automática. Dito isso, a proposta desse post é substituindo a energia elétrica por uma página web, a rede elétrica e o gerador de energia por duas placas Raspberry Pi e o mecanismo de detecção de falhas por softwares – Corosync e Pacemaker – criar um conjunto de dois ou mais computadores, um cluster de alta disponibilidade Linux.
Com isso, minimizamos o tempo fora do ar da página web, pois parafraseando um ditado conhecido “quem tem dois tem um, que tem um não tem nenhum”, que poderia ser o slogan de alta disponibilidade e deveria ser a política de quem trabalha com administração de sistemas e infraestrutura de redes.
Material necessário
Para realizar este projeto, vamos precisar de:
- 2 x Raspberry Pi 3 Modelo B+
- 2 x Cartão SD
- 2 x Fonte 5 V
Nos cartões SD é necessário estar gravado o sistema operacional Raspbian, de preferência o Lite. Qualquer dúvida de como isso deve ser feito, você pode consultar este post.
O que são Corosync e Pacemaker?
O Corosync é responsável pela associação, sincronismo e detecção de falhas do membros do cluster de alta disponibilidade Linux – também conhecidos como nodes ou nós, nesse post referidos como nodes. O Pacemaker é um gerenciador de recursos de cluster (cluster resource manager), um sistema que administra recursos – endereço IP e servidor web, por exemplo – disponibilizados pelo cluster.
Configurando Corosync e Pacemaker
Para começar precisamos de algum tipo de acesso ao terminal, seja remoto via ssh ou local via teclado. Tudo certo? Então vamos lá!
A convenção seguida é que [TODOS] indica um comando que precisa ser executado em todas as máquinas do cluster de alta disponibilidade Linux. [NODE1] e [NODE2] indica um comando que precisa ser executado individualmente na respectiva máquina.
É uma boa prática atribuir manualmente o endereço IP dos nodes, para isso vamos editar o arquivo. [TODOS]
vim /etc/dhcpcd.conf
E incluir o conteúdo abaixo no final (fique atento aos comentários). [TODOS]
interface eth0 # SUBSTITUA "192.168.0.1" PELO ENDEREÇO IP DO SEU RASPBERRY PI. static ip_address=192.168.0.1/24 # SUBSTITUA "192.168.0.1" PELO ENDEREÇO IP DO SEU ROTEADOR. static routers=192.168.0.1
Agora vamos instalar os pacotes, nosso cluster será baseado no Corosync e Pacemaker. [TODOS]
apt-get update apt-get install pacemaker corosync crmsh
É uma boa prática fazer uma cópia do arquivo de configuração antes de editá-lo. [TODOS]
cp -p /etc/corosync/corosync.conf /etc/corosync/corosync.conf.default
Agora iremos limpar o conteúdo do arquivo. [TODOS]
echo "" > /etc/corosync/corosync.conf
Editá-lo. [TODOS]
vim /etc/corosync/corosync.conf
E incluir o conteúdo abaixo (fique atento aos comentários!). [TODOS]
totem { # Especifica a versão do arquivo de configuração. # Atualmente, a única versão válida para esta diretiva é 2. version: 2 # Especifica o nome do cluster. cluster_name: pacemaker1 # Quanto tempo antes de declarar um token perdido (ms). token: 3000 # Quantos tokens são retransmitidos antes de formar uma nova configuração. token_retransmits_before_loss_const: 10 # Limita nodeids a 31 bits (números inteiros com sinal positivo). clear_node_high_bit: yes # Usado para autenticação mútua dos nodes. # Necessário criar uma chave compartilhada com "corosync-keygen". # Habilitar crypto_cipher, requer também a habilitação de crypto_hash. crypto_cipher: aes256 crypto_hash: sha1 # Esta diretiva controla o mecanismo de transporte usado. # Unicast (udpu), que requer uma lista de membros na seção nodelist {}. transport: udpu # Define a interface para se comunicar. interface { # O ringnumber deve ser numerado consecutivamente, começando em 0. ringnumber: 0 # Especifica o endereço onde o Corosync deve se vincular. # O bindnetaddr deve ser o endereço IP configurado no sistema ou o endereço de rede. # Por exemplo, se o endereço IP configurado no sistema for 192.168.0.1 com a máscara de # rede 255.255.255.0, você deve definir bindnetaddr como 192.168.0.1 ou 192.168.0.0. # Definindo bindnetaddr como endereço de rede poderemos usar esse mesmo arquivo # de configuração para todos os outros nós do cluster. # SUBSTITUA O ENDEREÇO DE REDE 192.168.0.0 DE ACORDO COM SUA REDE. bindnetaddr: 192.168.0.0 } } logging { # Em caso de dúvida, deixe "off". fileline: off # Em caso de dúvida, deixe "no". to_stderr: no # Em caso de dúvida, deixe "no". to_logfile: no # Em caso de dúvida, deixe "yes". to_syslog: yes # Em caso de dúvida, deixe "daemon". syslog_facility: daemon # Em caso de dúvida, deixe "off". debug: off # Em caso de dúvida, deixe "on". timestamp: on logger_subsys { subsys: QUORUM debug: off } } quorum { # O serviço votequorum faz parte do projeto Corosync. # Esse serviço pode ser opcionalmente carregado nos nodes do cluster Corosync para evitar situações de split-brain. # Isso é feito atribuíndo um número de votos esperados e garantindo que somente com a maioria dos votos # as operações do cluster possam prosseguir. provider: corosync_votequorum # votequorum requer um valor de votos esperados para funcionar, isso pode ser fornecido de duas maneiras. # O número de votos esperados será calculado automaticamente quando a seção nodelist {} estiver presente em # corosync.conf ou quando expected_votes estiver presente na seção de quorum {}. # A falta de ambos desativará o voto. Se ambos estiverem presentes ao mesmo tempo, o valor expected_votes # substituirá o calculado a partir da lista de nodes. expected_votes: 2 # O cluster de dois nodes (two node cluster) é um caso de uso que requer atenção especial. # Com um cluster de dois nodes, cada node com um voto, há dois votos no cluster. # Usando o cálculo da maioria simples (50% dos votos + 1) para calcular o quórum, o quórum seria 2. # Isso significa que os dois nodes sempre precisariam estar ativos para que o cluster operasse. # Ativando two_node: 1, o quorum é definido artificialmente como 1. two_node: 1 } # Dentro da seção nodelist {}, é possível especificar informações sobre os nodes do cluster. nodelist { node { # Especifica o endereço IP do node. # SUBSTITUA O ENDEREÇO IP 192.168.0.1 PELO ENDEREÇO IP DO PRIMEIRO NODE. ring0_addr: 192.168.0.1 } node { # Especifica o endereço IP do node. # SUBSTITUA O ENDEREÇO IP 192.168.0.2 PELO ENDEREÇO IP DO SEGUNDO NODE. ring0_addr: 192.168.0.2 } }
Para garantir a autenticidade e a privacidade das mensagens trocadas entre os nodes do cluster, iremos gerar uma chave privada. [NODE1]
corosync-keygen
Se o resultado for algo parecido com.
Corosync Cluster Engine Authentication key generator. Gathering 1024 bits for key from /dev/random. Press keys on your keyboard to generate entropy. Press keys on your keyboard to generate entropy (bits = 928). Press keys on your keyboard to generate entropy (bits = 1000). Writing corosync key to /etc/corosync/authkey.
Tudo certo, podemos seguir.
Precisamos enviar o arquivo contendo a chave para o outro node do cluster. [NODE1]
Atenção! Não esqueça de substituir o nome de usuário (pi) e o endereço IP (192.168.0.2), caso necessário.
rsync -avz /etc/corosync/authkey [email protected]:/tmp/
Vamos mover o arquivo para o diretório correto. [NODE2]
mv /tmp/authkey /etc/corosync/
Corrigir as permissões. [NODE2]
chown root. /etc/corosync/authkey
E reiniciar os serviços. [TODOS]
systemctl restart corosync systemctl restart pacemaker
Verificando a instalação do Corosync
Primeiro vamos verificar se a comunicação do cluster está funcionando. [TODOS]
corosync-cfgtool -s
Podemos ver que tudo parece normal, o nosso endereço IP listado como o id (não o endereço 127.0.0.1) e sem falhas para o status.
Printing ring status. Local node ID 1217522751 RING ID 0 id = 192.168.0.1 status = ring 0 active with no faults
Em seguida, verificar as APIs de associação e o quórum. [NODE1] ou [NODE2]
corosync-cmapctl | grep members
Se o resultado for algo parecido com.
runtime.totem.pg.mrp.srp.members.1217522751.config_version (u64) = 0 runtime.totem.pg.mrp.srp.members.1217522751.ip (str) = r(0) ip(192.168.0.1) runtime.totem.pg.mrp.srp.members.1217522751.join_count (u32) = 1 runtime.totem.pg.mrp.srp.members.1217522751.status (str) = joined runtime.totem.pg.mrp.srp.members.1217522754.config_version (u64) = 0 runtime.totem.pg.mrp.srp.members.1217522754.ip (str) = r(0) ip(192.168.0.2) runtime.totem.pg.mrp.srp.members.1217522754.join_count (u32) = 1 runtime.totem.pg.mrp.srp.members.1217522754.status (str) = joined
Tudo certo.
Verificando a instalação do Pacemaker
Agora que confirmamos que o Corosync está funcionando, podemos verificar o restante da pilha. [NODE1] ou [NODE2]
crm status
O resultado deve ser algo como.
Stack: corosync Current DC: node2 (version 1.1.16-94ff4df) - partition with quorum Last updated: Mon Jul 29 09:33:22 2019 Last change: Mon Jul 29 09:31:03 2019 by hacluster via crmd on node2 2 nodes configured 0 resources configured Online: [ node1 node2 ] No resources
Antes de fazermos qualquer alteração, é uma boa ideia verificar a validade da configuração do cluster de alta disponibilidade Linux. [NODE1] ou [NODE2]
crm_verify -L -V
Como você pode ver, a ferramenta encontrou alguns erros.
error: unpack_resources: Resource start-up disabled since no STONITH resources have been defined error: unpack_resources: Either configure some or disable STONITH with the stonith-enabled option error: unpack_resources: NOTE: Clusters with shared data need STONITH to ensure data integrity Errors found during check: config not valid
A fim de garantir a segurança de seus dados, fencing (STONITH) é habilitado por padrão.
No entanto, ele também sabe quando nenhuma configuração STONITH foi fornecida e relata isso como um problema.
Desativaremos esse recurso por enquanto. [NODE1] ou [NODE2]
crm configure property stonith-enabled=false
Adicionando recurso – endereço IP
Independentemente de onde os serviços do cluster estão sendo executados, os usuários precisam de um endereço IP consistente para contatá-los. Aqui, vou escolher 192.168.0.10 como o endereço flutuante, dar-lhe o nome de FloatIP e dizer ao cluster para verificar se ele está em execução a cada 10 segundos.
Atenção! Não se esqueça de substituir o endereço IP (192.168.0.10) de acordo com sua rede. O endereço escolhido não deve estar em uso na rede. [NODE1] ou [NODE2]
crm configure primitive FloatIP ocf:heartbeat:IPaddr2 params ip=192.168.0.10 nic=eth0 cidr_netmask=24 op monitor interval=10s
Agora, vamos verificar se o recurso IP foi adicionado. [NODE1] ou [NODE2]
crm status
Como você pode ver, o endereço IP (FloatIP) foi iniciado no node1.
Stack: corosync Current DC: node2 (version 1.1.16-94ff4df) - partition with quorum Last updated: Mon Jul 29 09:38:10 2019 Last change: Mon Jul 29 09:38:02 2019 by root via cibadmin on node1 2 nodes configured 1 resource configured Online: [ node1 node2 ] Full list of resources: FloatIP (ocf::heartbeat:IPaddr2): Started node1
Para verificar, no node onde o endereço IP foi iniciado, nesse exemplo node1.
ip a
Veremos então dois endereços IP: o endereço IP do node e o endereço IP flutuante.
inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.0.10/24 brd 192.168.0.255 scope global secondary eth0 valid_lft forever preferred_lft forever
Adicionando recurso – servidor web
Agora que temos um cluster básico mas funcional, estamos prontos para adicionar um serviço real. Mais especificamente um servidor web, pois além de ser usado em muitos clusters é relativamente simples de configurar.
Nosso servidor web será baseado no Apache, vamos a instalação. [TODOS]
apt-get update apt-get install apache2
Os serviços devem ser gerenciados pelo cluster nunca pelo sistema operacional. Por isso, iremos parar e desativar o serviço do Apache na inicialização do sistema. [TODOS]
systemctl stop apache2 systemctl disable apache2
Precisamos criar uma página para o Apache servir. [TODOS]
cat <<-END >/var/www/html/index.html <html> <body> Site Teste - $(hostname)</body> </html> END
Neste ponto, o Apache está pronto para funcionar e tudo o que precisa ser feito é adicioná-lo ao cluster de alta disponibilidade Linux . Dando-lhe o nome de WebSite e dizendo ao cluster para verificar se ele está em execução a cada 60 segundos. [NODE1] ou [NODE2]
crm configure primitive WebSite ocf:heartbeat:apache params \ configfile=/etc/apache2/apache2.conf \ statusurl="http://localhost/server-status" \ op monitor interval=60s
Após alguns segundos, devemos ver o cluster iniciar o Apache. [NODE1] ou [NODE2]
crm status
O resultado deve ser algo como.
Stack: corosync Current DC: node2 (version 1.1.16-94ff4df) - partition with quorum Last updated: Mon Jul 29 10:46:55 2019 Last change: Mon Jul 29 10:46:35 2019 by root via cibadmin on node1 2 nodes configured 2 resources configured Online: [ node1 node2 ] Full list of resources: FloatIP (ocf::heartbeat:IPaddr2): Started node1 WebSite (ocf::heartbeat:apache): Started node2
Espere um momento, o servidor web (WebSite) não está sendo executado no mesmo node que o endereço IP (FloatIP)!
Por otimização, o Pacemaker geralmente distribuirá os recursos entre os nodes do cluster. No entanto, podemos dizer ao cluster que dois recursos estão relacionados e precisam ser executados no mesmo node. Vamos informar o cluster que o WebSite deve executar apenas no node em que o FloatIP está ativo. [NODE1] ou [NODE2]
crm configure colocation WebSite-with-FloatIP inf: WebSite FloatIP
E verificar se a alteração ocorreu com sucesso. [NODE1] ou [NODE2]
crm status
O resultado deve ser algo como.
Stack: corosync Current DC: node2 (version 1.1.16-94ff4df) - partition with quorum Last updated: Mon Jul 29 10:49:52 2019 Last change: Mon Jul 29 10:49:41 2019 by root via cibadmin on node1 2 nodes configured 2 resources configured Online: [ node1 node2 ] Full list of resources: FloatIP (ocf::heartbeat:IPaddr2): Started node1 WebSite (ocf::heartbeat:apache): Started node1
Para ter certeza de que nossa página responda independentemente da configuração de endereço do Apache, precisamos fazer com que o FloatIP seja iniciado antes do WebSite. [NODE1] ou [NODE2]
crm configure order FloatIP-before-WebSite inf: FloatIP WebSite
Para verificar se a alteração ocorreu com sucesso. [NODE1] ou [NODE2]
crm configure show
Aqui podemos ver toda configuração que fizemos até agora.
node 1217522751: node1 node 1217522754: node2 primitive FloatIP IPaddr2 \ params ip=192.168.0.10 nic=eth0 cidr_netmask=24 \ op monitor interval=10s primitive WebSite apache \ params configfile="/etc/apache2/apache2.conf" statusurl="http://localhost/server-status" \ op monitor interval=60s order FloatIP-before-WebSite inf: FloatIP WebSite colocation WebSite-with-FloatIP inf: WebSite FloatIP property cib-bootstrap-options: \ have-watchdog=false \ dc-version=1.1.16-94ff4df \ cluster-infrastructure=corosync \ cluster-name=debian \ stonith-enabled=false
Testando o cluster de alta disponibilidade linux
Em primeiro lugar, localize o node onde o endereço IP flutuante (FloatIP) e a página web (WebSite) estão sendo executados. [NODE1] ou [NODE2]
crm status
Nesse exemplo, node1.
Stack: corosync Current DC: node2 (version 1.1.16-94ff4df) - partition with quorum Last updated: Mon Jul 29 11:35:09 2019 Last change: Mon Jul 29 10:53:09 2019 by root via cibadmin on node1 2 nodes configured 2 resources configured Online: [ node1 node2 ] Full list of resources: FloatIP (ocf::heartbeat:IPaddr2): Started node1 WebSite (ocf::heartbeat:apache): Started node1
Agora abra um navegador e digite o endereço IP flutuante, no meu caso 192.168.0.10.
Confirmando o cluster (crm status), no momento a página web está sendo servida pelo node1.
Legal, agora vamos simular uma falha no node1 e ver o que acontece. [NODE1]
crm cluster stop
Localize novamente o node onde o endereço IP flutuante (FloatIP) e a página web (WebSite) estão sendo executados. [NODE2]
crm status
Agora estão no node2, inclusive podemos ver que o node1 está offline (na visão do cluster).
Stack: corosync Current DC: node2 (version 1.1.16-94ff4df) - partition with quorum Last updated: Mon Jul 29 12:08:33 2019 Last change: Mon Jul 29 10:53:09 2019 by root via cibadmin on node1 2 nodes configured 2 resources configured Online: [ node2 ] OFFLINE: [ node1 ] Full list of resources: FloatIP (ocf::heartbeat:IPaddr2): Started node2 WebSite (ocf::heartbeat:apache): Started node2
Abra um navegador e digite o endereço IP flutuante, no meu caso 192.168.0.10.
Mesmo com o node1 offline a página web continua disponível, mas agora servida pelo node2.
Não se esqueça de iniciar o cluster novamente após os testes. [NODE1]
crm cluster start
Esse é um assunto interessante e extenso, mas com certeza é um bom começo.
Gostou de criar um cluster de alta disponibilidade linux com Raspberry Pi? Ajude-nos a melhorar o blog comentando abaixo sobre este tutorial.
Até a próxima!!