viernes, 20 de marzo de 2015

Error Courier IMAP y Outlook Express en Windows XP: actualizando courier-imap usando repositorios oneiric y wheezy "fijados" (pinned)

Aunque parezca mentira no sólo me quejo en este apartado de que aún haya clientes que sigan usando Windows XP (que de por sí es una irresponsabilidad). El problema en sí es que el sistema operativo del servidor también es anticuado.

Aunque estoy en proceso de migrar a Debian 7 (y en la mayoría de los casos a una configuración basada en ISPConfig) todos los viejos ubuntu server que tenía instalados (hace un par de años migré una ubuntu 10.04, el año pasado un par de ubuntus 12.04, etc), aún tengo un servidor que se resiste debido a que una de las páginas principales del cliente no funciona en versiones actuales de PHP, por lo que pasar de PHP 5.3 a 5.4 supone perder la funcionalidad del negocio y se considera una catástrofe.

Dejando a parte que actualizar dicha aplicación no sería demasiado costoso, tuve que actualizar el hardware y aproveché para hacerlo sobre una instalación limpia (y obsoleta, sin soporte ni actualizaciones de seguridad) de Ubuntu 11.10 Server (oneiric).

Hecha la locura (una espina que tengo clavada y que me costará tiempo quitarla) fui a migrar el servidor de correo y todo iba de maravilla hasta que uno de los clientes empezó a llamar alertado porque su cliente Outlook Express de Windows XP le decía que no podía descargar nuevos mensajes.

Hasta donde me alcanzaba la memoria recordé que ese fue un problema que ya pasamos y que tras buscar mucho por Internet solucioné instando una versión ligeramente superior de courier-imap. Se trataba de un bug conocido que habían arreglado en una versión posterior, por lo que de una instalación originalmente con estos paquetes:

ii  courier-base             0.66.1-1ubuntu3                 Courier mail server - base system
ii  courier-imap             4.9.1-1ubuntu3                  Courier mail server - IMAP server
ii  courier-imap-ssl         4.9.1-1ubuntu3                  Courier mail server - IMAP over SSL
ii  courier-ssl              0.66.1-1ubuntu3                 Courier mail server - SSL/TLS Support

Terminé dejando esto instalado en el servidor, sin recordar de dónde saqué los paquetes.

ii  courier-base             0.66.3-2                        Courier mail server - base system
ii  courier-imap             4.9.3-2                         Courier mail server - IMAP server
ii  courier-imap-ssl         4.9.3-2                         Courier mail server - IMAP over SSL
ii  courier-ssl              0.66.3-2                        Courier mail server - SSL/TLS Support

Mucho me temo, basándome en que ya no aparecen las palabras "ubuntu" en los paquetes, que generé los paquetes actualizados desde el código fuente y sólo instalé los paquetes DEB necesarios en el servidor. El problema es que de ello hace ya tanto tiempo que ya no dispongo de esos paquetes, ¡ni quiero tenerlos!, prefiero que se actualicen junto con el "sistema operativo" durante un apt-get update, aunque obviamente no voy a tener demasiadas actualizaciones.

¿Cómo hice la actualización en el nuevo servidor?: usar repositorios de oneiric y wheezy (debian 7) de manera simultánea.

Como he dicho, quería evitar usar paquetes generados desde las fuentes para evitar "tragarme" un agujero de seguridad que hubiera sido subsanado por una actualización. Con esta solución al menos el servidor de imap estará actualizado y al día.

¿Cómo se hace esta proeza? Fácil si seguimos las instrucciones que aparecen en la propia página de ubuntu: Pinning Howto

Para empezar definimos la distribución objetivo por defecto ("oneiric") en un archivo llamado, por ejemplo, /etc/apt/apt.conf.d/00default:

APT::Default-Release "oneiric";

Posteriormente configuramos el repositorio de Debian Wheezy (obtenido a través de este generador, cambiando "stable" por "wheezy" para evitar sorpresas en un futuro cercano) en /etc/apt/sources.list.d/wheezy.list:

deb http://ftp.es.debian.org/debian wheezy main

Creamos el archivo /etc/apt/preferences.d/wheezy.pref con el siguiente contenido:

Package: courier-imap courier-imap-ssl courier-base courier-ssl
Pin: release n=wheezy
Pin-Priority: 1000

Package: *
Pin: release n=wheezy
Pin-Priority: -1

Y posteriormente creamos el archivo /etc/apt/preferences.d/oneiric.pref con el siguiente contenido:

Package: *
Pin: release n=oneiric
Pin-Priority: 990

Hay que notar que en otros "howtos" de debian y apt-preferences fija las prioridades mediante la "suite" ("archive") a=stable, mientras que en la guía de ubuntu y mi solución usamos "codename" n=wheezy para ser homogéneos.

