lunes, 8 de julio de 2013

Tutorial: Restaurar una unidad de RAID con un disco de menor capacidad.

Hace mucho que no escribo, así que decidí agregar un artículo técnico que le dé algo de valor a este intento de blog, haciendo que no parezca abandonado. Acá les dejo un nuevo tutorial entonces. Disfrútenlo.


Siempre que instalo un servidor me gusta poder utilizar hardware de buena calidad, aunque a veces los clientes quieren aprovechar equipamiento que no puede utilizarse con la última versión de ese conocido "sistema operativo de escritorio que ahora pretende convertir un PC en un celular" (practicamente cualquier cosa fabricada antes del 2008), lo cual muchas veces lleva a que se trabaje con equipamiento de cierta edad y/o de confiabilidad dudosa, y en algunos casos cuya obsolescencia representa un riesgo a corto o mediano plazo, dado que es dificil encontrar piezas de reemplazo para efectuar reparaciones básicas y mantener su ciclo de funcionamiento más allá del ya definido por el fabricante.

Supongo que siendo que en Uruguay no se fabrican computadoras ni componentes, no es dificil de entender que todos queramos que nuestro hardware supere su expectativa de vida, limitada por la obsolescencia planificada a la que es sometido por los fabricantes...

Independientemente de la calidad del hardware disponible, siempre exijo que se cumplan ciertos requisitos que disminuyen la probabilidad de fallos terminales en los equipos, como por ejemplo unidades de disco redundantes (RAID).

A pesar de mis intentos de obtener lo que considero esencial siempre, con frecuencia sucede que cuando me dan los equipos para comenzar la instalación, alguien olvidó agregare el disco adicional para armar el RAID, con lo cual a veces se generan esperas innecesarias. En ese caso, suelo crear las unidades de RAID por software en forma independiente a la instalación, e instalar luego, haciendole creer al sistema que está usando una unidad de RAID degradada. Eso me permite instalar el servidor sin esperas, y luego solo agregarle el disco faltante reconstruyendo las unidades de RAID cuando las condiciones así lo permitan (muchas veces estando los servidores en producción).

Para crear las unidades de RAID antes de instalar el sistema operativo, simplemente se carga un CD/DVD de rescate, se crean las particiones y luego se crean las unidades de RAID necesarias con la herramienta mdadm:
mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sda2 missing
Esta línea de comandos permite crear una unidad de RAID de nivel 1 por software, formado por dos unidades de disco (en realidad, formado por particiones de los discos), pero declarando la segunda partición como "no existente". De esa forma, aseguramos la creación de la unidad de RAID sin necesidad de tener los dos discos duros instalados.

Una vez que vamos a instalar el sistema operativo, lo único que tenemos que tener en cuenta es que utilizaremos como particiones las unidades de RAID creadas (sean cuantas sean). Cuando recibimos el disco faltante, simplemente lo particionamos y reconstruimos las unidades de RAID para que las mismas queden en el estado de consistencia que las hace útiles. Si no recibimos el otro disco duro, simplemente podemos dejar el servidor con las unidades degradadas, aunque obviamente la falta de redundancia hará que cualquier fallo físico en el único disco que el servidor tiene sea fatal para el sistema, o por lo menos, genere un downtime no programado, algo que no es precisamente apreciado por clientes y usuarios.

Hace unos días tuve que instalar un servidor que había traído un único disco duro de 80 GB (específicamente un Western Digital WDC WD800BD-22JM, de exactamente 80.026.361.856 de bytes de espacio disponible).

Decidí no esperar por el segundo disco, así que particioné el disco e instalé el sistema operativo, usando la técnica de creación de unidades de RAID L1 por software manualmente. Esta técnica dejó el sistema con este "layout":
srv:~ # fdisk -l
Disk /dev/sda: 80.0 GB, 80026361856 bytes
255 heads, 63 sectors/track, 9729 cylinders, total 156301488 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x4e3acf1a

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048      411647      204800   83  Linux
/dev/sda2          411648     8800255     4194304   fd  Linux raid autodetect
/dev/sda3         8800256   156301487    73750616   fd  Linux raid autodetect
La primera partición la uso para el /boot (cerca de 200MB), y las otras las utilizo como particiones origen para crear dos unidades de RAID separadas, una para el raiz del sistema (75 GB)y la otra como SWAP (4 GB).

