DRBD + OCFS2 + Haproxy + Keepalived + Debian Squeeze

E ai galera, aqui vou estar apresentando uma solução de Alta disponibilidade com balanceamento de carga para servidores Apache, porém pode ser utilizado para outros tipos de serviço, nessa solução vou estar utilizando o DRBD + OCFS2 para garantir a disponibilidade dos dados entre os servidores Apache, vou estar utilizando o Haproxy que vai fazer o balanceamento da Carga, ele tem uma fácil configuração e tem uma interface web para acompanhamento de estatísticas, o Keepalived é um framework escrito em C, que fica monitorando o pool do LVS, o LVS é o responsável pelo balanceamento de carga, com isso caso um dos servidores do pool acabe caindo ele toma à ação de remover do pool para não ter conflito na resposta para o cliente.

O que vou utilizar de máquinas:

Vamos utilizar no mínimo 4 máquinas nesta solução, pois teremos 2 balancer para garantir a disponibilidade do balanceamento de carga, teremos 2 servidores apache para os dados, aqui vou utilizar o algoritmo round robin que distribui as requisições iguais entre os 2 servidores.

  1. Nodo1 do Balancer nome: debian1
  2. Ip Real: 10.101.0.20
  3. Ip Compartilhado: 10.101.0.30
  1. Nodo2 do Balancer nome: debian2
  2. Ip Real: 10.101.0.21
  3. Ip compartilhado: 10.101.0.30
  1. Nodo1 do Apache: debian3
  2. Ip Real: 10.101.0.22
  3. Partição utilizada: /dev/sdb1 dispositivo com 8 GB
  4. Ip para DRBD: 172.19.0.22
  1. Nodo2 do Apache : debian4
  2. Ip Real: 10.101.0.23
  3. Partição utilizada: /dev/sdb1 dispositivo com 8 GB
  4. Ip para DRBD: 172.19.0.23

Aqui nos servidores que vão ter o apache, vou utilizar 2 faixas de ip, uma delas está na DMZ que seria a nossa VLAN da DMZ e a outra está na rede de dados, que poderia ser a VLAN de SCSI.

Por que utilizar dessa forma ?

Aqui vamos separar, o tráfego, pois quanto maior for o compartilhamento de dados entre os DRBD, maior vai ser o nosso fluxo na rede, com isso vamos deixar em uma VLAN que é dedicada para dados para não complicar o resto da nossa rede.

Prepare o seu sistema com o seguinte script http://wiki.douglasqsantos.com.br/doku.php/confinicialsqueeze_en para que não falte nenhum pacote ou configuração.

Configuração inicial dos servidores Apache

Vamos começar a configuração dos servidores do Apache, que é um pouco mais trabalhosa.

Vamos atualizar e fazer um upgrade do sistema nas duas maquinas

aptitude update && aptitude dist-upgrade -y

Vamos acertar o /etc/hosts deixe como abaixo nos dois nodos do Apache.

vim /etc/hosts
127.0.0.1       localhost
10.101.0.22       debian3.douglasqsantos.com.br    debian3
10.101.0.23       debian4.douglasqsantos.com.br    debian4

Agora vamos instalar o drbd e o ocfs2 faça isso nos dois nodos do Apache.

aptitude install drbd8-utils  ocfs2-tools ocfs2-tools-dev -y

Agora vamos carregar os módulos faça isso nos dois nodos do Apache.

modprobe cn
modprobe drbd

Configuração do DRBD

Deixe o arquivo como abaixo nos dois nodos do Apache.

vim /etc/drbd.conf
include "drbd.d/global_common.conf";
#include "drbd.d/*.res";

Execute nas duas maquinas a parte abaixo.

Vamos fazer backup do arquivo de configuração original

cp /etc/drbd.d/global_common.conf{,.bkp}

Deixe o arquivo como abaixo

vim /etc/drbd.d/global_common.conf
#/etc/drbd.conf
# Opções Globais
# Geralmente no início do arquivo. Poucas opções são definidas nesta seção.
#
global {
 usage-count yes; # Gerar status da atualização do sistema de DRBD.
}
#
# Opções comuns a mais de um recurso, quando houver. No caso de existir opções
# definidas internamente ao recurso, elas irão sobrepor as opções comuns.
common {
 protocol C; # Método de replicação. Neste caso, replicação síncrona.
}
###  ocfs2 usando 02 primários
resource r1 {
 net {
 # Permitir/habilitar dois servidores primários.
 allow-two-primaries; #Permite habilitar dois servidores primários
 #Descarta o último disco que se tornar primário em caso da quebra de 
 #consistência, quando os dois discos estiverem como secundários
 after-sb-0pri discard-younger-primary;
 #Entrar em consenso para descartar um disco após quebra de consistência
 #quando houver um disco primário. Geralmente é resolvido na opção anterior,
 #Caso contrário, irá desconectar os dois discos
 after-sb-1pri consensus;
 #Desconectar em caso de quebra de consistência quando houver dois discos primários
 after-sb-2pri disconnect;
}
 startup {
 # Iniciar os dois servidores como primários, por padrão.
 become-primary-on both;
 # Espera 20 segundos pelo segundo nodo caso ele não suba podemos subir somente 1.
 wfc-timeout 20;
 }
 syncer {
 rate 600M; #Para placas de rede de 10/100 utilizar 10M
 }

 on debian3 {
 device     /dev/drbd1; # Nome do dispositivo de DRBD
 disk       /dev/sdb1; # Dispositivo de baixo nível utilizado a partição
 address    172.19.0.22:7789;  # IP:porta de conexão
 meta-disk internal; # Armazenamento das informações de dados é feito
 # dentro do dispositivo de baixo nível.
 }
 on debian4 {
 device   /dev/drbd1;
 disk      /dev/sdb1;
 address   172.19.0.23:7789;
 meta-disk internal;
 }
}

