Por Daniel Bristot de Oliveira | |
11/08/2006 | |
Dando continuiade ao artigo sobre Balanceamento de carga e redundância para Servidores Web publicado aqui no FUG, este artigo irá abordar três ferramentas muito utilizadas nesta abordagem: A primeira ferramenta é o CARP, o Protocolo de Redundância de Endereço Comum, que surgiu para ser uma alternativa livre a o VRRP, no final da seção do carp(4) ainda é mostrado como funciona o balanceamento de carga em nivel ARP que o carp(4) oferece. Outro assunto muito discutido é o monitoramento de interfaces de rede, isto é, um vigia para fazer alguma ação caso algum evento associado a uma interface aconteça, como executar um script cada vez que uma interface se torne inativa, isto é feito utilizando o port ifstated(8). Ao final, o assunto abordado é a sincronização de tabela de estados de conexões, algo fundamental para fazer a redundância de roteadores e firewalls transparente para os clientes, isto é feito com o auxílio da interface pfsync(4). O CARPO CARP é o substituto para o VRRP, o CARP - Protocolo de Redundância de Endereço Comum (Common Address Redundancy Protocol) - Ele é um protocolo nativo do OpenBSD, e foi portado para o FreeBSD. O CARP surgiu para substituir o VRRP, pois o Protocolo VRRP é um padrão do IETF e é patenteado pela CISCO, com isso o Projeto OpenBSD, seguindo sua ideologia, e como já feito com a criação do PF, pois o IPFilter não era um totalmente livre, criou um padrão livre, o CARP. O Objetivo do CARP é o mesmo do VRRP, garantir a redundância de hosts, fazendo com que vários hosts sejam responsáveis por um único endereço em uma rede, caso um falhe, o outro assume. Porém o CARP age de forma diferente do VRRP, o VRRP cria um endereço virtual vinculado a uma interface de rede, como o criado com o parâmetro "ifconfig_interface_alias0" do rc.conf(5), assim os hosts pertencentes ao mesmo grupo compartilha somente o mesmo IP, desta maneira, cada vez que um host muda de estado, todo o cache ARP da rede deve ser atualizado, Já o CARP trabalha com uma interface virtual, nomeada carpN, onde N é o numero da interface, que se vincula a uma interface real, a interface virtual tem um endereço MAC virtual, e todos os hosts que estão compartilhando o mesmo endereço também, assim quando um host muda de estado, o cache não precisa ser atualizado, pois o novo host mestre irá assumir não somente o endereço de IP mas também o endereço MAC. O problema é que para utilizar o CARP, necessita de no mínimo 3 IPs na mesma rede para funcionar, o que não é necessário no VRRP. Configurando o CARPAgora iremos configurar o CARP, seguindo o nosso esquema do artigo sobre HA. A única alteração é a adição de mais dois endereços de IP nos roteadores, que serão:
Configurando o Sistema OperacionalPara utilizarmos o CARP, devemos adicionar o suporte a interface carp ao kernel, para isto, adicione a seguinte linha ao arquivo de configuração do kernel: device carp Configurando a interface carp(4)Como o carp(4) trabalha com o conceito de interface, ele não possui uma arquivo específico de configuração, pois sua configuração é feita como a de qualquer dispositivo de rede, utilizando o ifconfig. A sintax do ifconfig(8) para os dispositivos carp(4) é: Para criar uma nova interface: ifconfig carpN create Para configurar uma interface é: ifconfig carpN vhid ID [pass senha] [carpdev carpdev] [advbase advbase] [advskew advskew] endereço-ip [ máscara ] OBS: Os campos fora de couchetes são obrigatórios. Explicação das opções:
ExemploComo exemplo iremos configurar os nossos dois roteadores, primeiramente iremos configurar o mestre, que terá as duas interfaces, como mostra a saída do ifconfig(8) abaixo: fxp0: flags=8843 Para nosso exemplo precisaremos de duas interfaces CARP, uma para a fxp0, que terá o endereço 200.18.15.16, e outra para fxp1, que terá o endereço 10.0.70.3. As interfaces no nó mestre terão a prioridade mais alta, para que sejam escolhidas como mestre, então iremos dar a elas o valor mínimo de advskew, já para as interfaces do nó escravo daremos uma prioridade mais baixa, então iremos dar um valor alto de advskew, por exemplo 100. Veremos abaixo como serão criadas as interfaces. Criando as interfaces, Antes de configurarmos as interfaces CARP, devemos cria-las, elas podem ser criadas de duas maneiras, através do console, com o comando ifconfig(8) carpN create, ou na inicialização do sistema, com a opção cloned_interfaces no rc.conf, veremos as duas opçoes abaixo. Criando a partir do console: # ifconfig carp0 create A partir do rc.conf cloned_interfaces="carp0 carp1" Pronto as interfaces já estão criadas, agora vamos configura-las. Aqui também é possível cria-las das duas formas, eu irei colocar apenas o exemplo do host mestre, porém a única diferença entre o mestre e o escravo é o valor de advskew, que no mestre será 1 e no escravo será 100. vamos configurar. Via console: # ifconfig carp0 vhid 1 advskew 1 pass senha1 200.18.15.16 Via rc.conf: ifconfig_carp0="vhid 1 advskew 1 pass senha1 200.18.15.16" Pronto as interfaces estão configuradas. Como o CARP trabalhaO host mestre envia regularmente, via broadcast, anúncios sobre o seu estado, assim os hosts de backup ficam sabendo quem é o host mestre. Se os hosts de backup não ouvirem mais estes anúncios do nó mestre, o host de maior prioridade, ou seja, menor advskew, caso todos estejam utilizando preemptvismo, ou o host que responder primeiro, provavelmente o que tiver menor advbase, caso não estejam utilizando preemptivismo, irá assumir o status de mestre. Estes anúncios são enviados utilizando o protocolo carp(4), e podemos ver os pacotes com o tcpdump(8), com o seguinte comando. # tcpdump proto carp Se você está utilizando um firewall, você deve liberar o trafego para este protocolo, por exemplo com o PF seria: pass out on $carp_dev proto carp keep state Onde $carp_dev deve ser a interface física que o carp(4) está utilizando. Balanceamento de carga com carp(4)Com o carp(4) também é possível fazermos balanceamento de carga, em nível ARP, isto é, o balanceamento será feito com o endereçamento ARP. Como sabemos o host mestre é definido por quem envia os anúncios para rede, então se fizermos isto em dois roteadores: Roteador 1: Uma interface no grupo 1 com advskew baixo Uma interface no grupo 2 com advskew alto Roteador 2: Uma interface no grupo 1 com advskew alto Uma interface no grupo 2 com advskew baixo O que irá acontecer? o mestre do grupo 1 será o Roteador 1 e o mestre do grupo 2 será o roteador 2, e se estes dois grupos utilizassem o mesmo endereço de IP? teriamos dois mestres anunciando, mas aconteceria algo de errado, os dois aceitariam os pacotes, porém para resolver isto, se habilitarmos a sysctl(8) net.inet.carp.arpbalance, os roteadores utilizarão o endereço de IP do cliente para definir se ele aceita o pacote ou descarta, assim, o balanceamento é feito. Veja o exemplo de configuração abaixo: Roteador1 # ifconfig carp0 vhid 1 pass senha 10.0.60.61 Roteador2 # ifconfig carp0 vhid 1 pass senha advskew 10010.0.60.61 Vejamos parte da saída do ifconfig dos dois roteadores. Roteador1 carp0: flags=49 Roteador2 carp0: flags=49 Agora precisamos habilitar a sysctl(8) net.inet.carp.arpbalance nos dois roteadores: # sysctl net.inet.carp.arpbalance=1 O Balanceamento está configurado. Vamos ver a saída do tcpdump(8). # tcpdump proto carp Como podemos ver os dois hosts, 10.0.60.2 e 10.0.60.4, estão anunciado, com priordade 0 e com seus distintos vhid's.
O problema da dependência de interfacesPorém nos surge um problema, se só uma interface de nossos roteadores cair? a outra continuaria UP, e isso quebraria a rede certo? Bom no VRRP nós temos a opção vridsdep, que cria uma dependência entre interfaces, assim, as duas estarão UP, se as duas estiverem UP, caso uma caia, o grupo inteiro cai também. Para resolver este problemas surge o ifstated(8). ifstated(8)O ifstated(8) é um daemon de monitoramento de interfaces, com ele é possível examinar as interfaces e executar ações caso algum evento aconteça, em nosso caso ficaremos examinado as interfaces fxp0 e fxp1. O ifstated está disponível no ports(8) net/ifstated. O arquivo de configuração tem uma sintaxe um pouco confusa no início, mas ele é extremamente poderoso. O arquivo de configuração fica em /usr/local/etc/ifstated.conf . Neste artigo vou apenas dar uma pincelada no ifstated.conf(5), quem tiver maior interesse nele, aconselho a ler o man. ifstated.confEste arquivo de configuração se parece um pouco com programação, então eu farei uma analogia ao C.
A primeira seção é denominada global, onde vão as opções para o início do sistema, ele apenas aceita a configuração de log e o estado inicial(Estado Inicial? espere um pouco que você vai intender). Aquí seria como dizer para o ifstated(8) quem é o void() do programa. A segunda seção é chamada Macros, nela são criadas a variáveis do usuário, em uma analogia, seria as variáveis globais do programa. A terceira e última seção é chamada Definições de estados, em uma analogia, estes estados são como as funções do programa (Agora você intendeu o que era aquele estado inicial), nele são feito testes com variáves, executados comandos. etc.
init-state one
A primeira linha é a seção global, nela apenas definimos que o estado inicial é o estado one. A segunda linha é uma variável, que verifica se a interface fxp1 e a fxp0 estão up, caso estejam, a variável se torna verdadeira, caso uma não esteja, ela se torna falsa. Este teste pode ser feito com qualquer interface, a sintax é Interface.link.Estado, e os estados das interfaces podem ser:
Existem outros testes, que fogem o escopo deste artigo, para maiores informações, leia o man 5 ifstated.conf A terceira linha podemos ver o início de um bloco, isto é um estado, ou como na analogia, uma função. O estado one é o inicial, ele checa: Se a $if_up for falso, isto é se alguma iterface não está ativa, ele aumenta o advskew, através da a opção run executa o comando que lhe foi passado, assim fazendo com que as interface carp que ainda está ativa vá pra o estado de BACKUP. A última linha muda para o estado two, em uma analogia, seria a chamada de uma outra função. O estato two faz o contrário do estado one, as interfaces aquí chegarão como BACKUP, então ele fica checando se: $if_up for verdade, isto é as duas interfaces estiverem ativas, ele diminui os advskew das interfaces carp, assim tornando elas interfaces MESTRE novamente.
net.inet.carp.preempt=1 Executando o ifstatedO ifstated pode ser executado de duas formas, manualmente, executando ifstated, ou durante a inicialização do sistema, pra isto adicione a linha abaixo no /etc/rc.conf: ifstated_enable="YES"
# ifstated -dv -f /home/usuario/ifstated.conf.teste PfsyncUm tema que não abordei na primeira parte do artigo, foi o firewall. Como estes roteadores estarão de frente para a Internet, é fundamental a presensa de um firewall. Bom, como todos podemos ver o firewall ou Packet Filter que mais vem se destacando é o Pacaket Filter do Projeto OpenBSD, ele trás várias vantagens como listas e tabelas, integra várias tecnologias com QoS e NAT, e tem uma sintaxe limpa e clara. Ele surgiu pelo mesmo motivo do CARP, substituir um software protegido por patente e direitos autorais e patente. Neste artigo não abordarei como fazer um firewall, mas sim uma das propriedades mais interessantes dele, o pfsync(4). Neste artigo estamos trabalhando com dois firewalls, um em cada roteador, suponhamos que um cliente está em uma tranzação que está passando pelo nosso roteador, e o nosso roteador cair, bom, o roteador de backup irá assumir o seu lugar, só que irá acontecer um problema, o firewall so backup não irá reconhecer a conexão já existente e irá trancar o cliente. Para resolver esta situação surgiu o pfsync(4). Ele irá sincronizar as tabelas de estados de conexões entre os firewall de uma rede. O pfsync(4) é como o carp(4), uma interface de rede, que é utilizada para enviar e receber, via multicast ou em unicast com o auxílio do ipsec(4), informações sobre estados de conexões. Vamos ver como ela funciona. O sistema operacionalPara utilizarmos os pfsync(4) devemos ter suporte ao PF e a interface pfsyc, para isto adicione as seguintes linhas no arquivo de configuração do seu kernel. device pf Compile e instale o seu kernel. Após reiniciar o seu novo kernel, você verá que aparecerá mais uma interface a saída do ifconfig(8), como no exemplo abaixo. pfsync0: flags=41 Configurando o pfsync(8)Como o pfsync é uma interface virtual, a sua configuração é feita através do ifconfig(8), a sintaxe de configuração é: ifconfig pfsyncN syncdev dispositivo [syncpeer EndereçoDeIp]
O método mais correto e eficiênte de fazer estas atualizações, seria adicionarmos mais um interface aos nossos roteadores, ligar os dois via cabo crossover e configurar o pfsync para estas interfaces, porém nós só estamos utilizando duas interfaces, então iremos utilizar uma delas. A nossa interface fxp1 está em um ambiênte seguro que é nossa rede, então poderemos utiliza-la. Configurando o pfsync(8)Veja o exemplo abaixo: # ifconfig pfsync0 sysncdev fxp1 Nossas interfaces estão conectadas. Como o pfsync(8) funcionaO pfsync envia suas mensagens, em modo multicast utilizando o protocolo pfsync, com o auxílio do tcpdump(8) podemos ver o tráfego dos pacotes co pfsync, como no exemplo abaixo. # tcpdump proto pfsync
pass on $sync_if proto pfsync Onde $sync_if é a interface real que o pfsync está ligado. Considerações FinaisChegou ao fim mais um artigo, este ficou um pouco menor que o artigo Monstro do GEOM, mas espero ter clareado a mente dos leitores sobre a utilização do CARP, do ifstated e do pfsync. Não posso deixar de agradecer ao Projeto OpenBSD por essas duas grandes contribuições. Um Obrigado também ao meu Mestre, ídolo e pai, Angelo de Oliveira. Referências bibliográficas: Failover Firewalls with OpenBSD and CARP. Disponível em: http://www.samag.com/documents/s=9658/sam0505e/ PF: Redundância de Firewall com CARP e pfsync Disponível em: http://www.openbsd.org/faq/pf/pt/carp.html Páginas do Man Até na próxima no fantástico mundo de Bob. |