Las unidades de RAID, una vez creadas, son estas:
srv:~ # cat /proc/mdstat
Personalities : [raid0] [raid1] [raid10] [raid6] [raid5] [raid4]
md0 : active raid1 sda3[0]
      73749520 blocks super 1.2 [2/1] [U_]
      bitmap: 1/1 pages [4KB], 65536KB chunk

md1 : active raid1 sda2[0]
      4193268 blocks super 1.2 [2/1] [U_]
      bitmap: 1/1 pages [4KB], 65536KB chunk

unused devices: 
srv:~ #
Todo estaba perfecto, hasta que recibí el segundo disco... un Hitachi HDS728080PLA380 (de 80.000.000.000 de bytes de capacidad).

Esto representa un verdadero problema, dado que más allá de las obvias diferencias de marca y modelo, hay una diferencia significativa en la capacidad del disco, lo cual afecta la viabilidad del proceso de reconstrucción. Hacen falta 26361856 de bytes para poder considerar usar ese disco como destino de las unidades de RAID, y mantener el mismo exacto layout, como debería ser el caso ideal.

Otro detalle que cabe tomar en cuenta es que al ser distintos los discos, la performance se podría ver afectada por la diferencia de velocidades de acceso, lectura, escritura y búsqueda entre los discos, sin contar con el ancho de banda y la capacidad de los buffers. Básicamente, al igual que en una red donde participan dos dispositivos con diferentes capacidades de transferencia, el más lento es el que establece los niveles máximos alcanzables, así que la performance global dependerá, obviamente, del disco más lento.

Como prueba base para saber cual de los dos discos es el más lento (suponiendo que eso fuera realmente una condición determinante), se puede usar la herramienta hdparm:
srv:~ # hdparm -tT /dev/sda

/dev/sda:
 Timing cached reads:   5322 MB in  2.00 seconds = 2663.04 MB/sec
 Timing buffered disk reads: 174 MB in  3.02 seconds =  57.65 MB/sec
srv:~ # hdparm -tT /dev/sdb

/dev/sdb:
 Timing cached reads:   5308 MB in  2.00 seconds = 2656.07 MB/sec
 Timing buffered disk reads: 168 MB in  3.03 seconds =  55.49 MB/sec
srv:~ #
Como puede verse, existe una leve diferencia en la velocidad de transferencia, aunque no es tan grave como para ser un factor determinante en cuanto a la viabilidad del disco en sí, o sea que el problema se reduciría solo a la diferencia de capacidad.

Debe notarse que el problema de la diferencia de tamaños en los discos no sería tan importante si se hubiera utilizado LVM, cosa que no se hizo dado que el servicio que este equipo provée es el de interconexión de redes (se trata de un router con capacidades avanzadas de firewalling) y no se espera que el esquema de particionamiento o las necesidades de almacenamiento cambien en el tiempo. LVM provée flexibilidad en el uso de las unidades de almacenamiento, pero para un equipo cuyo sistema de almacenamiento no va a cambiar, no es extremadamente necesario utilizarlo.

Llegado a este punto, pude simplemente descartar el disco y pedir otro que fuera de mayor capacidad, pero preferí hacer de este problema una oportunidad educativa para mi y para otros, así que decidí elaborar un procedimiento que me permitiera utilizar este disco de todas maneras.

ADVERTENCIA: El procedimiento que está a punto de leer asume que el operador tiene sólidos conocimientos técnicos sobre el uso de ciertas herramientas que pueden ser peligrosas para el sistema en caso de un error inadvertido. Niños, no lo hagan en sus casas sin la compañía, el consejo o (cómo mínimo) el teléfono de un sysadmin hábil a mano... y por sobre todas las cosas, si meten la pata, ¡no sucumban al pánico!