Agora vamos preparar o disco, faça isso nos dois nodos do Apache.

fdisk /dev/sdb
O dispositivo não contém nem uma tabela de partições DOS válida nem um rótulo de disco Sun, OSF ou SGI
Building a new DOS disklabel with disk identifier 0x6aadf3ff.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Aviso: a opção inválida 0x0000 da tabela de partições 4 será corrigida por gravação (w)

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
 switch off the mode (command 'c') and change display units to
 sectors (command 'u').

Comando (m para ajuda): p

Disk /dev/sdb: 8589 MB, 8589934592 bytes
255 heads, 63 sectors/track, 1044 cylinders
Units = cilindros of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x6aadf3ff

Dispositivo Boot      Start         End      Blocks   Id  System

Comando (m para ajuda): n
Comando - ação
 e   estendida
 p   partição primária (1-4)
p
Número da partição (1-4): 1
Primeiro cilindro (1-1044, default 1): ENTER
Using default value 1
Last cilindro, +cilindros or +size{K,M,G} (1-1044, default 1044): ENTER
Using default value 1044

Comando (m para ajuda): w
A tabela de partições foi alterada!

Chamando ioctl() para reler tabela de partições.
Sincronizando discos.

Agora vamos zerar as partições tem que ser executado nos dois nodos do Apáche.

dd if=/dev/zero of=/dev/sdb1 bs=1M count=128

Execute este comando nos dois nodos do Apache antes de passar para o próximo comando.

drbdadm -- --discard-my-data connect r1
 --=====  Thank you for participating in the global usage survey  =====--
The server's response is:

you are the 6260th user to install this version

Onde r1 é o nome do nosso dispositivo, que no arquivo de configuração do drbd está como resource r1.

Execute este comando nos dois nodos do Apache antes de passar para o próximo comando.

drbdadm create-md r1
Writing meta data...
initializing activity log
NOT initialized bitmap
New drbd meta data block successfully created.
success

Execute este comando nos dois nodos do Apache antes de passar para o próximo comando.

drbdadm attach r1

Execute este comando nos dois nodos do Apache antes de passar para o próximo comando.

drbdadm connect r1

Pronto, agora podemos iniciar o drbd, inicie-o nos dois nodos do Apache com o seguinte comando:

/etc/init.d/drbd start
Starting DRBD resources:[ s(r1) ]1: State change failed: (-2) Refusing to be Primary without at least one UpToDate disk
Command '/sbin/drbdsetup 1 primary' terminated with exit code 17
1: State change failed: (-2) Refusing to be Primary without at least one UpToDate disk
Command '/sbin/drbdsetup 1 primary' terminated with exit code 17
1: State change failed: (-2) Refusing to be Primary without at least one UpToDate disk
Command '/sbin/drbdsetup 1 primary' terminated with exit code 17
1: State change failed: (-2) Refusing to be Primary without at least one UpToDate disk
Command '/sbin/drbdsetup 1 primary' terminated with exit code 17
1: State change failed: (-2) Refusing to be Primary without at least one UpToDate disk
Command '/sbin/drbdsetup 1 primary' terminated with exit code 17

Podemos observar como está a situação do nosso dispositivo drbd com o seguinte comando.

cat /proc/drbd
version: 8.3.7 (api:88/proto:86-91)
srcversion: EE47D8BF18AC166BE219757 

 1: cs:Connected ro:Secondary/Secondary ds:Inconsistent/Inconsistent C r----
 ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:8385604

Se em “Connected st” estiver como !Primary/Primary, está tudo ok, porém se estiver como !Secondary/Secondary temos que forçar os dispositivos a passarem para primary e temos mais uma situação quanto ao dispositivo Unknown, normalmente é quando um dos servidores não está operante por problemas de rede ou de configuração do arquivo do drbd. Então muita atenção a esses detalhes.

Vamos levar em consideração que só estamos com o problema que os dois servidores estão como secondary, resolvemos com o seguinte comando. Este comando tem que ser rodado nos dois servidores.

drbdadm -- --overwrite-data-of-peer primary r1

Agora vamos monitorar novamente.

cat /proc/drbd
version: 8.3.7 (api:88/proto:86-91)
srcversion: EE47D8BF18AC166BE219757

 1: cs:SyncTarget ro:Primary/Primary ds:Inconsistent/UpToDate C r----
 ns:0 nr:1368684 dw:1368672 dr:12 al:0 bm:83 lo:1 pe:10097 ua:0 ap:1 ep:1 wo:b oos:7016932
 [=====>.................] sync'ed: 16.4% (6852/8188)M
 finish: 0:01:04 speed: 109,344 (97,760) K/sec

Agora é só esperar eles sincronizarem os dados, isso depende da placa de rede, da velocidade do disco e do tamanho do disco, fora os processos do drbd, se você notar muita lentidão em algum desses fatores, veja se não é bom fazer algum upgrade.

Para acompanhar a sincronização pode utilizar o seguinte comando:

watch cat /proc/drbd
Every 2,0s: cat /proc/drbd                              Mon May  7 11:20:16 2012

version: 8.3.7 (api:88/proto:86-91)
srcversion: EE47D8BF18AC166BE219757

 1: cs:SyncTarget ro:Primary/Primary ds:Inconsistent/UpToDate C r----
    ns:0 nr:4177692 dw:4176928 dr:80 al:0 bm:254 lo:24 pe:16500 ua:23 ap:1 ep:1
