Archive for the Scripts Category

* DRBD 8.x

DBRD é a acrônimo para o nome inglês Distributed Replicated Block Device. O DRBD consiste num módulo para o kernel de Linux que, juntamente com alguns scripts, oferece um dispositivo de bloco projetado para disponibilizar dispositivos de armazenamento distribuídos, geralmente utilizado em clusters de alta disponibilidade. Isto é feito espelhando conjuntos de blocos via rede (dedicada). O DRBD funciona, portanto, como um sistema RAID baseado em rede.

Referência: http://pt.wikipedia.org/wiki/DRBD

* GFS 1.x

O “Red Hat Global File System” é um Sistema de Arquivos para Cluster, que permite que vários nós leiam e escrevam dados simultaneamente em um dispositivo compartilhado.

O GFS suporta ACL’s e atributos extendidos, diferente se seu concorrente direto, o OCFS (Oracle Cluster File System)

Vale observar que a versão 2.0 do GFS ainda é considerado “Technology Preview” e não deve ser usado em produção.

Porém, o GFS congela todo o I/O se ele perde um nó (cliente), e fica congelado até o que o nó retorne ou que o mesmo seja “fenced”.

Referência: http://www.redhat.com/gfs/
http://en.wikipedia.org/wiki/Comparison_of_file_systems

* Fence Devices

Fence é algo difícil de traduzir para a nossa língua, assim como a palavra “proxy” O Babylon sugere “grade; muro; cercar; proteger” enquanto o Google Translator sugere “vedação”.

Enfim, é algo nesse sentido: Se um nó do cluster apresenta problemas, para evitar que esse cara escreva algo no FileSystem? e acabe por corromper o mesmo, é necessário que o mesmo seja “fenceado”, ou seja, tirado da jogada. As formas comuns se se fazer isso são:

- Desligando a alimentação de energia deles;
- Desligando a porta do switch;
- Reiniciando a máquina usando DRAC/RSA/ILO (Dell, IBM e HP respectivamente);
- Manualmente;

Utilizaremos a forma menos recomendada (manual) devido a falta de infra-estrutura para utilizarmos as demais. Um script do modificado do DRBD irá tornar o fencing_manual em um fencing automatizado :-D

Referência: http://www.everlinux.com/blog/2008/04/22/redhat-enterprise-linux-51-cluster-suite/

* LVM

Usaremos LVM para garantir flexibilidade da solução:

Criar volumes LV nas duas máquinas

# pvcreate /dev/sda9
# vgcreate vol0 /dev/sda9
# lvcreate -L 105.94G -n lvm vol0

- Configurando o DRBD

Configurar o /etc/hosts para conter todas as maquinas, principalmente o hostname no IP principal e um nome para os IPs da rede de sincronismo:

127.0.0.1 localhost.localdomain localhost
10.10.10.1 hotsite-1.com.br
10.10.10.2 hotsite-2.com.br
192.168.0.3 drbd_hotsite-1 drdb_hotsite-1.com.br
192.168.0.4 drdb_hotsite-2 drdb_hotsite-2.com.br

Configurar o /etc/drbd.conf no master e slave

# DRDB Configuration
global {
usage-count no;
}

resource hotsite {
protocol C;

startup {
wfc-timeout 0;
degr-wfc-timeout 120;
become-primary-on both;
}
disk {
fencing resource-and-stonith;
}
handlers {
outdate-peer “/sbin/obliterate”;
}
net {
cram-hmac-alg sha1;
shared-secret “senha_secreta”;
timeout 60;
connect-int 10;
ping-int 10;
max-buffers 2048;
max-epoch-size 2048;
allow-two-primaries;
after-sb-0pri discard-zero-changes;
after-sb-1pri discard-secondary;
after-sb-2pri disconnect;
rr-conflict violently;
}
syncer {
rate 650M;
}

on hotsite-1.com.br {
device /dev/drbd0;
disk /dev/vol0/lvm;
address 192.168.0.3:7789;
flexible-meta-disk internal;
}

on hotsite-2.com.br {
device /dev/drbd0;
disk /dev/vol0/lvm;
address 192.168.0.4:7789;
flexible-meta-disk internal;
}
}