Las reglas que decidí que regirían el procedimiento son las siguientes:
  1. Siendo que el servidor está en producción, el procedimiento debe realizarse sin afectar el servicio que el mismo provee.
  2. Como el disco principal es mayor que el nuevo disco, es imperativo modificar el formato de las particiones del disco principal para organizar el espacio disponible y que las particiones queden iguales en los dos discos. Esto ademas proveerá elegancia a la solución, dado que el formato de las particiones quedará lo más parecido posible.
  3. El procedimiento debe poder ser ejecutado en forma remota, de manera de poder ser realizado en cualquier horario, sin representar un problema para mi o para el cliente.
Como el servidor está en producción, no es posible disminuir el tamaño de la partición raiz del sistema para que quede igual al espacio que tendría la partición correlativa del segundo disco (que sería la solución más simple), así que decidí modificar la partición que correspondería a la unidad RAID asignada al SWAP (/dev/md1, la cual utiliza la partición /dev/sda2), haciendo que su tamaño disminuya como para poder compensar la diferencia de tamaño entre los discos y permitir crear una partición en el disco /dev/sdb de tamaño suficiente como para ser capaz de asignarse a /dev/md0, permitiendo la reconstrucción de la unidad.

El procedimiento detallado sería este:

  1. Crear un archivo de SWAP capaz de compensar la falta que hará la desactivación de la unidad de RAID de 4 GB asignada al SWAP actualmente (/dev/md1).
  2. Activar el archivo de SWAP y desactivar el SWAP al que está asociada la unidad /dev/md1.
  3. Desactivar la unidad /dev/md1, para poder modificar el formato de las particiones del disco /dev/sda.
  4. Hacer el cálculo de cual sería la posición (sector del disco) en la que debería terminar la partición /dev/sda2 para permitir la creación de las particiones /dev/sdb2 y /dev/sdb3 con un tamaño apropiado para ser utilizadas como particiones integrantes de las unidades /dev/md1 y /dev/md0 respectivamente.
  5. Eliminar la partición /dev/sda2.
  6. Crear la partición /dev/sda2, con el nuevo tamaño calculado. Esto dejaría un espacio "libre" entre el final de la partición /dev/sda2 y el inicio de /dev/sda3, el cual será igual a la cantidad de bytes faltantes en el disco /dev/sdb para llegar al tamaño de /dev/sda.
  7. Crear las particiones correlativas en el disco /dev/sdb
  8. Crear la nueva unidad de RAID /dev/md1.
  9. Configurar /dev/md1 como SWAP nuevamente.
  10. Insertar la partición /dev/sdb3 en la unidad de RAID /dev/md0, reconstruyendo la partición y obteniendo como resultado final la redundancia que se espera que un sistema como este tenga.
Habiendo definido entonces el procedimiento, ponemos manos a la obra. Todo el proceso lo ejecuté conectado vía SSH al sistema, en forma remota. Cabe notar que he coloreado en amarillo los comandos que ejecuté, de forma de facilitar la lectura:

1) Crear un archivo de SWAP

Primero verificamos el tamaño actual del SWAP y el uso que el sistema le está dando:
srv:~ # free
             total       used       free     shared    buffers     cached
Mem:       2052948    1392436     660512          0     128200     788968
-/+ buffers/cache:     475268    1577680
Swap:      4193264     356468    3836796
Como puede verse, hay poco uso de SWAP, aunque no es despreciable, así que no va a haber necesidad de que el sistema "transvase" demasiada información desde el SWAP actual al nuevo archivo que crearemos una vez que lo configuremos. Debe considerarse que un sistema en producción jamás debe quedar sin SWAP, aunque en un momento dado se observe que el mismo no lo está utilizando.