wo:b oos:4208676
        [====================>...........] sync'ed: 49.9% (4108/8188)M
        finish: 0:00:47 speed: 89,128 (90,800) K/sec

Agora depois de sincronizados

cat /proc/drbd
version: 8.3.7 (api:88/proto:86-91)
srcversion: EE47D8BF18AC166BE219757

 1: cs:Connected ro:Primary/Primary ds:UpToDate/UpToDate C r----
 ns:8385660 nr:0 dw:0 dr:8385860 al:0 bm:512 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:0

Configurando o OCFS2

Vamos configurar o cluster para o ocfs2. Tem que ser configurado nos dois nodos do Apache.

vim /etc/ocfs2/cluster.conf

node:
 ip_port = 7777
 ip_address = 172.19.0.22
 number = 0
 name = debian3
 cluster = ocfs2

node:
 ip_port = 7777
 ip_address = 172.19.0.23
 number = 1
 name = debian4
 cluster = ocfs2

cluster:
 node_count = 2
 name = ocfs2

Agora vamos configurar o o2cb tem que ser configurado nos dois nodos do Apache.

vim /etc/default/o2cb
[...]
O2CB_ENABLED=true

Agora é so restartar o serviço nos dois nodos do Apache.

/etc/init.d/o2cb restart
ls: cannot access /config: No such file or directory
Loading filesystem "configfs": OK
Mounting configfs filesystem at /sys/kernel/config: OK
Loading stack plugin "o2cb": OK
Loading filesystem "ocfs2_dlmfs": OK
Creating directory '/dlm': OK
Mounting ocfs2_dlmfs filesystem at /dlm: OK
Setting cluster stack "o2cb": OK
Starting O2CB cluster ocfs2: OK
/etc/init.d/ocfs2 restart
Stopping Oracle Cluster File System (OCFS2) OK

Agora é so criar o sistema de arquivos ocfs2 no drbd, precimos fazer isso somente em um dos dois nodos do Apache

Opções: -C (indicado acima de 128K para grandes arquivos) -b (indicado 4K) -N qtd de nodos -L label para o a partição

mkfs.ocfs2 -b 4K -C 128K -N 2 -L ocfs2 /dev/drbd1
mkfs.ocfs2 1.4.4
Cluster stack: classic o2cb
Label:
Features: sparse backup-super unwritten inline-data strict-journal-super
Block size: 4096 (12 bits)
Cluster size: 4096 (12 bits)
Volume size: 8586858496 (2096401 clusters) (2096401 blocks)
Cluster groups: 65 (tail covers 32017 clusters, rest cover 32256 clusters)
Extent allocator size: 4194304 (1 groups)
Journal size: 67108864
Node slots: 4
Creating bitmaps: done
Initializing superblock: done
Writing system files:
done
Writing superblock: done
Writing backup superblock: 2 block(s)
Formatting Journals: done
Growing extent allocator: done
Formatting slot map: done
Writing lost+found: done
mkfs.ocfs2 successful

Agora é so montar a partição

Vamos criar um diretório para o OCFS2 nos dois nodos do Apache e vamos montar.

mkdir /ocfs2 
mount.ocfs2 /dev/drbd1 /ocfs2/ 

Vamos agora verificar as nossas partições

df -Th
Sist. Arq.    Tipo    Size  Used Avail Use% Montado em
/dev/sda1     ext3    323M  147M  160M  48% /
tmpfs        tmpfs    249M     0  249M   0% /lib/init/rw
udev         tmpfs    244M  168K  244M   1% /dev
tmpfs        tmpfs    249M     0  249M   0% /dev/shm
/dev/sda9     ext3    2,8G   69M  2,6G   3% /home
/dev/sda8     ext3    234M  6,1M  216M   3% /tmp
/dev/sda5     ext3    2,8G  639M  2,0G  24% /usr
/dev/sda6     ext3    1,4G  273M  1,1G  21% /var
/dev/drbd1   ocfs2    8,0G  279M  7,8G   4% /ocfs2

Como podemos ver temos a nossa partição montada com ocfs2

Agora podemos deixar isso na inicialização do sistema

vim /etc/fstab
[...]
/dev/drbd1 /ocfs2 ocfs2 _netdev,defaults 0 0

Agora vamos ajustar a ordem de inicialização dos serviços no dois servidores

Agora temos que acertar o o2cb nos dois nodos do apache, o cabeçalho tem que ficar como abaixo, por que nas ultimas versões o drbd não ta funcionando corretamente no runlevel S

vim /etc/init.d/o2cb
#!/bin/bash
# init fragment for O2CB.
#
# chkconfig: 2345 24 20
# description: Load O2CB cluster services at system boot.
#
### BEGIN INIT INFO
# Provides: o2cb
# Required-Start: $local_fs $network $syslog drbd
# Required-Stop:  $local_fs $network $syslog drbd
# Should-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Load O2CB cluster services at system boot.
# Description: Load O2CB cluster services at system boot.
### END INIT INFO

Agora temos que acertar o ocfs2 nos dois nodos do apache, o cabeçalho tem que ficar como abaixo, por que nas ultimas versões o drbd não ta funcionando corretamente no runlevel S

vim /etc/init.d/ocfs2
#! /bin/bash
# Copyright (c) 2005 Oracle
# All rights reserved.
#
# chkconfig: 2345 25 19
# description: Mount OCFS2 volumes at boot.
#
### BEGIN INIT INFO
# Provides: ocfs2
# Required-Start: $local_fs $network $syslog o2cb
# Required-Stop: $local_fs $network $syslog o2cb
# X-UnitedLinux-Should-Start:
# X-UnitedLinux-Should-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Mount OCFS2 volumes at boot.
# Description:  Mount OCFS2 volumes at boot.
### END INIT INFO

