Translate

viernes, 7 de diciembre de 2012

Asterisk con Alta-Disponibilidad + MySQL

En algunas ocasiones nos vemos en la necesidad de crear un Cluster de alta disponibilidad para nuestros servicios de Asterisk. A continuación se describen los pasos necesarios para llevar esto acabo en nuestros servidores usando Asterisk y MySQL(por si queremos usar Asterisk Realtime Architechture).

Estos pasos están basados en las instrucciones que brinda Digium y los tutoriales de DRBD para MySQL.
Este tutorial no esta hecho para hacer copy&paste.
El color verde indica que son pasos para realizar en ambos servidores.
El color Naranja indica que son pasos para realizar en el servidor primario.
El color Rojo indica que son pasos para realizar en el servidor secundario.
El Hostname del Servidor primario es "node1".
El Hostname del Servidor secundario es "node2".
La dirección IP del servidor primario es 10.0.1.51
La dirección IP del servidor secundario es 10.0.1.52
La dirección IP compartida del cluster y a la que deberán apuntar los servicios(como el registro de teléfonos, MySQL o apache) es 10.0.1.50.
La dirección IP del Gateway es 10.0.1.1.
Se puede adaptar fácilmente el Hardware Failover que provee Digium(rseries) y los servicios de Apache.



La Imagen anterior describe el funcionamiento del Cluster:
-- Escenario 1: El servidor primario esta activo y el secundario esta en modo pasivo esperando.
-- Escenario 2: El servidor Primario ha entrado en estado de falla(por conexión de RED o por reinicio o falla en el kernel), el servidor secundario entonces, se convierte en el servidor primario y es marcado como activo.
-- Escenario 3: El servidor secundario(antes primario) se ha recuperado de la falla y ha entrado en modo pasivo.
-- Escenario 4: El servidor primario(antes secundario)  ha presentado falla  y el servidor secundario(antes primario) es marcado como servidor primario nuevamente y entra en modo activo.


Paso 1 ---- Realizar en Ambos Servidores:

Instala CentOS 5.X(Los agentes de recursos "ocf"de Digium no son compatibles con las versiones 6.X de CentOS). Escoger el modo de partición manual y dejar un espacio libre sin formateo ni nada, en este tutorial yo he dejado 5GB sin particionar. Este espacio será donde guardemos nuestros datos a replicar en el Cluster, así que deberán considerar cuanto espacio necesitaran para sus archivos y logs.

Paso 2 ---- Realizar en Ambos Servidores:

Instala las dependencias para nuestros servidores. Primero añadiré el repositorio de rpmforge:
#rpm -ihv http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.2-2.el5.rf.[ARCH].rpm
Cambia [ARCH] por la arquitectura del servidor: i386 o x86_64.

Ahora instala las dependencias:
#yum -y install kernel kernel-devel libxml2  libxml2-devel  libtiff  libtiff-devel  lame httpd  mysql mysql-devel mysql-server php  php-pear  php-mysql  php-gd openssl openssl-devel perl  bison ncurses-devel audiofile-devel curl sox gcc newt-devel libusb-devel glibc-devel  zlib-devel svn gcc-c++ subversion make nano wget cfdisk


Paso 3 ---- Realizar en Ambos Servidores:

Ejecuta el comando:
#cfdisk

Obtendrás una ventana como esta:

Selecciona el espacio libre y crea una nueva partición con todo el espacio libre usando los botones: New, Primary, Write. Al finalizar te preguntara si quieres efectuar los cambios, escribe la palabra: yes y da enter.

Cuando el proceso termine reinicia el servidor:
#reboot  