Inicializar as partições para o drbd no master e slave

# drbdadm create-md hotsite |
# drbdadm attach hotsite | drbdadm up hotsite
# drbdadm connect hotsite |

# drbdadm -- --overwrite-data-of-peer primary hotsite
# watch -n1 cat /proc/drbd
# drbdadm primary hotsite

Obs: Caso de erro de carga de modulo inicie o drbd com “service drbd start” mesmo acusando erro, isso fará com que carregue o modulo corretamente.

Inicializar o drbd no master e slave

# service drbd start

- Configurando o cluster para o GFS

* Crie o arquivo de configuração do cluster (/etc/cluster/cluster.conf) para o gfs, em todas as maquinas:

Vou colocar ele em um arquivo separado pois o wordpress não está gostando as tags do mesmo ;)

cluster.conf

Formatar a partição DRBD com GFS

# gfs_mkfs -t hotsite:gfs-00 -p lock_dlm -j 2 /dev/drbd0

Com isto ele irá iniciar o sincronismo com slave, pode ser observado executando o comando:

# watch -n 1 cat /proc/drbd

Inicie o serviços de cluster:

# service cman start

Testando

# mount -v /dev/drbd0 /data
# for i in `seq 1 10`; do a=`echo $RANDOM`; dd if=/dev/zero of=/data/$a bs=1k count=$a; sleep 1; done
# ls -ltrk /data

Forçando um reboot:
# echo 1 > /proc/sys/kernel/sysrq
# echo b > /proc/sysrq-trigger

Para forçar o sincronismo de uma máquina
(faça somente se souber o que está fazendo)
# drbdsetup /dev/drbd0 primary -o

Ordem dos scripts:

Essa deverá ser a ordem para init level 0 e 6, pois durante o reboot/ shutdown da máquina o procedimento é o seguinte:
- Desmonta a partição
- Tira a máquina do Cluster
- Para o DRBD

[root@hotsite-2 /etc/rc0.d]# ll | egrep '(partition|drbd|cman)'
lrwxrwxrwx 1 root root 12 Jun 13 11:57 K80partition -> ../init.d/partition
lrwxrwxrwx 1 root root 14 Jun 13 11:47 K81cman -> ../init.d/cman
lrwxrwxrwx 1 root root 14 Jun 13 11:57 K82drbd -> ../init.d/drbd

Para os init level 3, 4 e 5 deverá ser:
- Coloca a máquina do Cluster
- Inicia o DRBD
- Monta a partição do drbd (pois o mesmo irá falhar durante a inicialização)

[root@hotsite-2 /etc/rc3.d]# ll | egrep '(partition|drbd|cman)'
lrwxrwxrwx 1 root root 14 Jun 13 11:55 S21cman -> ../init.d/cman
lrwxrwxrwx 1 root root 14 Jun 13 11:55 S70drbd -> ../init.d/drbd
lrwxrwxrwx 1 root root 12 Jun 13 11:55 S91partition -> ../init.d/partition

O Script obliterate

O script Obliterate foi escrito pelo Lon Hohberger e está disponível aqui.

Eu alterei as últimas linhas pois o fence_manual precisa que o comando fence_ack_manual seja executado, senão o GFS não vai liberar o I/O do cluster enquanto o outro nó não retornar com sucesso…

#
fence_node $REMOTE
fence_ack_manual -O -e -n $REMOTE

if [ $? -eq 0 ]; then
# Reference:
# http://osdir.com/ml/linux.kernel.drbd.devel/2006-11/msg00005.html
# 7 = node got blown away.
exit 7
fi

# Fencing failed?!
exit 1

Referência: http://sources.redhat.com/cluster/wiki/DRBD_Cookbook

O script anterior foi atualizado contando com algumas melhorias sugeridas pelos seus usuários, como:

- Agora ele é escrito em Inglês, para maior portabilidade com outros usuários do xen ao redor do mundo;

- Você pode fazer backup de somente uma máquina específica, não é mais necessário esperar todo o laço terminar para ver o resultado do mesmo;

- Script parametrizado e funcões sub-divididas e

- Pequenos problemas corrigidos.