Agora temos que recarregar as configuração de inicialização dos serviços

Vamos tirar os serviços da inicialização primeiro

insserv -r -v ocfs2
insserv -r -v o2cb
insserv -r -v drbd

Agora vamos colocar eles na inicialização novamente

insserv -f -v drbd
insserv -f -v o2cb
insserv -f -v ocfs2

Agora vamos reiniciar os dois nodos do Apache para testarmos se vai ser montado o drbd na inicialização

init 6

Depois da inicialização nodo1 do Apache

uptime
 15:22:11 up 0 min,  1 user,  load average: 0.26, 0.07, 0.02
df -Th
Sist. Arq.    Tipo    Size  Used Avail Use% Montado em
/dev/sda1     ext3    323M  147M  160M  48% /
tmpfs        tmpfs    249M     0  249M   0% /lib/init/rw
udev         tmpfs    244M  168K  244M   1% /dev
tmpfs        tmpfs    249M     0  249M   0% /dev/shm
/dev/sda9     ext3    2,8G   69M  2,6G   3% /home
/dev/sda8     ext3    234M  6,1M  216M   3% /tmp
/dev/sda5     ext3    2,8G  639M  2,0G  24% /usr
/dev/sda6     ext3    1,4G  273M  1,1G  21% /var
/dev/drbd1   ocfs2    8,0G  151M  7,9G   2% /ocfs2

Depois da inicialização nodo2 do Apache

uptime
15:22:13 up 0 min,  1 user,  load average: 0.21, 0.12, 0.04
df -Th
Sist. Arq.    Tipo    Size  Used Avail Use% Montado em
/dev/sda1     ext3    323M  147M  160M  48% /
tmpfs        tmpfs    249M     0  249M   0% /lib/init/rw
udev         tmpfs    244M  168K  244M   1% /dev
tmpfs        tmpfs    249M     0  249M   0% /dev/shm
/dev/sda9     ext3    2,8G   69M  2,6G   3% /home
/dev/sda8     ext3    234M  6,1M  216M   3% /tmp
/dev/sda5     ext3    2,8G  639M  2,0G  24% /usr
/dev/sda6     ext3    1,4G  273M  1,1G  21% /var
/dev/drbd1   ocfs2    8,0G  151M  7,9G   2% /ocfs2

Caso de algum problema na inicialização como um dos dois nodos do Apache não ficar como primary temos podemos resolver da seguinte maneira

Primeiro vamos mandar desmontar as partições montadas com o ocfs2 nos dois nodos do Apache

umount /ocfs2

Agora vamos mandar reiniciar o drbd nos dois nodos do Apache

/etc/init.d/drbd restart

Agora vamos forçar a utilização dos dois nodos do Apache

drbdadm -- --overwrite-data-of-peer primary r1

Agora é so remontar as partições novamente nos dois nodos do Apache

mount.ocfs2 /dev/drbd1 /ocfs2/

Erros de sincronismo

Exemplo de erro de sincronismo dos discos, aonde perdemos a consistencia dos dados, com isso vamos precisar acertar este erro.

cat /proc/drbd 
version: 8.3.7 (api:88/proto:86-91)
srcversion: EE47D8BF18AC166BE219757 

 1: cs:StandAlone ro:Secondary/Unknown ds:Outdated/DUnknown   r----
    ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:258100

No nodo2 vamos mandar ele desconsiderar os dados que ele já tem e resincronizar com o nodo1 do Apache

drbdadm -- --discard-my-data connect r1

Agora vamos verificar a sincronismo.

cat /proc/drbd 
version: 8.3.7 (api:88/proto:86-91)
srcversion: EE47D8BF18AC166BE219757 

 1: cs:SyncTarget ro:Secondary/Primary ds:Inconsistent/UpToDate C r----
    ns:0 nr:293128 dw:287336 dr:0 al:0 bm:19 lo:1448 pe:35179 ua:1448 ap:0 ep:1 wo:b oos:207647312
  [>....................] sync'ed:  0.2% (202780/203060)M
  finish: 1:00:10 speed: 57,464 (57,464) K/sec

Assim que terminar este processo precisamos somente forçar os dois como primary da seguinte forma

drbdadm -- --overwrite-data-of-peer primary r1

O discos ainda sincronizando e forçados como primary.

cat /proc/drbd 
version: 8.3.7 (api:88/proto:86-91)
srcversion: EE47D8BF18AC166BE219757 

 1: cs:SyncSource ro:Primary/Primary ds:UpToDate/Inconsistent C r----
    ns:22204456 nr:0 dw:0 dr:22211888 al:0 bm:1356 lo:40 pe:1833 ua:1797 ap:0 ep:1 wo:b oos:185737536
  [=>..................] sync'ed: 10.7% (181384/203060)M
  finish: 0:55:40 speed: 55,560 (47,940) K/sec

Agora vamos instalar o Apache e acertar a configuração básica dele, vamos primeiro configurar o nodo1 do Apache

Configuração do Apache no apache1

aptitude install apache2 apache2-utils -y

Vamos desabilitar o site default no nodo1 do Apache

a2dissite 000-default

Agora vamos criar um virtualHost para teste no nodo1 do Apache