Creamos el archivo que utilizaremos como SWAP momentáneamente. Para este caso en particular, viendo que no se estaba utilizando la totalidad del SWAP, lo hacemos de 2G de capacidad. Adicionalmente, lo formateamos como tal:
srv:~ # dd if=/dev/zero of=/swap.dat bs=2G count=1
0+1 records in
0+1 records out
2147479552 bytes (2.1 GB) copied, 155.499 s, 13.8 MB/s
srv:~ # mkswap /swap.dat
Setting up swapspace version 1, size = 2097144 KiB
no label, UUID=12105ad3-d781-478f-a967-d1597b92ea78

2) Activacion del SWAP del archivo y desactivación del SWAP provisto por la unidad /dev/md1

srv:~ # swapon /swap.dat
srv:~ # free
             total       used       free     shared    buffers     cached
Mem:       2052948     560468    1492480          0       3388     482876
-/+ buffers/cache:      74204    1978744
Swap:      6290408     356468    5933940
Llegados a este punto, podemos desasociar la unidad de RAID /dev/md1 del SWAP:
srv:~ # swapoff /dev/md1
srv:~ # free
             total       used       free     shared    buffers     cached
Mem:       2052948     890400    1162548          0       3448     458016
-/+ buffers/cache:     428936    1624012
Swap:      2097144          0    2097144
srv:~ #
Ahora que liberamos la unidad de RAID, podemos trabajar tranquilos de que no hay ningún proceso en el sistema que la esté utilizando.

4) Desactivar la unidad /dev/md1

srv:~ # mdadm -S /dev/md1
mdadm: stopped /dev/md1
srv:~ # cat /proc/mdstat
Personalities : [raid0] [raid1] [raid10] [raid6] [raid5] [raid4]
md0 : active raid1 sda3[0]
      73749520 blocks super 1.2 [2/1] [U_]
      bitmap: 1/1 pages [4KB], 65536KB chunk

unused devices: 
srv:~ #
En este momento, solo quedó activa la unidad /dev/md0, la cual contiene el sistema raiz, el cual no debe ser perturbado de ninguna forma, dado que el funcionamiento del sistema depende de ello.

3) Cálculo del tamaño (y posición de comienzo y final) de la partición /dev/sda2

Una vez desactivada la unidad correspondiente, podemos hacer el cálculo del tamaño que tendría que tener la partición correspondiente a esta unidad para compensar la diferencia de espacio que falta en el disco /dev/sdb, para poder crear luego las particiones /dev/sdb2 y /dev/sdb3, y que específicamente /dev/sdb3 tenga el mismo exacto tamaño que /dev/sda3, condición indispensable para que sea posible reconstruir /dev/md0. Es cuestión de aplicar las matemáticas para obtener el resultado.

El tamaño de la partición /dev/sda3 es de 147501231 sectores (73750616 bloques), y suponiendo que intentásemos crear la partición /dev/sdb3 con el espacio que nos queda después de crear las particiones /dev/sdb1 y /dev/sdb2 (idénticas a sus correlativas en /dev/sda), dicha partición nos quedaría de 147449743 sectores (73724872 bloques), lo cual nos dá una diferencia de 51488 sectores (25745 bloques) con respecto al tamaño de /dev/sda3. Entonces, si disminuímos el tamaño de la partición /dev/sda2 en 51488 sectores, debería quedarnos suficiente espacio para que fuera posible crear las particiones /dev/sdb2 y /dev/sdb3 con exactamente las mismas características que las particiones /dev/sda2 y /dev/sda3.

Si bien podríamos tomarnos la molestia de usar un programa de cambio de tamaño de particiones (como gpart), en este caso vamos a decantarnos por eliminar la partición /dev/sda2 y crearla de nuevo con el nuevo tamaño calculado (8337119 sectores, obtenido al restarle 51488 sectores al tamaño de la partición original, la cual finaliza en el sector 8800255). De estas operaciones obtenemos la nueva posición del extremo final de la partición, en el sector 8748767.

5) Eliminación de la partición /dev/sda2

La operación entonces se reduce primero a eliminar la partición /dev/sda2 anterior con fdisk:
srv:~ # fdisk /dev/sda
Command (m for help): d
Partition number (1-4): 2

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.