#!/bin/bash
# Backup of Xen VM's
# Tiago Cruz - tiagocruz@everlinux.com
# v 1.0 Mar/2008 - Initial version, just backup all VM's
# v 1.1 May/2008 - Now we have functions and parameters

export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
BACK="_snap"
LOG=/var/log/backup.`date +%Y%m%d`
# root partition to backup ("/")
# usually the second it's swap
ROOT="1"

[ ! -d "/mnt/back" ] && mkdir -p /mnt/back
[ ! -d "/data/backup" ] && mkdir -p /data/backup

function showHelp() {
echo " "
echo "Use the following parameters: "
echo " help = Show this help"
echo " all = Backup of all VM's"
echo " list = List all VM's from this domain"
echo " = Backup one specific VM”
echo ” ”
echo “ex: back_xen.sh tomcat_shop”
echo ” ”
exit 1
}

function listVM() {
echo “List of VM’s avaliables:”
/usr/sbin/xm list | awk ‘{print $1}’ | egrep -v ‘(Name|Domain-0)’
echo ” ”
}

function backXen () {
echo “Backuping machine $i…”
echo “Please, look the progress on $LOG”
listVM | grep $i >/dev/null
if [ $? -ne 0 ]; then
echo “Machine $i does not exist, aborting!”
exit 2
fi
backup
if [ $? -eq 0 ]; then
echo “Backup of $i completed successfully!!!”
echo “Backup finalized on `date` with load `cat /proc/loadavg | cut -c 1-14`” >> $LOG
echo “==============================================” >> $LOG
echo “==============================================” >> $LOG
fi
}

function backAll () {
VMS=`xm list | awk ‘{print $1}’ | egrep -v ‘(Name|Domain-0)’`
for i in $VMS; do
backup
done
echo “Backup finalized on `date` with load `cat /proc/loadavg | cut -c 1-14`” >> $LOG
echo “==============================================” >> $LOG
echo “==============================================” >> $LOG
}

function backup () {
echo “==============================================” >> $LOG
echo “Backup $i started on `date` with load `cat /proc/loadavg | cut -c 1-14`” >> $LOG
DEVICE=`grep ^disk /etc/xen/$i | awk -F “Vol_LVM” ‘{print $2}’ | cut -d / -f 2 | cut -d , -f 1`
echo “Virtual Machine $i uses $DEVICE as storage device” >> $LOG

lvcreate –snapshot -L 15G -n $i$BACK /dev/Vol_LVM/$DEVICE >> $LOG 2>&1
[ $? -ne 0 ] && echo “Error $i: creating LVM $i$BACK” >> $LOG

kpartx -a /dev/mapper/Vol_LVM-$i$BACK >> $LOG 2>&1
mount /dev/mapper/Vol_LVM-$i$BACK$ROOT /mnt/back/ >> $LOG 2>&1
[ $? -ne 0 ] && echo “Error $i: mounting $i$BACK$ROOT” >> $LOG

SIZE1=`df -hP /mnt/back/ | awk ‘{print $3}’ | grep -v Used`
SIZE2=`df -hP /mnt/back/ | awk ‘{print $2}’ | grep -v Size`
echo “Backup of /dev/mapper/Vol_LVM-$i$BACK$ROOT - $SIZE1 of $SIZE2 used” >> $LOG
tar zcf /data/backup/$i-xen.tar.gz /mnt/back >> $LOG
[ $? -ne 0 ] && echo “Error $i: creating /LVM/backup/$i.tar.gz” >> $LOG

SIZE3=`ls -lh /LVM/backup/$i-xen.tar.gz | awk ‘{print $5}’`
echo “Created /LVM/backup/$i-xen.tar.gz with $SIZE3″ >> $LOG

sleep 1
umount /mnt/back/ >> $LOG 2>&1
[ $? -ne 0 ] && echo “Error $i: umounting $i$BACK” >> $LOG
kpartx -d /dev/mapper/Vol_LVM-$i$BACK >> $LOG 2>&1
[ $? -ne 0 ] && echo “Error $i: deleting partition mappings $i$BACK” >> $LOG

echo “Removing snapshot already backuped $i$BACK” >> $LOG
lvremove /dev/Vol_LVM/$i$BACK -f >> $LOG 2>&1
}