vim /etc/apache2/sites-available/nodo1
<VirtualHost *:80>

 #Nome do do site
 ServerName apache1.douglasqsantos.com.br

 #Apelido para o site
 ServerAlias apache1.douglasqsantos.com.br
 
 #Localização dos arquivos do Site apache1
 DocumentRoot "/var/www/website/frontend/"

 #Controle de acesso ao diretório Raiz do Apache
 <Directory "/var/www/website/frontend/">
 Options -Indexes FollowSymLinks MultiViews
 AllowOverride All
 Order allow,deny
 allow from all
 </Directory>

 #Alias para o cgi-bin do site apache1 
 ScriptAlias /cgi-bin/ "/var/www/website/frontend/cgi-bin/"

 #Controle de acesso e execução do diretorio cgi-bin do site
 <Directory "/var/www/website/frontend/cgi-bin/">
 AllowOverride All
 Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
 Order allow,deny
 Allow from all
 </Directory>

 #Vamos acertar o Formato do Log para que não seja gerado log dos acessos dos balancer e sim dos clientes.
 LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

 #Agora criar uma regra para negar a geração de logs para o arquivo de checagem que o balancer vai utilizar.
 SetEnvIf Request_URI "^/.check\.txt$" dontlog

 #Localização dos logs de Erro do site.
 ErrorLog "/var/www/website/logs/apache1.douglasqsantos.com.br-error.log"

 #Negando os logs de checagem do balancer
 CustomLog "/var/www/website/logs/apache1.douglasqsantos.com.br-access.log" combined env=!dontlog
 
 #Para a segurança do servidor vamos tirar a assinatura do Apache
 ServerSignature Off
  
 #Tipos de log que o apache vai gerar 
 LogLevel info
</VirtualHost>

Agora vamos criar os diretório necessários para o Apache.

mkdir -p /var/www/website/frontend/cgi-bin/
mkdir -p /var/www/website/logs/

Agora vamos acertar as permissões de acesso ao site

chown -R www-data:www-data /var/www/website 

Agora vamos criar o arquivo de checagem do balancer na raiz do site.

touch /var/www/website/frontend/.check.txt

Vamos criar um arquivo de index para identificarmos qual site estamos acessando

echo "<h1>Debian3</h1>" > /var/www/website/frontend/index.html

Agora vamos habilitar o nosso site no Apache

a2ensite nodo1

Agora vamos reiniciar o apache do nodo1 do Apache.

/etc/init.d/apache2 restart

Configuração do Apache no apache2

aptitude install apache2 apache2-utils -y

Vamos desabilitar o site default no nodo1 do Apache

a2dissite 000-default

Agora vamos criar um virtualHost para teste no nodo1 do Apache

vim /etc/apache2/sites-available/nodo2
<VirtualHost *:80>

 #Nome do do site
 ServerName apache2.douglasqsantos.com.br

 #Apelido para o site
 ServerAlias apache2.douglasqsantos.com.br
 
 #Localização dos arquivos do Site apache1
 DocumentRoot "/var/www/website/frontend/"

 #Controle de acesso ao diretório Raiz do Apache
 <Directory "/var/www/website/frontend/">
 Options -Indexes FollowSymLinks MultiViews
 AllowOverride All
 Order allow,deny
 allow from all
 </Directory>

 #Alias para o cgi-bin do site apache1 
 ScriptAlias /cgi-bin/ "/var/www/website/frontend/cgi-bin/"

 #Controle de acesso e execução do diretorio cgi-bin do site
 <Directory "/var/www/website/frontend/cgi-bin/">
 AllowOverride All
 Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
 Order allow,deny
 Allow from all
 </Directory>

 #Vamos acertar o Formato do Log para que não seja gerado log dos acessos dos balancer e sim dos clientes.
 LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

 #Agora criar uma regra para negar a geração de logs para o arquivo de checagem que o balancer vai utilizar.
 SetEnvIf Request_URI "^/.check\.txt$" dontlog

 #Localização dos logs de Erro do site.
 ErrorLog "/var/www/website/logs/apache2.douglasqsantos.com.br-error.log"

 #Negando os logs de checagem do balancer
 CustomLog "/var/www/website/logs/apache2.douglasqsantos.com.br-access.log" combined env=!dontlog
 
 #Para a segurança do servidor vamos tirar a assinatura do Apache
 ServerSignature Off
  
 #Tipos de log que o apache vai gerar 
 LogLevel info
</VirtualHost>

Agora vamos criar os diretório necessários para o Apache.

mkdir -p /var/www/website/frontend/cgi-bin/
mkdir -p /var/www/website/logs/

Agora vamos acertar as permissões de acesso ao site

chown -R www-data:www-data /var/www/website 

Agora vamos criar o arquivo de checagem do balancer na raiz do site.

touch /var/www/website/frontend/.check.txt

Vamos criar um arquivo de index para identificarmos qual site estamos acessando

echo "<h1>Debian4</h1>" > /var/www/website/frontend/index.html

Agora vamos habilitar o nosso site no Apache

a2ensite nodo2

Agora vamos reiniciar o apache do nodo2 do Apache.

/etc/init.d/apache2 restart

Configuração do Balancer1

Vamos mandar atualizar os repositórios e fazer um upgrade do sistema

aptitude update && aptitude dist-upgrade -y

Vamos instalar o haproxy nele.

apt-get install haproxy

Agora vamos fazer backup do arquivo de configuração do haproxy no nodo1 do balancer, neste arquivo temos alguns exeplos de configuração do haproxy.

cp /etc/haproxy/haproxy.cfg{,.bkp}

Vamos zerar o arquivo de configuração do haproxy

cat /dev/null > /etc/haproxy/haproxy.cfg

Agora vamos criar o novo arquivo de configuração para a nossa solução.

vim /etc/haproxy/haproxy.cfg
global
        #definição de logs gerados pelo haproxy
        #endereço do servidor de log, categoria do syslog, prioridade
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        #número máximo de conexões simultaneas para todos os clusters neste servidor,
        #se ultrapassar este valor o haproxy para de aceitar conexões, para todos os clusters
        maxconn 4096
        #Habilita o debug, e desabilita o trabalho do haproxy em background,
        #para mostrar as mensagems de iniciliazação.
        #debug
        #Não mostra mensagem durante a inicialização do haproxy
        #quiet
        #usuário que o haproxy vai ser executado
        user haproxy
        #grupo que o haproxy vai ser executado
        group haproxy
        #O haproxy vai ser executado em segundo plano no sistema.
        daemon