srv:~ #
Obsérvese que aparece una advertencia al grabar la nueva tabla de particiones. Esto es normal para un sistema en producción y no debe producir pánico. Ejecutar partprobe o kpartx no resuelve el problema, dado que las particiones siguen en uso. Lo único que "resuelve" este "problema" es un simple reboot, que podrá ser ejecutado cuando el momento sea apropiado. A los efectos de mantener el funcionamiento normal del servidor, esta advertencia puede perfectamente ser ignorada sin consecuencias de ningún tipo durante todo el tiempo que sea necesario.

6) Creación de la nueva partición /dev/sda2 con el tamaño apropiado.

Posteriormente a crear la partición /dev/sda2 de esta manera:
srv:~ # fdisk /dev/sda
Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4, default 2):
Using default value 2
First sector (411648-156249999, default 411648):
Using default value 411648
Last sector, +sectors or +size{K,M,G} (411648-156249999): 8748767

Command (m for help):
Nótese que usamos el valor 8748767 para indicar cual es el sector final de la partición. Pudimos también especificar el tamaño de la partición en sectores, indicando el valor que calculamos anteriormente y anteponiéndole un signo de "+": +8337119. Cualquiera de las dos formas son válidas.

7) Creación de las particiones necesarias en /dev/sdb

srv:~ # fdisk /dev/sdb

Command (m for help): p

Disk /dev/sdb: 80.0 GB, 80000000000 bytes
255 heads, 63 sectors/track, 9726 cylinders, total 156250000 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4, default 1): 1
First sector (2048-156249999, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-156249999, default 156249999): 411647

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4, default 2): 2
First sector (411648-156249999, default 411648):
Using default value 411648
Last sector, +sectors or +size{K,M,G}(411648-156249999): 8748767

Command (m for help): t
Partition number (1-4): 2
Hex code (type L to list codes): fd
Changed system type of partition 2 to fd (Linux raid autodetect)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4, default 3): 3
First sector (8748768-156249999, default 8748768):
Using default value 8748768
Last sector, +sectors or +size{K,M,G} (8748768-156249999, default 156249999):
Using default value 156249999

Command (m for help): t
Partition number (1-4): 3
Hex code (type L to list codes): fd
Changed system type of partition 3 to fd (Linux raid autodetect)

Command (m for help): p

Disk /dev/sdb: 80.0 GB, 80000000000 bytes
255 heads, 63 sectors/track, 9726 cylinders, total 156250000 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048      411647      204800   83  Linux
/dev/sdb2          411648     8748767     4168560   fd  Linux raid autodetect
/dev/sdb3         8748768   156249999    73750616   fd  Linux raid autodetect

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.
srv:~ #
En el proceso debe notarse que el tipo asignado a las particiones que formarán parte de las unidades de RAID fueron declarados como "fd" (Linux raid autodetect). También se puede observar que la partición /dev/sdb3 tiene exactamente 73750616 bloques (que era nuestro objetivo principal), y la partición /dev/sdb2 tiene exactamente 4168560 bloques, lo cual indica que los cálculos fueron correctos.

8) Crear la nueva unidad de RAID /dev/md1.

Llegados a este punto podemos crear nuevamente la unidad de RAID que desactivamos anteriormente, con el propósito de manipular los tamaños y las posiciones en los discos. Esta es una tarea simple, usando mdadm:
srv:~ # mdadm --create /dev/md1 --level=1 --raid-devices=2 /dev/sda2 /dev/sdb2
mdadm: /dev/sda2 appears to be part of a raid array:
    level=raid1 devices=2 ctime=Fri Jun 21 16:11:35 2013
mdadm: Note: this array has metadata at the start and
    may not be suitable as a boot device.  If you plan to
    store '/boot' on this device please ensure that
    your boot-loader understands md/v1.x metadata, or use
    --metadata=0.90
mdadm: /dev/sdb2 appears to be part of a raid array:
    level=raid1 devices=2 ctime=Fri Jun 21 16:11:35 2013