if [ “$#” -eq 0 ]; then
showHelp

fi

case “$1″ in
list) listVM ;;
all ) backAll ;;
help) showHelp ;;
* ) i=$1; backXen ;;
esac

Caso tenha problemas com o copy-past, você pode pegar o mesmo aqui: back_xen.sh.txt.

Se você usa o Xen, usa Storage Devices sob LVM, e acha importante ter um backup das mesmas, você pode utilizar/ adaptar este pequeno script que tira um snapshot e em seguida faz um “tar.gz” de todo o “/” da sua VM, e a guarda em um local para que você possa restaura-lo caso necessário. :-D

#!/bin/bash
# Backup das VM's do Xen
# Tiago Cruz - tiagocruz@everlinux.com
# Mar/2008
export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

VMS=`xm list | awk '{print $1}' | egrep -v '(Name|Domain-0)'`
BACK="_snap"
LOG=/var/log/backup
# Particao root, geralmente a segunda eh swap
ROOT="1"

[ ! -d "/mnt/back" ] && mkdir -p /mnt/back
[ ! -d "/dados/backup" ] && mkdir -p /dados/backup

for i in $VMS; do
echo "=================================================================" >> $LOG
echo "Backup $i iniciado em `date` com load de `cat /proc/loadavg`" >> $LOG
DEVICE=`grep disk /etc/xen/$i | awk -F "Vol_LVM" '{print $2}' | cut -d / -f 2 | cut -d , -f 1`
echo "Maquina Virtual $i usa $DEVICE como storage device" >> $LOG

lvcreate --snapshot -L 15G -n $i$BACK /dev/Vol_LVM/$DEVICE >> $LOG
[ $? -ne 0 ] && echo "Erro $i: criando LVM $i$BACK" >> $LOG

kpartx -a /dev/mapper/Vol_LVM-$i$BACK >> $LOG
mount /dev/mapper/Vol_LVM-$i$BACK$ROOT /mnt/back/ >> $LOG
[ $? -ne 0 ] && echo "Erro $i: montando $i$BACK$ROOT" >> $LOG

SIZE1=`df -hP /mnt/back/ | awk '{print $3}' | grep -v Used`
SIZE2=`df -hP /mnt/back/ | awk '{print $2}' | grep -v Size`
echo "Backup de /dev/mapper/Vol_LVM-$i$BACK$ROOT - $SIZE1 de $SIZE2 usados" >> $LOG
tar zcf /dados/backup/$i-xen.tar.gz /mnt/back >> $LOG
[ $? -ne 0 ] && echo "Erro $i: criando /dados/backup/$i.tar.gz" >> $LOG

SIZE3=`ls -lh /dados/backup/$i-xen.tar.gz | awk '{print $5}'`
echo "Criado /dados/backup/$i-xen.tar.gz com $SIZE3" >> $LOG

umount /mnt/back/ >> $LOG
[ $? -ne 0 ] && echo "Erro $i: desmontando $i$BACK" >> $LOG
kpartx -d /dev/mapper/Vol_LVM-$i$BACK >> $LOG
[ $? -ne 0 ] && echo "Erro $i: desmapeando $i$BACK" >> $LOG

echo "Removendo snapshot ja backupeado $i$BACK" >> $LOG
lvremove /dev/Vol_LVM/$i$BACK -f >> $LOG
done

echo "Backup finalizado em `date` com load de `cat /proc/loadavg`" >> $LOG
echo "=================================================================" >> $LOG
echo "=================================================================" >> $LOG

Trecho do log:

Backup ora_busca iniciado em Fri Mar 28 05:02:53 BRT 2008 com load de 1.31 1.33 1.21
Maquina Virtual ora_busca usa ora_busca como storage device
Logical volume “ora_busca_snap” created
Backup de /dev/mapper/Vol_LVM-ora_busca_snap1 - 16G de 95G usados
Criado /dados/backup/ora_busca-xen.tar.gz com 4.9G
Removendo snapshot ja backupeado ora_busca_snap
Logical volume “ora_busca_snap” successfully removed