#Definido o tipo de proxy que sera utilizado
defaults
        #utiliza a configuração de log da seção global.
        log     global
        #Temos 3 modos de operação tcp trabalha como tcp padrão modo full-duplex,
        #http qualquer pedido que não é compatível com RFC serão rejeitadas
        #health  este modo só vai responder "OK" para conexões de entrada e fechar a conexão. Nada será logado
        mode    http
        #Ativa o log de solicitação HTTP de estado de sessão, e temporizadores.
        option  httplog
        #Não gerar logs de conexões aonde nenhum dado foi transferido.
        option  dontlognull
        #Número de tentativas para executar em um servidor após uma falha de conexão.
        retries 3
        #Ativa a redistribuição da sessão em caso de falha de conexão.
        option redispatch
        #Tempo limite de verificação adicional, mas apenas depois que uma conexão já foi estabilecida
        timeout check 5000
        #Tempo limite de inatividade máxima no lado do cliente.
        timeout client 50000
        #Tempo limite de inatividade máxima no lado do servidor
        timeout server 50000
        #Tempo máximo de espera para uma tentativa de conexão a um servidor para sucesso.
        timeout connect 2000
        
#Definição do ip e porta que vai responder o cluster
listen clusterapache 10.101.0.30:80
       #número máximo de conexões simultaneas, se ultrapassar este valor o clusterapache,
       #para de responder novas conexões.
       maxconn 1000
       #Temos 3 modos de operação tcp trabalha como tcp padrão modo full-duplex,
       #http qualquer pedido que não é compatível com RFC serão rejeitadas
       #health  este modo só vai responder "OK" para conexões de entrada e fechar a conexão. Nada será logado
       mode http
       #libera acesso a pagina de estatísticas do haproxy
       stats enable
       #usuário e senha da página de estatísticas do haproxy
       stats auth user1:senha
       #Quantidade de conexões simultâneas ao relatório de estdrão é 1maxconn 5
       #algoritmo de balanceamento
       balance roundrobin
       #Modo analisador de URL padrão, com isso o haproxy vai procurar o cookie em 10.101.0.30/.check.txt
       cookie JSESSIONID prefix
       #Trabalha como um interruptor para o http, fechando a conexão, após cada transferência.
       option httpclose
       #Força o haproxy inspecionar todas as requisições de uma conexão
       option forwardfor
       #Definindo como que vai ser a checagem do serviço http método HEAD , uri /.check.txt, Versão HTTP/1.0
       option httpchk HEAD /.check.txt HTTP/1.0
       #Definição dos servidores apache, o nome apache1 ou apache2 é o que vai aparecer nos logs
       #10.101.0.* é o ip dos servidores pode ser ipv4 ou ipv6
       #:80 é opcional, senão for definido vai ser redirecionado na mesma porta que o cliente solicitou ao haproxy
       #cookie A ou B é o valor do cookie enviado ao cliente.
       #Quem pode ter valores de cookies iguais é o servidor A por exemplo e o Backup.
       server apache1 10.101.0.22:80 cookie A check
       server apache2 10.101.0.23:80 cookie B check

Agora vamos configurar o haproxy para ser executado na inicialização do sistema.

sed -i "s/ENABLED=0/ENABLED=1/" /etc/default/haproxy

Agora vamos ajustar o kernel para que ele possa adicionar o ip que foi definido no haproxy para o clusterapache.

echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf

Agora vamos carregar a nova variável do kernel.

sysctl -p

Agora vamos instalar o keepalived no nodo1 do balancer

apt-get install keepalived -y

Agora vamos criar o arquivo de configuração para o keepalived, podemos obter exemplos da configuração do keepalived em /usr/share/doc/keepalived/samples

vim /etc/keepalived/keepalived.conf
#Configuração global do keepalived
global_defs {
   #Quem vai receber o email de notificação do keepalived
   notification_email {
     douglas@douglasqsantos.com.br
   }
   #Em nome de quem vai ser enviado o email
   notification_email_from douglas@douglasqsantos.com.br
   #Qual o servidor de email que vai enviar a mensagem
   smtp_server smtp.douglasqsantos.com.br
   #tempo de espera máximo
   smtp_connect_timeout 30
   #identificação que vai aparecer no email sobre esta notificação
   router_id clusterapache
}

#Script que vai ser executado em caso do outro nodo estar utilizando o ip virtual
vrrp_script chk_haproxy {
        #O comando que vai ser executado
        script "killall -0 haproxy"
        #Intervalo de checagem
        interval 2
        #Peso do script
        weight 2
}

#
vrrp_instance clusterapache {
        #Interface que vai receber o ip virtual
        interface eth0
        #Tipo da instancia, pode ser master ou backup
        state MASTER
        #identificação desta instancia
        virtual_router_id 51
        #prioridade 101 no servidor master, 100 no backup
        priority 101                    
        
        
        #Ip virtual que vai ser compartilhado
        virtual_ipaddress {
            10.101.0.30/24
        }
        #Ação que vai ser tomada caso tenhamos conflito no uso do ip virtual
        track_script {
            chk_haproxy
        }
}

Agora vamos iniciar o haproxy e o keepalived

/etc/init.d/haproxy restart && /etc/init.d/keepalived restart

Agora vamos ver se o haproxy subiu o ip 10.101.0.30