Continue creating array? yes
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md1 started.
srv:~ # 
Como puede observarse, aparece una advertencia, dado que la partición /dev/sda2 cree pertenecer a una unidad de RAID previa (lo cual es cierto). Podemos ignorar esta advertencia sin problema, porque sabemos que esta partición formaba parte de la unidad original y no correremos riesgos recreandola, así que la respuesta correcta a la pregunta "Continue creating array?" es presionar la tecla "y".

A continuación verificamos que la unidad se creó correctamente:

srv:~ # cat /proc/mdstat
Personalities : [raid0] [raid1] [raid10] [raid6] [raid5] [raid4]
md1 : active raid1 sdb2[1] sda2[0]
      4167524 blocks super 1.2 [2/2] [U_]
      bitmap: 1/1 pages [4KB], 65536KB chunk
      [>....................]  resync =  4.6% (193792/4167524) finish=1.0min speed=64597K/sec

md0 : active raid1 sda3[0]
      73749520 blocks super 1.2 [2/1] [U_]
      bitmap: 1/1 pages [4KB], 65536KB chunk

unused devices: 
Aquí podemos apreciar que la unidad fué inicializada correctamente y que comenzó el proceso de reconstrucción.

Como el proceso se lleva a cabo en forma totalmente independiente del funcionamiento del sistema, podemos seguir con el procedimiento sin esperar que haya problemas de importancia. La sincronización llevará un tiempo, pero no es necesario desperdiciar ese tiempo esperando a que el sistema termine de ejecutarlo.

9) Configurar /dev/md1 como SWAP nuevamente.

srv:~ # mkswap -f /dev/md1
Setting up swapspace version 1, size = 4167520 KiB
no label, UUID=1b6613f9-dd0b-42ab-bfe7-b9cf8fb385e8

srv:~ # swapon /dev/md1
srv:~ #
Ya habiendo activado la unidad de RAID en el SWAP, podemos desactivar el archivo de SWAP que creamos originalmente y eliminarlo.

srv:~ # swapoff /swap.dat
srv:~ # rm -f /swap.dat
srv:~ #

10) Insertar la partición /dev/sdb3 en la unidad de RAID /dev/md0

srv:~ # mdadm --add /dev/md0 /dev/sdb3
mdadm: added /dev/sdb3
srv:~ # cat /proc/mdstat
Personalities : [raid0] [raid1] [raid10] [raid6] [raid5] [raid4]
md1 : active raid1 sdb2[1] sda2[0]
      4167524 blocks super 1.2 [2/2] [UU]
      bitmap: 1/1 pages [4KB], 65536KB chunk

md0 : active raid1 sdb3[2] sda3[0]
      73749520 blocks super 1.2 [2/1] [U_]
      [>....................]  recovery =  0.2% (194560/73749520) finish=31.5min speed=38912K/sec
      bitmap: 1/1 pages [4KB], 65536KB chunk

unused devices: 
srv:~ # 
Llegado este punto, podemos decir que el procedimiento ha concluído con éxito. Si el tamaño de la partición /dev/sdb3 fuera inapropiado, mdadm no permitiría su inclusión en la unidad de RAID, con lo cual este procedimiento hubiera sido en vano.

Ahora solo cabe esperar que la unidad /dev/md0 se reconstruya, proceso que puede si bien se estima que puede tardar una media hora, puede tardar mucho más que eso. Y una vez terminado, las unidades quedarán así:

srv:~ # cat /proc/mdstat
Personalities : [raid0] [raid1] [raid10] [raid6] [raid5] [raid4]
md1 : active raid1 sdb2[1] sda2[0]
      4167524 blocks super 1.2 [2/2] [UU]
      bitmap: 1/1 pages [4KB], 65536KB chunk

md0 : active raid1 sda3[2] sdb3[0]
      73749520 blocks super 1.2 [2/2] [UU]
      bitmap: 1/1 pages [4KB], 65536KB chunk

unused devices: 

Conclusión.

En definitiva, el procedimiento cumplió con los objetivos y con las reglas que lo rigeron. No hubo downtime, y la manipulación de las particiones y unidades no representó un riesgo significativo para el funcionamiento del sistema en ningún momento.