1-) Estou armazenando as VMs no LVM:

# lvcreate -Ay -L 60G -n vm00 Vol_LVM
# lvcreate -Ay -L 60G -n vm01 Vol_LVM
# lvcreate -Ay -L 60G -n vm02 Vol_LVM

2-) Estou usando o “partimage-0.6.7_beta2.tar.bz2″, pois a versão stable não funciona bem em 64 bits:

3-) A primeira VM deve ser instalada/ configurada manualmente/normalmente. Depois você pode tirar uma cópia dela:

# kpartx -a /dev/mapper/Vol_LVM-vm01
# partimage -z1 save /dev/mapper/Vol_LVM-vm01p1 /LVM/vm01p1.partimg.gz

ou
# partimage -z0 -c -d -f0 save /dev/mapper/Vol_LVM-vm01p1 /LVM/vm01p1.partimg
# kpartx -d /dev/mapper/Vol_LVM-vm01

PS: Note que se você usar compressão (-z1) a geração da imagem vai demorar mais para ser criado, porém com o tamanho bem menor (515M vs 3.7GB) . A restauração da mesma também será mais lenta.

4-) Com base na primeira VM:

# fdisk -l /dev/mapper/Vol_LVM-vm00
Disk /dev/mapper/Vol_LVM-vm00: 64.4 GB, 64424509440 bytes
255 heads, 63 sectors/track, 7832 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/mapper/Vol_LVM-vm00p1 * 2 7395 59392305 83 Linux
/dev/mapper/Vol_LVM-vm00p2 7396 7832 3510202+ 82 Linux swap / Solaris

Você poderá preparar um arquivo, por exemplo, /tmp/parttable, com as especificações das demais partições.
1,7394,83,*
7395,,82,-

Estou usando uma partição primária para o raiz “/” (tipo 83) com ~ 60 GB e o restante para swap (tipo 82).

Você poderá usar o sfdisk e especificar os dados em: sectors, blocks, cylinders ou megabytes.

5-) Crie as partições para a segunda VM:

# dd if=/dev/zero of=/dev/mapper/Vol_LVM-vm01 count=1 bs=512
# sfdisk -uC /dev/mapper/Vol_LVM-vm01 < /tmp/parttable

Se preferir, simplesmente faça o processo manualmente:
# fdisk /dev/mapper/Vol_LVM-vm01

6-) Crie a SWAP para o segundo device:

Será necessário usar o “kpartx” para “mapear” as partições que existem dentro do device LVM:

# kpartx -a /dev/mapper/Vol_LVM-vm01
# ll /dev/mapper/Vol_LVM-vm01*
# mkswap /dev/mapper/Vol_LVM-vm01p2

7-) Restaure a imagem da primeira VM:

- Restauração com GZIP:

# partimage restore /dev/mapper/Vol_LVM-vm02p1 /LVM/vm01p1.partimg.gz
Time elapsed: 10m:59sec
Speed: 5.16 GiB/min
Data copied: 56.64 GiB

- Restauração sem GZIP:

# partimage restore /dev/mapper/Vol_LVM-vm03p1 /LVM/vm01p1.partimg.000
Time elapsed: 1m:15sec
Speed: 2.90 GiB/min
Data copied: 3.62 GiB

8-) Monte a VM e troque endereços de IP, hostname e MAC Address:
# mount /dev/mapper/Vol_LVM-vm01p1 /mnt/xen/
# vi /mnt/xen/etc/sysconfig/network-scripts/ifcfg-eth0
# vi /mnt/xen/etc/sysconfig/network
# vi /mnt/xen/etc/hosts

PS: Use o macgen.py para alterar o MAC address:

$ cat macgen.py
#! /usr/bin/python
# macgen.py script generates a MAC address for Xen guests
#
import random
mac = [ 0×00, 0×16, 0×3e,
random.randint(0×00, 0×7f),
random.randint(0×00, 0xff),
random.randint(0×00, 0xff) ]
print ‘:’.join(map(lambda x: “%02x” % x, mac))

9-) Desmonte a partição, e arrume seu /etc/xen/vm02:

# umount /mnt/xen
# kpartx -d /dev/mapper/Vol_LVM-vm02