ip address list eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:c7:b7:94 brd ff:ff:ff:ff:ff:ff
    inet 10.101.0.20/24 brd 10.101.0.255 scope global eth0
    inet 10.101.0.30/24 scope global secondary eth0
    inet6 fe80::a00:27ff:fec7:b794/64 scope link
       valid_lft forever preferred_lft forever

Como pode ser notado o nosso nodo1 do balancer já está ok.

Agora podemos testar o nosso balancer em http://10.101.0.30, cada vez que mandarmos atualizar ele vai para um servidor diferente.

OBS: No Google Chrome ele não fica atualizando pois a conexão não foi fechado com isso ele vai continuar no mesmo server, somente vai ser mudado o servidor quando a conexão for fechada.

Vamos abrir algumas requisições simultâneas para o nosso servidor.

ab -n 3000 -c 100 http://10.101.0.30/                                        
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 10.101.0.30 (be patient)
Completed 300 requests
Completed 600 requests
Completed 900 requests
Completed 1200 requests
Completed 1500 requests
Completed 1800 requests
Completed 2100 requests
Completed 2400 requests
Completed 2700 requests
Completed 3000 requests
Finished 3000 requests


Server Software:        Apache/2.2.16
Server Hostname:        10.101.0.30
Server Port:            80

Document Path:          /
Document Length:        17 bytes