Bien, ¿qué son esas prioridades?

  • 1000: Toma preferencia sobre cualquier otra versión disponible de igual o superior versión. Sólo la prioridad 1001 permite bajar de versión un paquete previamente instalado. De este modo nos aseguraremos que la versión de los paquetes requeridos será la disponible en los repositorios de wheezy.
  • 990: Prioridad normal, con especial cuidado de que no será actualizado por ningún paquete que no sea de la distribución objetivo configurada. Sólo se instalarán paquetes nuevos y se actualizarán los existentes con aquellos pertenecientes a "oneiric".
  • -1: Sólo puedes instalar un paquete de este repositorio si manualmente lo indicas. Por ejemplo, se podría hacer un apt-get install traceroute/wheezy para forzar la instalación del traceroute disponible en wheezy, y no en oneiric.

Ahora basta con hacer un apt-get update para que se actualicen sólo los paquetes deseados a la versión disponible en los repositorios wheezy.

Solución alternativa 1: poniendo una prioridad a wheezy inferior a oneiric (por ejemplo 500 o 100) todo funcionaría igual con apt-get update (no se metería de manera automática un paquete más actual de wheezy). Sin embargo si hacemos un apt-get dist-upgrade podremos "liarla parda" ya que deja de hacer uso la distribución objetivo y usa las versiones de paquete más actuales, por lo que prefiero dejarle una prioridad -1.

Solución alternativa 2: dejando únicamente una prioridad -1 para wheezy y no configurando prioridad 1000 para los paquetes de courier deseados podríamos hacer una instalación "forzada" de los paquetes de wheezy usando el siguiente comando: apt-get install courier-ssl/wheezy courier-imap/wheezy courier-imap-ssl/wheezy courier-base/wheezy.

Al final todo ha quedado de la siguiente manera:

ii  courier-base             0.68.2-1                        Courier mail server - base system
ii  courier-imap             4.10.0-20120615-1               Courier mail server - IMAP server
ii  courier-imap-ssl         4.10.0-20120615-1               Courier mail server - IMAP over SSL
ii  courier-ssl              0.68.2-1                        Courier mail server - SSL/TLS Support

jueves, 19 de marzo de 2015

Courier maildrop: Cómo enviar los mensajes marcados como SPAM a la carpeta de correo no deseado

Gracias a ISPConfig estoy empezando a jugar con Dovecot y su filtrado gestionado por ManageSieve. Este servicio permite a los usuarios gestionar sus scripts de filtrado sin necesidad de tener acceso físico (FTP, SCP, WebDAV o similar) al sistema de archivos mediante un estándar que puede ser integrado en diferentes clientes (como roundcube, horde, thunderbird, etc).

Como en la actualidad mantengo algunos servidores con postfix+courier hasta ahora usaba un script de maildrop genérico que detecta el flag de SPAM que deja Spamassassin en los mensajes para enviarlos a una carpeta IMAP en particular (SPAM hasta hace poco). Como la mayoría de clientes de correo usan la carpeta "Junk" como destino de los correos marcados como SPAM, decidí cambiar dicho directorio de destino y, de paso, publicar el script para que otras personas puedan usarlo.

Este es el archivo /etc/maildroprc genérico que uso en esos servidores:

# Global maildrop filter file

# Uncomment this line to make maildrop default to ~/Maildir for
# delivery- this is where courier-imap (amongst others) will look.
#DEFAULT="$HOME/Maildir"

# Compruebo si es un correo con puntuación mayor de 25. En ese caso lo mando a
# una carpeta que periódicamente usa "spamassassin -r" para reportar a Pyzor,
# Razor, DCC e incluso Spamcop (luego los valido manualmente en su web) y no
# permito que llegue al destinatario.
if (/^X-Spam-Level: *\*{25,}/)
{
    DESTINO="/var/mail/cron.SPAM"
    # Compruebo si la carpeta existe y en caso contrario la creo
    exception {
        `test -d "$DESTINO"`
            if( $RETURNCODE == 1 )
            {
                `/usr/bin/maildirmake "$DESTINO"`
            }
    }
    to "$DESTINO"
}

# Si está marcado como SPAM (y tiene una puntuación inferior a 25) lo mando a
# la carpeta "Junk" del usuario.
if (/^X-Spam-Flag: *YES/)
{
    # Compruebo si la carpeta existe y en caso contrario la creo
    exception {
        `test -d "$DEFAULT/.Junk"`
            if( $RETURNCODE == 1 )
            {
                `/usr/bin/maildirmake "$DEFAULT/.Junk"`
            }
    }
    to "$DEFAULT/.Junk"
}

# Si no es ninguno de los dos casos anteriores lo tramito normalmente.
to "$DEFAULT"

Por hacer: tener un patrón genérico de correo electrónico y línea de comandos para probar el correcto funcionamiento de maildrop.

miércoles, 27 de febrero de 2013

Instalando un sintetizador de voz en castellano en Debian/Ubuntu (TTS - Text To Speech)

Me ha surgido la necesidad de un sintetizador de voz en castellano para generar voces con el contenido de un mensaje de alerta en nuestros servidores Ubuntu Server (en proceso de migración a Debian).

He decidido usar "festival", haciendo uso del paquete de voz en castellano "festvox-ellpc11k". El proceso de instalación es muy sencillo:

apt-get install festival festvox-ellpc11k

He visitado bastantes páginas de internet que recomiendan no usar "text2wave" para generar la voz por no poder cambiar de lenguaje (!) por lo que se complican la vida agregando un archivo ".festivalrc" que contiene el siguiente texto:

(Parameter.set 'Audio_Method 'Audio_Command)
(Parameter.set 'Audio_Command "cat $FILE > foo.raw")

Para generar un archivo de sonido necesitamos dos pasos:

  • Generar el archivo RAW:
    iconv -f utf-8 -t iso-8859-1 < archivo.txt | festival --language spanish --tts
  • Convertir el archivo RAW en WAV:
    sox -c 1 -r 11025 -s -2 foo.raw salida.wav

No digo que esté mal hacerlo así, pero tiene el inconveniente de no funcionar de manera correcta si realizamos dos conversiones paralelas. Ambas trabajarán en el archivo foo.raw, perdiéndose una de las dos conversiones de texto a voz.

Finalmente, investigando un poco, he preferido "forzar" la configuración de idioma pasándosela como parámentro a "text2wave" como comando LISP que se evaluará previo a la conversión.

Creando un script (llamado "texto_a_voz.sh", por ejemplo) con el siguiente contenido nos facilitará la tarea enormemente:

#!/bin/bash
/usr/bin/iconv -f utf-8 -t iso-8859-1 | /usr/bin/text2wave -eval "(language_castillian_spanish)"

Bastará con ejecutar la siguiente línea para, a partir de un archivo de texto de entrada en formato UTF-8, generar un archivo WAV de salida:

texto_a_voz.sh < archivo.txt > salida.wav

Si deseáramos pasar el archivo a MP3, por ejemplo, bastaría con agregar a la cadena "lame", con la opción "-S" si no queremos mensajes (modo silencioso), a la línea del comando:

texto_a_voz.sh < archivo.txt | lame -S - salida.mp3

Espero que os sea de utilidad.

jueves, 14 de febrero de 2013

Particionando tablas en Zabbix 2.0

Tras usar durante varios años en producción Zabbix 1.8 estamos migrando la plataforma a Zabbix 2.0 para realizar una limpieza de equipos, refinado de plantillas, etc.

Una de las cosas que deben hacerse para mejorar el rendimiento de la base de datos es deshabilitar el housekeeping integrado en Zabbix y realizar el borrado de datos usando particiones en las tablas históricas.

Si usamos una guía genérica de particionamiento de tablas basado en Zabbix 1.8 no nos funcionará debido al uso de claves foráneas en algunas tablas. Por desgracia, a día de hoy, MySQL (ni Percona) soporta claves foráneas al mismo tiempo que particionamiento de tablas, por lo que la solución que propondremos aquí eliminará de forma permanente dichas relaciones.

Primer paso: Eliminar claves foráneas

# Tabla "acknowledges"
ALTER TABLE `acknowledges`
 DROP FOREIGN KEY `c_acknowledges_2`,
 DROP FOREIGN KEY `c_acknowledges_1`;

# Tabla "alerts"
ALTER TABLE `alerts`
 DROP FOREIGN KEY `c_alerts_4`,
 DROP FOREIGN KEY `c_alerts_1`,
 DROP FOREIGN KEY `c_alerts_2`,
 DROP FOREIGN KEY `c_alerts_3`;

# Tabla "auditlog"
ALTER TABLE `auditlog`
 DROP FOREIGN KEY `c_auditlog_1`;

# Tabla "auditlog_details"
ALTER TABLE `auditlog_details`
 DROP FOREIGN KEY `c_auditlog_details_1`;

# Tabla "service_alarms"
ALTER TABLE `service_alarms`
 DROP FOREIGN KEY `c_service_alarms_1`;

Segundo paso: Cambio de claves primarias

ALTER TABLE `acknowledges` DROP PRIMARY KEY, ADD KEY `acknowledgedid` (`acknowledgeid`);
ALTER TABLE `alerts` DROP PRIMARY KEY, ADD KEY `alertid` (`alertid`);
ALTER TABLE `auditlog` DROP PRIMARY KEY, ADD KEY `auditid` (`auditid`);
ALTER TABLE `events` DROP PRIMARY KEY, ADD KEY `eventid` (`eventid`);
ALTER TABLE `service_alarms` DROP PRIMARY KEY, ADD KEY `servicealarmid` (`servicealarmid`);
ALTER TABLE `history_log` DROP PRIMARY KEY, ADD PRIMARY KEY (`itemid`,`id`,`clock`);
ALTER TABLE `history_log` DROP KEY `history_log_2`;
ALTER TABLE `history_text` DROP PRIMARY KEY, ADD PRIMARY KEY (`itemid`,`id`,`clock`);
ALTER TABLE `history_text` DROP KEY `history_text_2`;

Tercer paso: Obtener fechas iniciales para particiones

SET @SEMANA= DATE_ADD(NOW(), INTERVAL 1 WEEK);
SET @F_SEMANA = DATE_FORMAT(@SEMANA, '%Y-%m-%d');
SET @P_SEMANA= CONCAT('p', DATE_FORMAT(@SEMANA, '%x%v'));
SELECT @F_SEMANA, @P_SEMANA;
SET @DIA= DATE_ADD(NOW(), INTERVAL 1 DAY);
SET @F_DIA = DATE_FORMAT(@DIA, '%Y-%m-%d');
SET @P_DIA= CONCAT('p', DATE_FORMAT(@DIA, '%Y%m%d'));
SELECT @F_DIA, @P_DIA;

Cuarto paso: Crear particiones semanales

# Formato de fecha PHP "oW"/'%x%v'
ALTER TABLE `acknowledges` PARTITION BY RANGE( clock ) ( PARTITION pYYYYss VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `alerts` PARTITION BY RANGE( clock ) ( PARTITION pYYYYss VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `events` PARTITION BY RANGE( clock ) ( PARTITION pYYYYss VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `auditlog` PARTITION BY RANGE( clock ) ( PARTITION pYYYYss VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `events` PARTITION BY RANGE( clock ) ( PARTITION pYYYYss VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `service_alarms` PARTITION BY RANGE( clock ) ( PARTITION pYYYYss VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `trends` PARTITION BY RANGE( clock ) ( PARTITION pYYYYss VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `trends_uint` PARTITION BY RANGE( clock ) ( PARTITION pYYYYss VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );

ALTER TABLE `acknowledges` PARTITION BY RANGE( clock ) ( PARTITION p201308 VALUES LESS THAN (UNIX_TIMESTAMP("2013-02-21 00:00:00")) );

Quinto paso: Crear particiones diarias

ALTER TABLE `history` PARTITION BY RANGE( clock ) ( PARTITION pYYYYmmdd VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `history_log` PARTITION BY RANGE( clock ) ( PARTITION pYYYYmmdd VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `history_str` PARTITION BY RANGE( clock ) ( PARTITION pYYYYmmdd VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `history_text` PARTITION BY RANGE( clock ) ( PARTITION pYYYYmmdd VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );
ALTER TABLE `history_uint` PARTITION BY RANGE( clock ) ( PARTITION pYYYYmmdd VALUES LESS THAN (UNIX_TIMESTAMP("XXXXXXXXXX 00:00:00")) );

ALTER TABLE `history` PARTITION BY RANGE( clock ) ( PARTITION p20130215 VALUES LESS THAN (UNIX_TIMESTAMP("2013-02-15 00:00:00")) );

lunes, 18 de junio de 2012

Notas sobre DRBD y el cluster proyectado

La idea original de usar DRBD y OCFS2 funciona muy bien bajo una carga que no sea excesiva y sin muchos "syncs" (las bases de datos sqlite suelen hacerlos de manera frecuente) en el sistema de archivos.

El cluster de pruebas estuvo activo durante más de 6 meses funcionando muy bien, pero observé fallos de rendimiento que he terminado por subsanar pasando el sistema de archivos a una tercera máquina con OpenNAS. No me ha sido posible convencer a los usuarios para que dejen de usar bases de datos basados en archivos (sqlite), por lo que el cambio fue casi obligado.

Voy a retomar el artículo para terminar con el proceso de instalación original usando DRBD y posteriormente haré un artículo para mejorar el rendimiento usando un almacenamiento iSCSI externo.

Por último, el cluster lo monté originalmente en Ubuntu Server 10.04. Estoy planteándome migrar a Debian 6 o a Ubuntu Server 12.04. Cuando confirme mi decisión postearé igualmente cualquier modificación que se deba aplicar a lo ya escrito.

Siento haberme demorado en la documentación de la instalación :) entre mi reciente paternidad, mi creciente carga de trabajo y los exámenes de la universidad no he tenido apenas tiempo. Ahora en verano tendré más tiempo libre para retomar estos temas.

domingo, 20 de noviembre de 2011

Cluster de alta disponibilidad y balanceo de carga Apache + PHP + MySQL con sólo dos máquinas (Primera parte)

Introducción

Tras poner en producción un cluster de estas características para mi empresa, decido publicar una serie de artículos que ilustrarán cómo montar una arquitectura similar y para que todo el mundo que lo desee pueda disfrutar de un aumento de rendimiento en sus aplicaciones LAMP.

Lo ideal sería separar las máquinas que ejecutan PHP y Apache de las máquinas que almacenan las páginas web y el servidor de bases de datos. Posiblemente haciendo esto se solucionen la mayoría de problemas de rendimiento que tienen la gran mayoría de las instalaciones LAMP.

¿Cómo mejoro el rendimiento en mi instalación LAMP actual?

Antes de decidir montar un cluster de alta disponibilidad y balanceo de carga tenemos que tener muy claro que no podemos sacarle mayor rendimiento a la arquitectura actual. Para ello debemos hacernos las siguientes preguntas:

¿Dónde tenemos el cuello de botella en nuestra instalación hardware?

Dependiendo de dónde esté el cuello de botella (aquél elemento que ralentiza en mayor grado la ejecución de nuestros scripts) debemos aumentar el hardware de nuestros servidores para mejorar lo máximo posible el problema.

Podemos destacar los siguientes cuellos de botella hardware:

  • CPU: Que se esté usando la CPU al 100% (nice + idle + user + system) en nuestra máquina es una buena señal ya que significa que tenemos bien dimensionada nuestra máquina en memoria y disco duro y que si no es capaz de procesar un mayor número de peticiones es por falta de potencia de procesamiento. También puede ser un indicador de que nuestros scripts PHP no están optimizados todo lo que debieran. En algunos casos es posible aumentar la CPU sin tener que cambiar el resto del hardware (placa madre, memoria, etc), pero no siempre es así. El balanceo de carga que propondremos en esta arquitectura solucionará este problema drásticamente permitiendo, a su vez, escalar tanto como deseemos la potencia de cálculo del cluster cada vez que sea necesario.
  • Memoria: Cuando los procesos agotan la memoria RAM y empiezan a hacer uso del área de intercambio el rendimiento general del servidor decae radicalmente debido a que cualquier tipo de entrada salida (búsqueda de una imagen desde el servidor web, búsqueda de datos desde el servidor MySQL, acceso a datos en disco desde un script PHP, etc) se ve ralentizado por las constantes entradas y salidas de datos de memoria a intercambio y viceversa. Generalmente podemos saber cuándo está un servidor perdiendo rendimiento debido a este motivo observando que la memoria RAM libre y la caché de disco es muy baja y, sin embargo, tanto el uso de memoria de intercambio ha aumentado como el número de procesos esperando la finalización de un proceso de entrada/salida (iowait). Aumentar la memoria RAM de un servidor suele ser mucho más sencillo y barato que aumentar la RAM y deberemos hacerlo tanto como podamos antes de montar el clustar. Usar un cluster de balanceo de carga permitirá repartir el consumo de RAM de algunos procesos PHP mientras que otros usos de memoria RAM no se podrán reducir o evitar (caché de índices, consultas, etc del servidor MySQL, por ejemplo).
  • Disco duro: Hay que tener en cuenta que una aplicación que haga uso intensivo del almacenamiento (cálculo de la firma MD5, creación o lectura de un archivo muy grande, etc) podría provocar la ralentización de todo el sistema de manera similar a cuando entramos en paginación. La diferencia radica en que un proceso que haga uso intensivo de disco tendrá un tiempo de ejecución acotado (si nuestra aplicación está bien diseñada) mientras que un estado de paginación por falta de memoria RAM se producirá durante largos periodos de tiempo. Hay que procurar que se use lo mínimo posible de manera intensiva el almacenamiento compartido (afectará al rendimiento del cluster). Como cada servidor MySQL funciona con su réplica de datos local, un uso intensivo puntual de una de las máquinas no afectará a la otra. Para mejorar el rendimiento de E/S de datos se recomienda el uso de discos de estado sólido (SSD) o el uso de RAID 5 para mejorar sensiblemente la tasa de transferencia a la vez que se agrega redundancia (es importante mantener a salvo los datos en caso de fallo de uno de los discos).

¿Qué arquitectura de cluster vamos a montar?

El objetivo de este pequeño proyecto es ofrecer los servicios de procesamiento, almacenamiento, bases de datos, etc de manera autónoma en sólo dos máquinas proporcionando alta disponibilidad sin hacer uso de servicios externos:
  • No disponemos de almacenamiento SAN (Network Attached Storage).
  • No podemos tener máquinas separadas para el servidor MySQL, servidor HTTP, servidor de archivos, etc.
Esto nos deja la siguiente propuesta de arquitectura:
  • Gestor de Recursos del Cluster (CRM): Usaremos heartbeat y pacemaker. Nos proporcionará monitorización de los recursos para mover la IP virtual de servicio a aquella máquina que esté funcional.
  • Servidor web: Usaremos un servidor apache en cada máquina sirviendo páginas web con soporte para ejecutar scripts PHP.
  • Acelerador web: Usaremos squid como acelerador web para descargar la carga del servidor web real y, a su vez, realizar la función de balanceador de carga solicitando una petición a cada servidor web real mediante un esquema de peticiones round-robin.
  • Almacenamiento compartido: Usaremos DRBD para replicar la información entre dos volúmenes lógicos, proporcionando redundancia en caso de caída de un nodo o bien fallo catastrófico de los discos duros de una de las máquinas, y OCFS2 para proporcionar un acceso concurrente a los datos de dicho dispositivo replicado.
  • Servidor de bases de datos: Usaremos MySQL por ser su uso el más extendido entre aplicaciones PHP. A su vez usaremos un esquema de replicación circular para proporcionar una mayor disponibilidad de los datos y minimizar el tiempo de recuperación de servicio en caso de caída de un nodo (aunque ello no implica consistencia como veremos más adelante en los "contras").
En la próxima entrega comenzaremos montando el sistema de archivos compartido donde alojaremos las páginas web de los usuarios.

viernes, 16 de julio de 2010

Ubuntu server 10.04 LTS en castellano bajo OpenVZ

La forma más fácil de crear una máquina virtual bajo Linux es usando el sistema de virtualización proporcionada por OpenVZ.

El único problema que plantea esta manera de instalar máquinas virtuales es que las plantillas están configuradas por defecto con zonas horarias, idiomas, etc que no nos interesan.

En este documento instalaremos una plantilla de Ubuntu server 10.04 LTS y la configuraremos para que use tanto la configuración local española como su zona horaria. Presupondremos instalado y funcionando OpenVZ en el sistema anfitrión.

El primer paso será descargar la plantilla de http://download.openvz.org/template/precreated/ y colocarla en la ruta adecuada:

root@anibal:~# wget -O "/var/lib/vz/template/cache/ubuntu-10.04-x86.tar.gz" "http://download.openvz.org/template/precreated/ubuntu-10.04-x86.tar.gz"
--09:01:21-- http://download.openvz.org/template/precreated/ubuntu-10.04-x86.tar.gz
=> '/var/lib/vz/template/cache/ubuntu-10.04-x86.tar.gz'
Resolviendo download.openvz.org... 64.131.90.11
Conectando a download.openvz.org|64.131.90.11|:80... conectado.
Petición HTTP enviada, esperando respuesta... 200 OK
Longitud: 137,211,613 (131M) [application/x-gzip]

100%[==============================================>] 137,211,613 1.88M/s ETA 00:00

09:02:15 (2.41 MB/s) - `/var/lib/vz/template/cache/ubuntu-10.04-x86.tar.gz' guardado [137211613/137211613]

El segundo paso es crear la máquina virtual usando la plantilla que acabamos de descargar. Hay que fijarse que en el parámetro --ostemplate se omite la extensión ".tar.gz" de la plantilla:

root@anibal:~# vzctl create 100 --ostemplate ubuntu-10.04-x86 --ipadd 10.0.0.100 --hostname equipo100
Creating VE private area (ubuntu-10.04-x86)
Performing postcreate actions
VE private area was created

Ahora deberemos configurar algunos aspectos de la máquina virtual, iniciarla y cambiarle la clave de root:

root@anibal:~# vzctl set 100 --nameserver 10.0.0.1 --save
Saved parameters for VE 100
root@anibal:~# vzctl set 100 --onboot yes --save
Saved parameters for VE 100
root@anibal:~# vzctl start 100
Starting VE ...
VE is mounted
Adding IP address(es): 10.0.0.100
Setting CPU units: 1000
Configure meminfo: 65536
Set hostname: equipo100
File resolv.conf was modified
VE start in progress...
root@anibal:~# vzctl exec 100 passwd
Enter new UNIX password: nuevaclave
Retype new UNIX password: nuevaclave
passwd: password updated successfully

Tras esto DEBEREMOS loguearnos usando ssh en la máquina remota para continuar nuestro trabajo: instalar los paquetes necesarios para poder trabajar en castellano. Recomiendo ENCARECIDAMENTE que el resto de trabajo se realice bajo una conexión SSH y no con el comando "vzctl enter 100" para que se aplique correctamente la configuración local al usuario.

root@anibal:~# ssh 10.0.0.100
The authenticity of host '10.0.0.100 (10.0.0.100)' can't be established.
RSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.0.0.100' (RSA) to the list of known hosts.
root@10.0.0.100's password:
Linux equipo100 2.6.24-28-openvz #1 SMP Thu May 27 04:04:37 UTC 2010 i686 GNU/Linux
Ubuntu 10.04 LTS

Welcome to Ubuntu!
* Documentation: https://help.ubuntu.com/

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.*/

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

root@equipo100:~# apt-get update
Get:1 http://archive.ubuntu.com lucid Release.gpg [189B]
Get:2 http://archive.ubuntu.com lucid-updates Release.gpg [189B]
Get:3 http://archive.ubuntu.com lucid-security Release.gpg [189B]
Get:4 http://archive.ubuntu.com lucid Release [57.2kB]
Get:5 http://archive.ubuntu.com lucid-updates Release [44.7kB]
Get:6 http://archive.ubuntu.com lucid-security Release [38.5kB]
Get:7 http://archive.ubuntu.com lucid/main Packages [1386kB]
Get:8 http://archive.ubuntu.com lucid/restricted Packages [6208B]
Get:9 http://archive.ubuntu.com lucid/universe Packages [5448kB]
Get:10 http://archive.ubuntu.com lucid-updates/main Packages [259kB]
Get:11 http://archive.ubuntu.com lucid-updates/restricted Packages [3252B]
Get:12 http://archive.ubuntu.com lucid-updates/universe Packages [74.9kB]
Get:13 http://archive.ubuntu.com lucid-security/main Packages [48.9kB]
Get:14 http://archive.ubuntu.com lucid-security/restricted Packages [14B]
Get:15 http://archive.ubuntu.com lucid-security/universe Packages [24.5kB]
Fetched 7392kB in 15s (478kB/s)
Reading package lists... Done
root@equipo100:~# apt-cache search language | grep \\-es
kde-l10n-es - Spanish (es) localization for KDE
language-support-es - metapackage for Spanish; Castilian language support
language-support-writing-es - Writing aids metapackage for Spanish; Castilian
openoffice.org-l10n-es - office productivity suite -- Spanish language package
thunderbird-locale-es-ar - Thunderbird Spanish; Castilian language/region package
thunderbird-locale-es-es - Thunderbird Spanish; Castilian language/region package
apertium-es-ca - Apertium linguistic data to translate between Spanish and Catalan
apertium-es-gl - Apertium linguistic data to translate between Spanish and Galician
apertium-es-pt - Apertium linguistic data to translate between Spanish and Portuguese
apertium-es-ro - Apertium linguistic data to translate between Spanish and Romanian
apertium-eu-es - Apertium linguistic data to translate between Basque and Spanish
enigmail-locale-es-es - Spanish (ES) language package for Enigmail
erlang-esdl - Erlang bindings to the Simple Direct Media Library
maint-guide-es - Spanish translation of Debian New Maintainers Guide
python-espeak - Python bindings for eSpeak
sword-language-pack-es - Sword modules for the Spanish language
language-pack-es - translation updates for language Spanish; Castilian
language-pack-es-base - translations for language Spanish; Castilian
language-pack-gnome-es - GNOME translation updates for language Spanish; Castilian
language-pack-gnome-es-base - GNOME translations for language Spanish; Castilian
language-pack-kde-es - KDE translation updates for language Spanish; Castilian
language-pack-kde-es-base - KDE translations for language Spanish; Castilian
root@equipo100:~# apt-cache search manpages | grep \\-es
manpages-es - Spanish man pages
manpages-es-extra - Spanish extra manpages

A continuación instalamos los paquetes que nos proporcionarán la traducción al castellano del sistema:

root@equipo100:~# apt-get install language-pack-es manpages-es manpages-es-extra
Reading package lists... Done
Building dependency tree... Done
The following extra packages will be installed:
language-pack-es-base
Suggested packages:
language-support-es
The following NEW packages will be installed:
language-pack-es language-pack-es-base manpages-es manpages-es-extra
0 upgraded, 4 newly installed, 0 to remove and 3 not upgraded.
Need to get 6483kB of archives.
After this operation, 21.8MB of additional disk space will be used.
Do you want to continue [Y/n]? y
Get:1 http://archive.ubuntu.com/ubuntu/ lucid-updates/main language-pack-es-base 1:10.04+20100422 [4263kB]
Get:2 http://archive.ubuntu.com/ubuntu/ lucid-updates/main language-pack-es 1:10.04+20100422 [2040B]
Get:3 http://archive.ubuntu.com/ubuntu/ lucid/universe manpages-es 1.55-9 [1542kB]
Get:4 http://archive.ubuntu.com/ubuntu/ lucid/universe manpages-es-extra 0.8a-16 [676kB]
Fetched 6483kB in 13s (475kB/s)
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LANG = "es_ES.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
Preconfiguring packages ...
Selecting previously deselected package language-pack-es-base.
(Reading database ... 21602 files and directories currently installed.)
Unpacking language-pack-es-base (from .../language-pack-es-base_1%3a10.04+20100422_all.deb) ...
Selecting previously deselected package language-pack-es.
Unpacking language-pack-es (from .../language-pack-es_1%3a10.04+20100422_all.deb) ...
Selecting previously deselected package manpages-es.
Unpacking manpages-es (from .../manpages-es_1.55-9_all.deb) ...
Selecting previously deselected package manpages-es-extra.
Unpacking manpages-es-extra (from .../manpages-es-extra_0.8a-16_all.deb) ...
Setting up manpages-es (1.55-9) ...
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LANG = "es_ES.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory

Setting up manpages-es-extra (0.8a-16) ...
To enable these manpages set LC_MESSAGES to 'es' (or es_ZZ where ZZ is your
contry code). Man will then search for Spanish manpages under
/usr/share/man/es.

Para activar estas p▒ginas de manual ponga LC_MESSAGES a 'es'
(o es_ZZ donde ZZ es el c▒digo de su pais). Man buscar▒ sus
p▒ginas bajo /usr/share/man/es.

Setting up language-pack-es (1:10.04+20100422) ...
Setting up language-pack-es-base (1:10.04+20100422) ...
Generating locales...
es_AR.UTF-8... done
es_BO.UTF-8... done
es_CL.UTF-8... done
es_CO.UTF-8... done
es_CR.UTF-8... done
es_DO.UTF-8... done
es_EC.UTF-8... done
es_ES.UTF-8... done
es_GT.UTF-8... done
es_HN.UTF-8... done
es_MX.UTF-8... done
es_NI.UTF-8... done
es_PA.UTF-8... done
es_PE.UTF-8... done
es_PR.UTF-8... done
es_PY.UTF-8... done
es_SV.UTF-8... done
es_US.UTF-8... done
es_UY.UTF-8... done
es_VE.UTF-8... done
Generation complete.

Ahora, con los paquetes adecuados instalados sólo nos queda un único paso para tener en castellano nuestra ubuntu server: configurar la configuración local. Para ello tecleamos:

root@equipo100:~# update-locale LANG="es_ES.UTF-8" LANGUAGE="es_ES.UTF-8" LC_ALL="es_ES.UTF-8"

Antes de reiniciar nuestra máquina para comprobar que todo ha quedado bien procederemos a configurar la zona horaria:

root@equipo100:~# dpkg-reconfigure tzdata

Nos aparecerá un listado de contenientes en el que deberemos seleccionar "Europe":

Configuración de paquetes

┌───────────────────────┤ Configuración de tzdata ├───────────────────────┐
│ Please select the geographic area in which you live. Subsequent │
│ configuration questions will narrow this down by presenting a list of │
│ cities, representing the time zones in which they are located. │
│ │
│ Geographic area: │
│ │
│ Africa ↑ │
│ America ▒ │
│ Antarctica ▒ │
│ Australia ▒ │
│ Arctic ▮ │
│ Asia ▒ │
│ Atlantic ▒ │
│ Europe ▒ │
│ Indian ↓ │
│ │
│ │

│ │
└─────────────────────────────────────────────────────────────────────────┘

Tras elegir Europa, deberemos seleccionar "Madrid" en el siguiente listado de localizaciones:

Configuración de paquetes

┌────────────────────┤ Configuración de tzdata ├─────────────────────┐
│ Please select the city or region corresponding to your time zone. │
│ │
│ Time zone: │
│ │
│ Kiev ↑ │
│ Lisboa ▒ │
│ Liubliana ▒ │
│ Londres ▒ │
│ Luxemburgo ▮ │
│ Madrid ▒ │
│ Malta ▒ │
│ Mariehamn ▒ │
│ Minsk ▒ │
│ Mónaco ▒ │
│ Moscú ↓ │
│ │
│ │

│ │
└────────────────────────────────────────────────────────────────────┘

Tras configurar la zona horaria nos aparecerá la hora actual para confirmarnos que todo ha ido bien:

Current default time zone: 'Europe/Madrid'
Local time is now: Fri Jul 16 11:45:47 CEST 2010.
Universal Time is now: Fri Jul 16 09:45:47 UTC 2010.

Tras salir y entrar de nuevo a través de SSH veremos que todo (o casi todo) aparece en castellano. Podemos probar el resultado de un "apt-get update" o consultar una página del manual con "man ls" para comprobarlo:

root@anibal:~# ssh 10.0.0.100
root@10.0.0.100's password:
Linux equipo100 2.6.24-28-openvz #1 SMP Thu May 27 04:04:37 UTC 2010 i686 GNU/Linux
Ubuntu 10.04 LTS

Welcome to Ubuntu!
* Documentation: https://help.ubuntu.com/
Last login: Fri Jul 16 09:30:37 2010 from anibal
root@equipo100:~# apt-get update
Obj http://archive.ubuntu.com lucid Release.gpg
Des:1 http://archive.ubuntu.com/ubuntu/ lucid/main Translation-es [658kB]
Des:2 http://archive.ubuntu.com/ubuntu/ lucid/restricted Translation-es [2779B]
Des:3 http://archive.ubuntu.com/ubuntu/ lucid/universe Translation-es [1393kB]
Obj http://archive.ubuntu.com lucid-updates Release.gpg
Ign http://archive.ubuntu.com/ubuntu/ lucid-updates/main Translation-es
Ign http://archive.ubuntu.com/ubuntu/ lucid-updates/restricted Translation-es
Ign http://archive.ubuntu.com/ubuntu/ lucid-updates/universe Translation-es
Obj http://archive.ubuntu.com lucid-security Release.gpg
Ign http://archive.ubuntu.com/ubuntu/ lucid-security/main Translation-es
Ign http://archive.ubuntu.com/ubuntu/ lucid-security/restricted Translation-es
Ign http://archive.ubuntu.com/ubuntu/ lucid-security/universe Translation-es
Obj http://archive.ubuntu.com lucid Release
Obj http://archive.ubuntu.com lucid-updates Release
Obj http://archive.ubuntu.com lucid-security Release
Obj http://archive.ubuntu.com lucid/main Packages
Obj http://archive.ubuntu.com lucid/restricted Packages
Obj http://archive.ubuntu.com lucid/universe Packages
Obj http://archive.ubuntu.com lucid-updates/main Packages
Obj http://archive.ubuntu.com lucid-updates/restricted Packages
Obj http://archive.ubuntu.com lucid-updates/universe Packages
Obj http://archive.ubuntu.com lucid-security/main Packages
Obj http://archive.ubuntu.com lucid-security/restricted Packages
Obj http://archive.ubuntu.com lucid-security/universe Packages
Descargados 2054kB en 7s (293kB/s)
Leyendo lista de paquetes... Hecho
root@equipo100:~#