Cabe agregar que si bien es muy posible que este procedimiento haya sido una solución muy específica para un caso muy puntual, esto no significa que no presente un punto de vista distinto e interesante a tomar en cuenta cuando se nos presenta una situación fuera de lo común, con dificultades adicionales que lo hacen más entretenido aún (como por ejemplo que se deba hacer remotamente, que el servidor permanezca en producción, etc.).

Adicionalmente a este procedimiento que podríamos dar "por terminado" (y para completar como es debido este tutorial), deberían tomarse los recaudos del caso y copiarse el contenido de la partición montada en /boot (/dev/sda1) en /dev/sdb1 y asegurarse que el sistema puede bootear de ese disco en forma independiente de la existencia del otro (una de las razones por las cuales suelo instalar los discos de esta manera), así que ejecutamos algunos comandos más y ya dejamos todo como debe ser:

srv:~ # dd if=/dev/sda1 of=/dev/sdb1
409600+0 records in
409600+0 records out
209715200 bytes (210 MB) copied, 13.7615 s, 15.2 MB/s
srv:~ # fsck -f /dev/sdb1
fsck from util-linux 2.19
e2fsck 1.41.14 (22-Dec-2010)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/sdb1: 46/51200 files (10.9% non-contiguous), 35815/204800 blocks

srv:~ # grub

    GNU GRUB  version 0.97  (640K lower / 3072K upper memory)

 [ Minimal BASH-like line editing is supported.  For the first word, TAB
   lists possible command completions.  Anywhere else TAB lists the possible
   completions of a device/filename. ]

grub> find /boot/grub/stage1
 (hd0,0)
 (hd1,0)

grub> root (hd1,0)
 Filesystem type is ext2fs, partition type 0x83

grub> setup (hd1)
 Checking if "/boot/grub/stage1" exists... yes
 Checking if "/boot/grub/stage2" exists... yes
 Checking if "/boot/grub/e2fs_stage1_5" exists... yes
 Running "embed /boot/grub/e2fs_stage1_5 (hd1)"...  17 sectors are embedded.
succeeded
 Running "install /boot/grub/stage1 (hd1) (hd1)1+17 p (hd1,0)/boot/grub/stage2 /boot/grub/menu.lst"... succeeded
Done.

grub> exit
Con estos comandos, copiamos la partición /dev/sda1 sobre /dev/sdb1, asegurando que son exactamente iguales, pasamos un fsck para verificar que el filesystem contenido en /dev/sdb1 está en buenas condiciones, y por último ejecutamos GRUB para configurar el MBR en el disco /dev/sdb y asegurar así que va a ser capaz de bootear, independientemente de que el disco /dev/sda esté presente.

Por último, ejecutamos un nuevo scan de las unidades de RAID para actualizar el archivo /etc/mdadm.conf y listo.

srv:~ # echo "DEVICE containers partitions" > /etc/mdadm.conf
srv:~ # mdadm --detail --scan >> /etc/mdadm.conf
srv:~ # cat /etc/mdadm.conf
DEVICE containers partitions
ARRAY /dev/md0 metadata=1.2 name=srv:0 UUID=70578b13:6c3c1bc1:ace1d531:78764029
ARRAY /dev/md1 metadata=1.2 name=srv:1 UUID=4920c932:ddd10dfe:b97b79b8:5275b4a5

Como les dije antes, esta "solución" podría ser muy específica, pero espero que quienes lleguen a este artículo lo consideren como lo que es realmente, un punto de vista diferente y una solución alternativa a un problema relativamente infrecuente, y además le encuentren algo de utilidad.

Pido disculpas por lo extenso del artículo, pero me pareció interesante publicarlo de la forma más detallada posible para evitar errores que puedan hacer de un entretenido procedimiento, una pesadilla. Espero que sea de provecho para quienes visiten este aburrido rincón de Internet... :-)

:wq

 
Gustavo Castro

Crea tu insignia