Concurrency Level:      100
Time taken for tests:   2.156 seconds
Complete requests:      3000
Failed requests:        0
Write errors:           0
Total transferred:      876000 bytes
HTML transferred:       51000 bytes
Requests per second:    1391.16 [#/sec] (mean)
Time per request:       71.882 [ms] (mean)
Time per request:       0.719 [ms] (mean, across all concurrent requests)
Transfer rate:          396.70 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       2
Processing:     1    2   0.4      2       5
Waiting:        0    1   0.4      1       5
Total:          1    2   0.4      2       5

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      2
  80%      2
  90%      3
  95%      3
  98%      3
  99%      3
 100%      5 (longest request)

Agora podemos conferir as estatísticas no haproxy em http://10.101.0.30/haproxy?stats

A página vai ser similar a está.

Configuração do Balancer2

Vamos mandar atualizar os repositórios e fazer um upgrade do sistema

aptitude update && aptitude dist-upgrade -y

Vamos instalar o haproxy nele.

apt-get install haproxy

Agora vamos fazer backup do arquivo de configuração do haproxy no nodo1 do balancer, neste arquivo temos alguns exeplos de configuração do haproxy.

cp /etc/haproxy/haproxy.cfg{,.bkp}

Vamos zerar o arquivo de configuração do haproxy

cat /dev/null > /etc/haproxy/haproxy.cfg

Agora vamos criar o novo arquivo de configuração para a nossa solução.

vim /etc/haproxy/haproxy.cfg
global
        #definição de logs gerados pelo haproxy
        #endereço do servidor de log, categoria do syslog, prioridade
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        #número máximo de conexões simultaneas para todos os clusters neste servidor,
        #se ultrapassar este valor o haproxy para de aceitar conexões, para todos os clusters
        maxconn 4096
        #Habilita o debug, e desabilita o trabalho do haproxy em background,
        #para mostrar as mensagems de iniciliazação.
        #debug
        #Não mostra mensagem durante a inicialização do haproxy
        #quiet
        #usuário que o haproxy vai ser executado
        user haproxy
        #grupo que o haproxy vai ser executado
        group haproxy
        #O haproxy vai ser executado em segundo plano no sistema.
        daemon

#Definido o tipo de proxy que sera utilizado
defaults
        #utiliza a configuração de log da seção global.
        log     global
        #Temos 3 modos de operação tcp trabalha como tcp padrão modo full-duplex,
        #http qualquer pedido que não é compatível com RFC serão rejeitadas
        #health  este modo só vai responder "OK" para conexões de entrada e fechar a conexão. Nada será logado
        mode    http
        #Ativa o log de solicitação HTTP de estado de sessão, e temporizadores.
        option  httplog
        #Não gerar logs de conexões aonde nenhum dado foi transferido.
        option  dontlognull
        #Número de tentativas para executar em um servidor após uma falha de conexão.
        retries 3
        #Ativa a redistribuição da sessão em caso de falha de conexão.
        option redispatch
        #Tempo limite de verificação adicional, mas apenas depois que uma conexão já foi estabilecida
        timeout check 5000
        #Tempo limite de inatividade máxima no lado do cliente.
        timeout client 50000
        #Tempo limite de inatividade máxima no lado do servidor
        timeout server 50000
        #Tempo máximo de espera para uma tentativa de conexão a um servidor para sucesso.
        timeout connect 2000
        
#Definição do ip e porta que vai responder o cluster
listen clusterapache 10.101.0.30:80
       #número máximo de conexões simultaneas, se ultrapassar este valor o clusterapache,
       #para de responder novas conexões.
       maxconn 1000
       #Temos 3 modos de operação tcp trabalha como tcp padrão modo full-duplex,
       #http qualquer pedido que não é compatível com RFC serão rejeitadas
       #health  este modo só vai responder "OK" para conexões de entrada e fechar a conexão. Nada será logado
       mode http
       #libera acesso a pagina de estatísticas do haproxy
       stats enable
       #usuário e senha da página de estatísticas do haproxy
       stats auth user1:senha
       #Quantidade de conexões simultâneas ao relatório de estdrão é 1maxconn 5
       #algoritmo de balanceamento
       balance roundrobin
       #Modo analisador de URL padrão, com isso o haproxy vai procurar o cookie em 10.101.0.30/.check.txt
       cookie JSESSIONID prefix
       #Trabalha como um interruptor para o http, fechando a conexão, após cada transferência.
       option httpclose
       #Força o haproxy inspecionar todas as requisições de uma conexão
       option forwardfor
       #Definindo como que vai ser a checagem do serviço http método HEAD , uri /.check.txt, Versão HTTP/1.0
       option httpchk HEAD /.check.txt HTTP/1.0
       #Definição dos servidores apache, o nome apache1 ou apache2 é o que vai aparecer nos logs
       #10.101.0.* é o ip dos servidores pode ser ipv4 ou ipv6
       #:80 é opcional, senão for definido vai ser redirecionado na mesma porta que o cliente solicitou ao haproxy
       #cookie A ou B é o valor do cookie enviado ao cliente.
       #Quem pode ter valores de cookies iguais é o servidor A por exemplo e o Backup.
       server apache1 10.101.0.22:80 cookie A check
       server apache2 10.101.0.23:80 cookie B check

Agora vamos configurar o haproxy para ser executado na inicialização do sistema.

sed -i "s/ENABLED=0/ENABLED=1/" /etc/default/haproxy

Agora vamos ajustar o kernel para que ele possa adicionar o ip que foi definido no haproxy para o clusterapache.

echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf

Agora vamos carregar a nova variável do kernel.

sysctl -p

Agora vamos instalar o keepalived no nodo1 do balancer

apt-get install keepalived -y

Agora vamos criar o arquivo de configuração para o keepalived, podemos obter exemplos da configuração do keepalived em /usr/share/doc/keepalived/samples

vim /etc/keepalived/keepalived.conf
#Configuração global do keepalived
global_defs {
   #Quem vai receber o email de notificação do keepalived
   notification_email {
     douglas@douglasqsantos.com.br
   }
   #Em nome de quem vai ser enviado o email
   notification_email_from douglas@douglasqsantos.com.br
   #Qual o servidor de email que vai enviar a mensagem
   smtp_server smtp.douglasqsantos.com.br
   #tempo de espera máximo
   smtp_connect_timeout 30
   #identificação que vai aparecer no email sobre esta notificação
   router_id clusterapache
}

#Script que vai ser executado em caso do outro nodo estar utilizando o ip virtual
vrrp_script chk_haproxy {
        #O comando que vai ser executado
        script "killall -0 haproxy"
        #Intervalo de checagem
        interval 2
        #Peso do script
        weight 2
}

#
vrrp_instance clusterapache {
        #Interface que vai receber o ip virtual
        interface eth0
        #Tipo da instancia, pode ser master ou backup
        state MASTER
        #identificação desta instancia
        virtual_router_id 51
        #prioridade 101 no servidor master, 100 no backup
        priority 101                    
        
        
        #Ip virtual que vai ser compartilhado
        virtual_ipaddress {
            10.101.0.30/24
        }
        #Ação que vai ser tomada caso tenhamos conflito no uso do ip virtual
        track_script {
            chk_haproxy
        }
}

Agora vamos iniciar o haproxy e o keepalived

/etc/init.d/haproxy restart && /etc/init.d/keepalived restart

Agora vamos ver se o haproxy subiu o ip 10.101.0.30, como pode ser notado ele não está aqui, pois está sendo utilizado no nodo1.

ip address list eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:c7:b7:94 brd ff:ff:ff:ff:ff:ff
    inet 10.101.0.21/24 brd 10.101.0.255 scope global eth0
    inet6 fe80::a00:27ff:fec7:b794/64 scope link
       valid_lft forever preferred_lft forever

Como pode ser notado o nosso nodo2 do balancer já está ok.

Agora vamos desligar o nodo1 do balancer, para verificar se o ip 10.101.0.30 vai para o nodo2 balancer

No nodo1 do balancer

init 0

Agora vamos conferir no nodo2 do balancer se ele assumiu o ip

ip address list eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:58:cf:cf brd ff:ff:ff:ff:ff:ff
    inet 10.101.0.21/24 brd 10.101.0.255 scope global eth0
    inet 10.101.0.30/24 scope global secondary eth0
    inet6 fe80::a00:27ff:fe58:cfcf/64 scope link
       valid_lft forever preferred_lft forever

Agora vamos testar o nosso cluster em http://10.101.0.30, ele ainda está funcionando como se nada tivesse acontecido.

Como pode ser notado o nosso balancer está ok.

Agora vamos acertar o apache para ele buscar os dados do site no drbd.

Vamos configurar no nodo1 do apache.

Vamos mover a configuração do site para o ocfs2 como vai ser a mesma para os dois apache.

mv /var/www/ /ocfs2

Agora vamos criar um link simbolico em /var para não precisarmos alterar muita coisa.

ln -sf /ocfs2/www/ /var/www

Agora vamos acertar a permissão do Link

chown -R www-data:www-data /var/www

Agora no nodo2 do apache somente precisamos acertar o link, vamos fazer isso então.

Vamos remover o /var/www

rm -rf /var/www

Agora vamos criar o link

ln -sf /ocfs2/www /var/www

Agora vamos acertar as permissões

chown -R www-data:www-data /var/www

Agora vamos somente acertar a configuração do virtualhost do nodo1 do apache, levando em consideração que o cluster que estamos montado é para o www.

sed -i "s/apache1/www/g" /etc/apache2/sites-available/nodo1

Agora vamos somente acertar a configuração do virtualhost do nodo2 do apache, levando em consideração que o cluster que estamos montado é para o www.

sed -i "s/apache2/www/g" /etc/apache2/sites-available/nodo2

Agora só precisamos configurar o servidor DNS para responder o www.douglasqsantos.com.br em 10.101.0.30 e temos o nosso cluster com balanceamento funcionando.

Referências