Utilize o “uuidgen” para gerar um novo UUID para sua VM.
Não esqueça de trocar também o MAC no campo “vif” e o device LVM, ex:

name = “vm02″
uuid = “82f89076-487e-4de5-ab4a-99ce07c586eb”
maxmem = 1000
memory = 800
vcpus = 1
bootloader = “/usr/bin/pygrub”
on_poweroff = “destroy”
on_reboot = “restart”
on_crash = “restart”
vfb = [ “type=vnc,vncunused=1,keymap=en-us” ]
disk = [ “phy:/dev/Vol_LVM/vm01,xvda,w” ]
vif = [ “mac=00:16:3e:5a:02:a6,bridge=xenbr0″ ]

10-) Inicie a VM e corra para o abraço:

# xm create vm02 -c

Em caso de problemas, consulte este artigo: Xen: Dicas rápidas e problemas resolvidos

Caso você precise saber quanta memória seus processos do apache estão utilizando do seu SO, pode utilizar este script no crontab:

#!/bin/bash
LOG="/var/log/apache_memoria.log"
PROC=`ps -eLf | grep apache | wc -l`
rm -f /tmp/http.txt
for i in `ps -ylC httpd --sort:rss | awk '{print $8}'`; do echo $i | grep -v RSS >> /tmp/http.txt ; done
MEM=$(echo "scale=2; (`cat /tmp/http.txt | tr '\n' +`0"\)/1024 | bc)
echo "`date` -- $MEM MB utilizados pelo httpd com $PROC processos" >> $LOG

Os resultados me parecem bem interessantes... :-)


Tue Jan 8 12:45:01 BRST 2008 — 765.91 MB utilizados pelo httpd
Tue Jan 8 13:00:01 BRST 2008 — 903.92 MB utilizados pelo httpd
Tue Jan 8 13:15:01 BRST 2008 — 689.61 MB utilizados pelo httpd
Tue Jan 8 13:30:01 BRST 2008 — 629.17 MB utilizados pelo httpd

A quantidade pode variar bastante, caso seu apache seja estático ou dinâmico (com PHP por exemplo) e MPM’s de prefork e worker também apresentam resultados diferentes.

Estou passando aqui somente para compartilhar um shell script para verificar o estado atual da sua controladora RAID, pois redundância é bom mas se você não trocar os discos não adianta muita coisa :-)

O script atualmente suporta:

- Controladoras da LSI Megaraid e as mais novas MegaraidSAS, usando o megarc e o MegaCli respectivamente;
- Contoladoras ServerRAID da IBM (só o modelo novo que não funciona ainda no ipssend, o “IBM ServeRAID 8k/8k-l8” e eu não entendo o motivo.);
- Controladora Mylex e RAID por Software;
- É capaz de detectar sua controladora e configurar o nrpe localmente;
- Dá permissão para o usuário do nagios usar SUID para rodar os aplicativos;

Utilize os seguintes parâmetros:
check_raid.sh detecta - Para tentar detectar sua controladora e instalar os pacotes necessários
check_raid.sh nrpe - Para configurar o daemon do nrpe para a sua controladora

check_raid.sh megaraid - Para controladoras MegaRAID (geralmente nas Dell’s Poweredge 18xx, 28xx ou mais antigas)
check_raid.sh megaraid_sas - Para controladoras MegaRAD SAS (geralmente nas Dell’s Poweredge 19xx, 29xx ou mais novas)
check_raid.sh serveraid - Para controladoras geralmente presente em máquinas IBM’s
check_raid.sh mylex - Para a controladora Mylex
check_raid.sh software - Para RAID via software

Exemplos:
check_raid.sh nrpe
check_raid.sh megaraid_sas

O script está meio bagunçado, não reconhece todas as controladoras mas é um adianto na hora de chegar centenas ou milhares de RAID’s diferentes. Caso tenha alguma contribuição, favor entrar em contato comigo (tiagocruz AT everlinux.com).

Download aqui: http://everlinux.com/raid/check_raid.sh

PS: Não enviei ao NagioExchange porque fiz a me*** de escreve-lo todo em Português do Brasil… :-(