Una vez que el servidor haya arrancado de nuevo hay que limpiar la nueva partición usando el siguiente comando:
#dd if=/dev/zero of=/dev/[hs]da[#] bs=1M; sync
Cambia /dev/[hs]da[#] por tu dispositivo que puede ser SDA3,HDA3 o SDB3 HDB3 etc. En este tutorial es HDA3.

Veras una salida similar cuando termine el proceso, dependiendo del tamaño de tu partición y de la velocidad de tus discos duros puede tomar minutos u horas.


Crea un nuevo directorio en /usr/src:
#cd /usr/src/
#mkdir asterisk
#cd asterisk/


En el nuevo directorio descarga Asterisk y sus componentes:
#wget http://downloads.asterisk.org/pub/telephony/dahdi-linux-complete/dahdi-linux-complete-2.6.1+2.6.1.tar.gz
#wget http://downloads.asterisk.org/pub/telephony/libpri/libpri-1.4.13.tar.gz
#wget http://downloads.asterisk.org/pub/telephony/certified-asterisk/certified-asterisk-1.8.11-current.tar.gz
#wget http://downloads.digium.com/pub/telephony/rseries/rseries-current.tar.gz

Descomprime los archivos fuente:
#for i in `ls *gz`; do tar zxvf $i; done

Compilamos DAHDI:
#cd dahdi-linux-complete-2.6.1+2.6.1
#make && make all && make install && make config

Compilamos LibrPRI y configuramos DAHDI:
#cd ../libpri-1.4.13
#make && make install
#service dahdi start
#dahdi_genconf
#dahdi_cfg -vvvvv

Instalamos los agentes de Digium para el cluster:
#cd ../rseries-1.0.0/
#make && make install


Paso 4 ---- Realizar solo en  Servidor Primario..

Instalar Asterisk en el servidor primario:

#cd ../certified-asterisk-1.8.11-cert9
#contrib/scripts/get_mp3_source.sh
#./configure && make menuselect


En el menú selecciona las aplicaciones que quieras disponibles en tu asterisk:

Guarda los cambios y compila Asterisk:
#make && make install && make config && make samples

Inicia el servicio de Mysql y detenlo esto solo para crear las bases de datos por default.
#service mysqld start
#service mysqld stop


Paso 5 ---- Realizar en Ambos Servidores.

Cambiate al directorio de rseries:
#cd /usr/src/asterisk/rseries-1.0.0/

Instala los servicios de DRBD:
#yum -y install drbd83 kmod-drbd83

Instala Libesmtp, dependencia necesaria para Pacemaker:
#wget http://dl.fedoraproject.org/pub/epel/5/[ARCH]/libesmtp-1.0.4-5.el5.[ARCH].rpm #64bits
Cambia [ARCH] por la arquitectura del servidor: i386 o x86_64.

Instala PaceMaker y Corosync:
#wget -O /etc/yum.repos.d/pacemaker.repo http://clusterlabs.org/rpm/epel-5/clusterlabs.repo
#yum -y install -x heartbeat-stonith* pacemaker corosync
Estamos exluyendo el paquete heratbeat-stonith ya que cre un conflicto con pacemaker.

Instala los archivos de configuración que provee Digium:
#make samples

Agrega estas lineas al archivo /etc/drbd.conf:
echo "include \"drbd.d/global_common.conf\";" >> /etc/drbd.conf
echo "include \"drbd.d/*.res\";" >> /etc/drbd.conf

Edita el archivo /etc/drbd.d/asterisk.res. Cambia astnode1 por el nombre el hostname del servidor primario, cambia astnode2 por el hostname del servidor secundario, cambia /dev/sda3 por la partición que creamos con el espacio libre(en este tutorial hda3). Cambia las IPs por las de tus servidores primarios y secundarios.Cambia el correo electrónico por el tuyo o el administrador del sistema en este tutorial el archivo quedo así:
resource asterisk {
  handlers {
    split-brain "/usr/lib/drbd/notify-split-brain.sh clusteradmin@example.com";
  }

  net {
    after-sb-0pri discard-younger-primary;
    after-sb-1pri discard-secondary;
    after-sb-2pri disconnect;
  }

  on node1 {
    device    /dev/drbd0;
    disk      /dev/hda3;
    address   10.0.1.51:7789;    
    meta-disk internal;
  }
  on node2 {
    device    /dev/drbd0;
    disk      /dev/hda3;
    address   10.0.1.52:7789;
    meta-disk internal;
  }
}

Crea el Recurso llamado asterisk e inicia el servicio de DRDB:
#drbdadm create-md asterisk
#service drbd start


Paso 6 ---- Realizar solo en  Servidor Primario.

A continuación crea el UUID llamado Asterisk, y formatea la partición que será usada por el cluster tipo: EXT3
#drbdadm disconnect asterisk
#drbdadm -- --clear-bitmap new-current-uuid asterisk
#drbdadm -- --overwrite-data-of-peer primary asterisk
#mkfs.ext3 -m0 /dev/drbd0
#drbdadm secondary asterisk
#drbdadm detach asterisk
#drbdadm up asterisk


Crea el directorio que será usado para el cluster, pero antes marca como nodo primario para poder montarlo:
#drbdadm primary asterisk
#mkdir /mnt/asterisk

Monta la partición:
#mount -t ext3 /dev/drbd0 /mnt/asterisk

Ahora crea el directorio donde estará Mysql:
#mkdir /mnt/asterisk/mysql
#mkdir /mnt/asterisk/mysql/data
#cd /mnt/asterisk/mysql

Copia el contenido del directorio de Mysql al nuevo directorio:
#cp -aR /var/lib/mysql/* /mnt/asterisk/mysql/data
#ls data/

Mueve el archivo /etc/my.cnf al nuevo directorio de Mysql:
#mv /etc/my.cnf .

Crea un enlace simbólico al nuevo directorio:
#ln -s /mnt/asterisk/mysql/my.cnf /etc/
Edita el archivo my.cnf y cambia la directiva de DATADIR: datadir=/mnt/asterisk/mysql/data.

Crea un archivo dummy solo para verificar la replicación en el nodo secundario.
#touch test11

Desmonta la partición y marca el nodo como secundario:
#cd --
#umount /mnt/asterisk
#drbdadm secondary asterisk


Paso 7 ---- Realizar solo en Servidor Secundario

Elimina el archivo /etc/my.cnf
#rm -rf /etc/my.cnf

Vamos a verificar que los archivos de nuestra partición en el cluster se repliquen. Marca el servidor como primario y crea el mismo directorio:
#drbdadm primary asterisk
#mkdir /mnt/asterisk

Monta la partición y cambiate al directorio:
#mount -t ext3 /dev/drbd0 /mnt/asterisk
#cd /mnt/asterisk

Haz un enlace simbolico del archo my.cnf al directorio de la partición del cluster:
#ln -s /mnt/asterisk/mysql/my.cnf /etc/
Verifica que el archivo my.cnf sea el mismo que editamos anteriormente, es decir, que contenga:  datadir=/mnt/asterisk/mysql/data

Verifica que los archivos de Mysql y el archivo test11 existan en el directorio:
#ls

Si los archivos existen la replicación va de maravilla.

Desmonta la partición y marca el nodo como secundario:
#cd --
#umount /mnt/asterisk
#drbdadm secondary asterisk


Paso 8 ---- Realizar solo en  Servidor Primario.

Cambiate al directorio de rseries, mara el servdiro como primario y monta la partición:
#cd /usr/src/asterisk/rseries-1.0.0
#drbdadm primary asterisk
#mount -t ext3 /dev/drbd0 /mnt/asterisk/

Ejecuta el script cretalinks.sh:
#./createlinks.sh
Veras una salida como la siguiente:


Elimina el script de asterisk para que no arranque automáticamente cuando inicie el sistema, desmonta la partición y marca el nodo como secundario:
#chkconfig --del asterisk
#umount /mnt/asterisk
#drbdadm secondary asterisk


Paso 9 ---- Realizar solo en Servidor Secundario

Cambiate al directorio de rseries, marca el nodo como primario, monta la partición y ejecuta el script createlinks.sh:
#cd /usr/src/asterisk/rseries-1.0.0
#drbdadm primary asterisk
#mount -t ext3 /dev/drbd0 /mnt/asterisk/
#./createlinks.sh
Veras una salida como en la imagen anterior.

Cambiate al directorio de Asterisk, configura las mismas opciones que se configuraron en el servidor primario. Compilalo solo ejecutando make && make install. Desmonta la partición y marca el nodo como secundario.
#cd ../certified-asterisk-1.8.11-cert9
#contrib/scripts/get_mp3_source.sh
#./configure && make menuselect
#make && make install
#umount /mnt/asterisk/
#drbdadm secondary asterisk


Paso 10 ---- Realizar en Ambos Servidores.

Edita el archivo /etc/corosync/corosync.conf. Cambia la opción bindnetaddr, y las opciones memberaddr. Para este tutorial el archivo quedo de la siguiente manera:

totem {
        version: 2
        token: 3000
        token_retransmits_before_loss_const: 10
        join: 60
        consensus: 5000
        vsftype: none
        max_messages: 20
        clear_node_high_bit: yes
        secauth: off
        threads: 0
        rrp_mode: none

        interface {
                ringnumber: 0
                bindnetaddr: 10.0.1.0
                broadcast: yes
                mcastport: 5405
                member {
                        memberaddr: 10.0.1.51
                }
                member {
                        memberaddr: 10.0.1.52
                }
        }
}

aisexec {
        user:   root
        group:  root
}

logging {
        fileline: off
        to_stderr: yes
        to_logfile: no
        to_syslog: yes
        syslog_facility: daemon
        debug: off
        timestamp: on
        logger_subsys {
                subsys: AMF
                debug: off
                tags: enter|leave|trace1|trace2|trace3|trace4|trace6
        }
}

amf {
        mode: disabled
}

Inicia el servicio de Corosync y añade drbd y corosync al startup:
#service corosync start
#chkconfig drdb on
#chkconfig corosync on

Verifica el estado del Cluster con el siguiente comando:
#cat /proc/drbd
Veras una imagen como la siguiente:
Veras que se esta sincronizando la particion del cluster, también verás como Secondary/Secondary(no como en la imagen).

Si el proceso de sincronización reporta que tardará mucho tiempo puedes usar este comando para acelerar la velocidad de sincronización:
#drbdsetup /dev/drbd0 syncer -r 250M

La velocidad máxima de sincronización dependerá de la velocidad de tus tarjetas de red así como la velocidad de escritura de tus discos duros. Para más información de como calcular la velocidad ve a este enlace.

Una vez que el estado sea UpToDate/UpToDate reinicia los servidores:
#reboot


Paso 11 ---- Realizar solo en  Servidor Primario.

Edita el siguiente codigo para que:
-- node1 y node2. Sean los hostnames de tus servidores. En este ejemplo node1 y node2
-- ip bajo ClusterIP. Sea la Ip de tu Cluster, la IP flotante. En este ejemplo 10.0.1.50
-- cidr_mask bajo ClusterIP. Sea la mascara de tu red. en este ejemplo de 24bits(255.255.255.0)
- -host_list bajo GatewayStatus. Sea el gateway de tu red. en este ejemplo 10.0.1.1

node node1
node node2
primitive ClusterIP ocf:heartbeat:IPaddr2 \
        params ip="10.0.1.50" cidr_netmask="24" \
        op monitor interval="5"
primitive drbd ocf:linbit:drbd \
      params drbd_resource="asterisk" \
      op monitor start-delay="10" interval="5"  \
primitive drbd_fs ocf:heartbeat:Filesystem \
      params device="/dev/drbd0" directory="/mnt/asterisk/" fstype="ext3"
primitive mysqld lsb:mysqld
primitive Asterisk ocf:Digium:asterisk \
        op monitor interval="5"
primitive GatewayStatus ocf:pacemaker:ping \
        params host_list="10.0.1.1" multiplier="100" \
        op monitor interval="5" timeout="10"
ms drbd_ms drbd \
        meta master-max="1" master-node-max="1" clone-max="2" clone-node-max="1" notify="true"
clone GatewayStatusClone GatewayStatus
location Asterisk-with-ping Asterisk \
        rule $id="Asterisk-with-ping-rule" -inf: not_defined pingd or pingd lte 0
group mysql drbd_fs ClusterIP mysqld
colocation mysql_on_drbd inf: mysql drbd_ms:Master
order mysql_after_drbd inf: drbd_ms:promote mysql:start
colocation Everything-with-Asterisk inf: ( drbd_ms:Master )  ( ClusterIP drbd_fs )  Asterisk
order  Asterisk-after-Everything inf:   ( drbd_ms:promote ) ( ClusterIP drbd_fs )  Asterisk:start
property $id="cib-bootstrap-options" \
        cluster-infrastructure="openais" \
        expected-quorum-votes="2" \
        stonith-enabled="false" \
        no-quorum-policy="ignore"
rsc_defaults $id="rsc-options" \
        resource-stickiness="99"

Una vez que has editado el archivo Cluster_Mysql_Asterisk.cfg, actualiza la configuración de pacemaker:
#crm configure load update Cluster_Mysql_Asterisk.cfg

Si todo sale bien veras una salida como la siguiente y los servicios de MySQL y Asterisk se iniciaran en el nodo primario:

Para verificar que los servicios estén corriendo puedes revisar el estado del cluster con:
#crm_mon

Y verás algo así:



Demostración:

El siguiente video muestra las pruebas del cluster. Asterisk esta configurado con "static realtime" obteniendo los datos de una base de datos de MySQL. Este tutorial no cubre la cofiguración de ARA(Asterisk Realtime Architechture).




Herramientas para diagnosticar fallas:

Puedes ejecutar el siguiente comando en el nodo secundario para verificar que la configuración de pacemaker se replico:
#crm configure show

Para detener los servicios del cluster:
#crm configure property stop-all-resources=true

Para borrar la configuracion del cluster:
#crm configure erase

Verificar el estado del cluster:
#crm_mon

Verificar el estado de la sincronización y los roles de los servidores:
#cat /prco/drbd

Aumentar la velocidad de sincronización:
#drbdsetup /dev/drbd0 syncer -r 250M

21 comentarios:

  1. exelente tutorial.
    Pero como se confiraria DRBD si el server ya se encuentra operando com mysql y asterisk?

    ResponderEliminar
    Respuestas
    1. No sabría decirte sinceramente este tutorial esta hecho para instalaciones nuevas, sin lo que puedes hacer es adaptar la partición cluster en el server existente y seguir los pasos del tutorial para que funcione con el otro nodo.

      Saludos.

      Eliminar
  2. Hola una pregunta donde esta ubicado el archivo Cluster_Mysql_Asterisk.cfg?

    ResponderEliminar
    Respuestas
    1. Es el código del paso 11. Lo tienes que guardar con ese nombre o el de tu preferencia, solo recuerda cambiar también el nombre en el comando.

      Eliminar
    2. Hola Max gracias por tu ayuda, pero mi pregunta era en donde se ubicaba en que directorio, pero viendo de nuevo el manual de r series de Digium veo que esta en la carpeta del pacemaker supongo que es /usr/share/pacemaker en Debian mi caso, voy ha probar un par de cosas del MySql cualquier cosita te tocó la puerta, super sencillo y efectivo el manual pa, mis respeto :)

      Eliminar
  3. Franmy Reynoso
    Mi pregunta es cuando ejecuto el crm configure load update Cluster_Mysql_Asterisk.cfg me da el error:
    ERROR: object drbd_fs does not exist
    ERROR: constraint Everything-with-Asterisk references a resource drbd_fs which doesn't exist
    ERROR: constraint Asterisk-after-Everything references a resource drbd_fs which doesn't exist
    element nvpair: Relax-NG validity error : Type ID doesn't allow value 'drbd-monitor-5-instance_attributes-ocf:heartbeat:Filesystem' creo que puede ser heratbeat-stonith que me esta causando problema pero no puedo quitarlo por que me da problema con el pacemaker.
    Alguna ayuda.!!!

    ResponderEliminar
    Respuestas
    1. Como el tutorial lo dice no debes instalar los paquetes stonith, de ahí que se excluyan. Siempre tienes la posibilidad de desinstalar e instalar las cosas con el manejador de paquetes.

      Por otro lado el error "ERROR: object drbd_fs does not exist" indica que el objeto drbd_fs no existe, quizás sea un problema del OCF en sí, verifica que exista.

      Eliminar
  4. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  5. Excelente Artículo.
    Esto se puede probar en un par de maquinas virtuales (Virtual Box) o en un par de máquinas virtuales en un sistema BLADE?? o es para servidores físicos ??

    O bien, se puede hacer con un servidor físico y uno virtual ?

    ResponderEliminar
    Respuestas
    1. Todas las anteriores mientras los equipos se vean en la red y estén bien configuados, como verás no se usa nada que sea dependiente de una sola arquitectura.

      Eliminar
    2. Excelente, muchas gracias.
      Voy a probar con un servidor físico y uno virtual (BLADE).

      Gracias.!

      Eliminar
    3. Los servidores deben de tener las mismas características de hardware ??
      Mismo tamaño de HDD, misma cantidad de memoria RAM, etc. ??

      Eliminar
  6. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  7. Ejecuto el comando crm configure load update Cluster_MySQL_Asterisk.cfg y me despliega lo siguiente:


    Traceback (most recent call last):
    File "/usr/sbin/crm", line 41, in ?
    crm.main.run()
    File "/usr/lib/python2.4/site-packages/crm/main.py", line 246, in run
    if parse_line(levels,shlex.split(' '.join(args))):
    File "/usr/lib/python2.4/site-packages/crm/main.py", line 144, in parse_line
    rv = d() # execute the command
    File "/usr/lib/python2.4/site-packages/crm/main.py", line 143, in
    d = lambda: cmd[0](*args)
    File "/usr/lib/python2.4/site-packages/crm/ui.py", line 1365, in load
    return set_obj.import_file(method,url)
    File "/usr/lib/python2.4/site-packages/crm/cibconfig.py", line 199, in import_file
    return self.save(s, method == "update")
    File "/usr/lib/python2.4/site-packages/crm/cibconfig.py", line 357, in save
    cli_list = cp.parse(cli_text)
    File "/usr/lib/python2.4/site-packages/crm/parse.py", line 655, in parse
    cli_list = parser_fn(s)
    File "/usr/lib/python2.4/site-packages/crm/parse.py", line 493, in parse_constraint
    return parse_location(s)
    File "/usr/lib/python2.4/site-packages/crm/parse.py", line 295, in parse_location
    numtoks,l = parse_rule(s[i:])
    File "/usr/lib/python2.4/site-packages/crm/parse.py", line 249, in parse_rule
    if not cli_parse_score(s[i],head_pl):
    IndexError: list index out of range

    ResponderEliminar
    Respuestas
    1. Al parecer tienes algun error con tu programa, esos errores no son de la configuración en sí.

      Eliminar
    2. Con cual programa ?
      con el asterisk en si ?

      Eliminar
    3. ¬¬
      Pues el que ejecutaste al final, que fue el "crm". Checa tus versiones o de plano reinstalalo ese problema nunca lo había visto.

      Eliminar
  8. muchas gracias amigo exelente tutorial, pero tengo una consulta al cargar la configuracion de CRM de da una seri de errores de sintaxis, me ayudaria saber que estooy haciendo mal, saludos.

    [root@nodoastr01 admin]# crm configure load update Cluster_Mysql_Asterisk.cfg
    ERROR: 5: syntax: fstype=ext3
    ERROR: 10: syntax: clone-node-max=1 notify=true
    ERROR: 13: syntax: pingd lte 0
    ERROR: 17: syntax in colocation: ClusterIP
    ERROR: 18: syntax: drbd_fs ) Asterisk
    ERROR: 19: syntax in order: ClusterIP
    ERROR: 20: syntax: drbd_fs ) Asterisk:start

    ResponderEliminar
    Respuestas
    1. Hay una diagonal de mas en el código lo cual provoca los errores, su tarea es descubrir cual es y quitarla ;)

      Eliminar