PXE para instalaciones básicas de CentOS y Debian

jue, 20 oct 2011 by Foron

Otro mini-post que vuelve a salirse completamente de la idea general de este blog. Ya hay mucha documentación sobre PXE y sobre instalaciones automatizadas tanto de CentOS como de Debian, pero bueno, a ver si le es útil a alguien.

En este caso, vamos a montar un sencillo servidor PXE, que podremos usar para hacer instalaciones de CentOS y Debian. Bueno, en realidad, podemos instalar cualquier cosa, pero en mi caso no suelo necesitar nada más.

Todo esto se debe a que, para las pruebas que hago en mi laboratorio, el mínimo de máquinas virtuales que necesito no baja de... tres, y al final tiendo a perder mucho tiempo con las instalaciones, y poco con el trabajo "de verdad". Por eso, nada mejor que PXE, kickstart y debian-installer para agilizar el proceso.

Ojo, que todo esto, aunque perfectamente válido, no es lo que yo usaría, a priori, en un entorno real. Hay mucho software que automatiza lo que vamos a hacer aquí, con un interfaz web, scripts para actualizar repositorios, .... Por eso, creo que aplicaciones como Cobbler (por citar una) deben ser la primera opción.

Aún así, para los que queréis aprender cómo se montan estos "inventos", aquí van unas pinceladas.

El problema

Necesitamos una forma rápida de instalar servidores. En mi caso, máquinas virtuales. Aunque hoy en día la gente de VmWare, RedHat o Virsh+libvirt ofrecen alternativas para clonar instancias como churros, vamos a optar por una solución genérica y mucho más divertida.

Las distribuciones que vamos instalar con este sistema son CentOS y Debian. Para el caso de las basadas en kickstart, la cosa está muy clara, pero para Debian, muchos os preguntaréis ¿Por qué no FAI? Bien, la respuesta rápida, en mi caso, es que no quiero instalar un servidor NFS, y la última vez que miré era un requisito. Como decía, buscad la solución que más os guste.

Otro problema posterior es la configuración "fina" de las instancias. Eso no lo voy a documentar aquí, pero como pista: cfengine, puppet, ....

La solución

He dicho que iba a ir rápido, y ya me estoy enrollando.... Venga, lo primero que necesitamos, como no, es una BIOS que permita instalar los clientes vía PXE. Por supuesto, tanto Qemu/KVM como VmWare lo permiten, así que ni una palabra más al respecto.

En cuanto al software necesario para el servidor de instalaciones, necesitamos un DHCPD razonable (por ejemplo el del ISC), un TFTPD (por ejemplo atftpd) y un servidor web, que en mi caso va a ser apache. Situemos todo en contexto:

  1. La máquina virtual arranca y "habla" con DHCPD.
  2. Además de la información IP, se trasmite, vía DHCP+TFTP, pxelinux.0.
  3. En el caso de Debian, también se aprovecha para dar una pista sobre dónde encontrar el fichero para debian-installer.
  4. Cargamos el menú de arranque con TFTP.
  5. El sistema usa apache para obtener los ficheros ks, debian-installer y los rpm, deb y demás parafernalia.

Empezamos por lo fácil: El contenido web. Tan sencillo como copiar el contenido de los CDs de instalación de las distribuciones a una ruta del arbol web.

  # ls /var/www/instalaciones/centos/6.0-x86_64/
  CentOS_BuildTag  EULA  images    Packages                  repodata              RPM-GPG-KEY-CentOS-Debug-6     RPM-GPG-KEY-CentOS-Testing-6
  EFI              GPL   isolinux  RELEASE-NOTES-en-US.html  RPM-GPG-KEY-CentOS-6  RPM-GPG-KEY-CentOS-Security-6  TRANS.TBL

  # ls /var/www/instalaciones/debian/squeeze/
  autorun.inf  dists  firmware  g2ldr.mbr  install.amd  md5sum.txt  pool         README.mirrors.html  README.source  setup.exe  win32-loader.ini
  css          doc    g2ldr     install    isolinux     pics        README.html  README.mirrors.txt   README.txt     tools

Sigamos con la configuración para DHCP. Hemos dicho que, además de las obvias IPs, también van a ayudar a las Debian con la definición del fichero para debian-installer. Hay tres bloques de configuración que os quiero enseñar:

  # less /etc/dhcp/dhcpd.conf
  ...
  subnet 192.168.10.0 netmask 255.255.255.0 {
     option routers 192.168.10.1;
     option domain-name-servers 192.168.10.1;
     option domain-name "forondarena.net";
     option tftp-server-name "inst.forondarena.net";
     filename "/instalaciones/pxelinux.0";
  }
  host centos1 {
     hardware ethernet 52:54:00:30:38:c6;
     server-name "fn134.forondarena.net";
     fixed-address 192.168.10.134;
  }
  host debian1 {
     hardware ethernet 52:54:00:da:4a:92;
     server-name "fn135.forondarena.net";
     fixed-address 192.168.10.135;
     if substring (option vendor-class-identifier, 0, 3) = "d-i" {
       filename "http://inst.forondarena.net/instalaciones/squeeze_preseed_135.cfg";
          }
  }
  ...

Como veis, para CentOS no trasmitimos nada relacionado con el fichero kickstart, pero para Debian sí. ¿Por qué? Pues para enriquecer un poco el post con algo diferente, la verdad. Hay más de una forma de hacerlo.

Con esto ya tenemos la primera fase del arranque. Lo siguiente: El "boot menu". Y para esto necesitamos TFTP:

  /srv/tftp/instalaciones/
  ├── pxelinux.0
  ├── pxelinux.cfg
  │   ├── C0A80A86
  │   └── C0A80A87
  ├── squeeze-x86_64
  │   ├── initrd.gz
  │   └── vmlinuz
  ├── centos-6.0-x86_64
  │   ├── initrd.img
  │   └── vmlinuz
  ├── msgs
  │   ├── centos
  │   │   ├── boot.msg
  │   │   └── general.msg
  │   └── debian
  │       ├── f1.txt
  │       └── f2.txt

La mayoría de estos ficheros se pueden bajar casi desde cualquier sitio:

  http://ftp.cz.debian.org/debian/dists/squeeze/main/installer-amd64/current/images/netboot/debian-installer/amd64/

Como el contenido de "msg" es obvio, vamos a los fichero importantes, C0A80A86 y C0A80A87. ¿Qué clase de nombres son estos? Pues son las IPs, en hexadecimal, de nuestras dos máquinas virtuales:

  $ IP_ADDR="192.168.10.134"; printf '%02X' ${IP_ADDR//./ }; echo
  C0A80A86
  $ IP_ADDR="192.168.10.135"; printf '%02X' ${IP_ADDR//./ }; echo
  C0A80A87

El contenido, para CentOS, en C0A80A86:

  timeout 100
  prompt 1
  display msgs/centos/boot.msg
  F1 msgs/centos/boot.msg
  F2 msgs/centos/general.msg

  default Centos6

  label Centos6
    menu label ^Centos 6 amd64
    kernel centos-6.0-x86_64/vmlinuz
    append initrd=centos-6.0-x86_64/initrd.img ramdisk_size=6878 ip=dhcp ks=http://192.168.10.40/instalaciones/ks_rh6_134.ks

Como veis, hemos especificado la ruta web para el fichero kickstart.

Para Debian, en C0A80A87:

  # less C0A80A87
  menu hshift 15
  menu width 49
  prompt 1
  display msgs/debian/f1.txt
  timeout 100
  f1 msgs/debian/f1.txt
  f2 msgs/debian/f2.txt
  menu title Installer boot menu
  menu color title    * #FFFFFFFF *
  ...
  menu tabmsgrow 18
  menu tabmsg Press ENTER to boot or TAB to edit a menu entry

  default install

  label install
      menu label ^Debian Squeeze Texto amd64
      menu default
      kernel squeeze-x86_64/vmlinuz
      append video=vesa:ywrap,mtrr vga=788 initrd=squeeze-x86_64/initrd.gz auto=true priority=critical locale=es_ES console-keymaps-at/keymap=es --

En este caso, no hemos dicho dónde encontrar el fichero para debian-installer. Ya lo sabemos.

Y ya casi por último, veamos los ficheros kickstart y debian-installer, a los que vamos a acceder desde apache:

  # ls -1  /var/www/instalaciones/
  ...
  ks_rh6_134.ks
  squeeze_preseed_135.cfg

Todos conocéis el formato de los .ks; son simples y fáciles de leer.

  #version=RHEL6
  install
  url --url=http://192.168.10.40/instalaciones/centos/6.0-x86_64/
  lang es_ES.UTF-8
  keyboard es
  network --device eth0 --onboot yes --bootproto static --ip 192.168.10.134 --netmask 255.255.255.0 --gateway 192.168.10.1 --nameserver 192.168.10.1 --hostname fn134.forondarena.net
  rootpw  --iscrypted contraseña
  firewall --service=ssh
  authconfig --enableshadow --passalgo=sha512 --enablefingerprint
  selinux --enforcing
  timezone --utc Europe/Madrid
  bootloader --location=mbr --driveorder=vda --append="crashkernel=auto rhgb quiet"
  clearpart --all --drives=vda
  part /boot --fstype=ext4 --size=200
  part pv.gjsqnW-TYE3-SDwW-646R-0SSI-hhDa-ZF6bXm --grow --size=200
  volgroup vg_primario --pesize=4096 pv.gjsqnW-TYE3-SDwW-646R-0SSI-hhDa-ZF6bXm
  logvol / --fstype=ext4 --name=lv_root --vgname=vg_primario --size=7400
  logvol swap --name=lv_swap --vgname=vg_primario --size=588
  ##repo --name="CentOS"  --baseurl=http://192.168.10.1/instalaciones/centos/6.0-x86_64/ --cost=100

  halt

  %packages
  @core
  @server-policy
  @spanish-support
  openssh*
  %end

Es un ejemplo autogenerado para una máquina virtual tipo KVM. No le hagáis mucho caso al contenido en sí. Lo dicho, tenéis un kilo de documentación, e incluso aplicaciones para hacer estos ficheros.

Otra cosa muy diferente es debian-installer. La verdad, no conozco a mucha gente que no se haya atascado con esto en algún momento. El concepto es sencillo, con una opción para cada una de las opciones de cada uno de los menús que pueden aparecer durante el proceso de instalación. El problema es que, esto tan fácil de decir, es un listado .... largo; y con algunos algoritmos, como el del cálculo de espacio para particiones, nada claros. Además, como suele ser demasiado frecuente, el que decidió los nombres de las opciones.... bueno, que no me parece demasiado intuitivo, aunque si estás familiarizado con Debian te haces enseguida.

No voy a escribir un ejemplo completo. Os vais a tener que conformar con una pequeña muestra:

  # cat /var/www/instalaciones/squeeze_preseed_135.cfg
  ...
  # Keyboard selection.
  d-i console-tools/archs select at
  d-i console-keymaps-at/keymap select es
  d-i keyboard-configuration/xkb-keymap select es
  ### Network configuration
  d-i netcfg/choose_interface select eth0
  d-i netcfg/disable_dhcp boolean true
  # Static network configuration.
  d-i netcfg/get_nameservers string 192.168.10.1
  d-i netcfg/get_ipaddress string 192.168.10.135
  d-i netcfg/get_netmask string 255.255.255.0
  d-i netcfg/get_gateway string 192.168.10.1
  d-i netcfg/confirm_static boolean true
  ...
  # Root password, encrypted using an MD5 hash.
  d-i passwd/root-password-crypted password contraseña
  ...
  ### Partitioning
  d-i partman-auto/disk string /dev/sda
  d-i partman-auto/method string lvm
  d-i partman-lvm/device_remove_lvm boolean true
  d-i partman-lvm/device_remove_lvm_span boolean true
  d-i partman-auto/purge_lvm_from_device boolean true
  d-i partman-auto-lvm/new_vg_name string vg_forondarenanet
  d-i partman-basicmethods/method_only boolean false
  d-i partman-auto/expert_recipe string boot-root :: \
  100 100 100 ext3 \
         $defaultignore{ } \
         $primary{ } \
         device{ /dev/sda } \
         $bootable{ } \
         method{ format } \
         format{ } \
         use_filesystem{ } \
         filesystem{ ext3 } \
         mountpoint{ /boot } \
         . \
  200 1000 -1 ext4 \
         $defaultignore{ } \
         $primary{ } \
         device{ /dev/sda } \
         method{ lvm } \
         vg_name{ vg_forondarenanet } \
         . \
  300 4000 -1 ext4 \
         $lvmok{ } \
         lv_name{ lvroot } \
         in_vg{ vg_forondarenanet } \
         method{ format } \
         format{ } \
         use_filesystem{ } \
         filesystem{ ext4 } \
         mountpoint{ / } \
         . \
  512 512 512 linux-swap \
         $lvmok{ } \
         in_vg{ vg_forondarenanet } \
         lv_name{ lvswap } \
         method{ swap } \
         format{ } \
         .
  d-i partman-auto/choose_recipe select boot-root

  d-i partman/confirm_write_new_label boolean true
  d-i partman/choose_partition select finish
  d-i partman/confirm boolean true
  d-i partman/confirm_nooverwrite boolean true
  d-i partman/confirm_nochanges boolean true
  d-i partman-lvm/confirm boolean true
  d-i partman-lvm/confirm_nooverwrite boolean true
  d-i partman-lvm/confirm_nochanges boolean true
  ...
  # Individual additional packages to install
  d-i pkgsel/include string openssh-server less
  d-i pkgsel/upgrade select safe-upgrade
  popularity-contest popularity-contest/participate boolean false
  d-i finish-install/reboot_in_progress note
  d-i debian-installer/exit/halt boolean true
  # This will power off the machine instead of just halting it.
  d-i debian-installer/exit/poweroff boolean true
  ...

Y así podría seguir...

En este caso es una máquina virtual para ESX. Me interesa que veáis la parte de particionado. Aunque no os lo creáis, he definido una partición primaria /boot de unos 100M, y el resto en LVM, con aproximadamente 512M de swap, y el resto de espacio disponible para raíz.

Y poco más hace falta. Ahora bien, en este post, las notas que suelo añadir al final son más importantes que nunca.

Notas

Nota 1: Los ficheros de instalación automática de los ejemplos hacen un halt una vez finalizada la instalación. ¿Por qué? Porque no tengo automatizado que la BIOS cambie por arte de magia de arranque por PXE a arranque desde disco.

Nota 2: Más que una nota, un consejo. No os volváis locos con la configuración de ficheros de sistema, usuarios y aplicaciones. Tenéis herramientas mucho mejores para la configuración "fina", así que plantearos añadir puppet, cfengine, chef, ... en los bloques "%packages" y "d-i pkgsel/include", y dejarles que hagan su trabajo al arrancar la máquina. Para CentOS (desde puppetlabs):

  %post
  ....
  /sbin/chkconfig --level 345 puppet on
  /bin/echo "$PUPPETIP puppet" >> /etc/hosts
  /bin/echo "nameserver $NAMESERVERIP" >> /etc/resolv.conf
  hostname $hostname
  # Write out the hostname to a file for reboot.
  /bin/echo -e "NETWORKING=yes\nHOSTNAME=$hostname" > /etc/sysconfig/network
  /usr/sbin/puppetd -tv

y, como mini-ejemplo, un poco diferente, para Debian:

  d-i preseed/late_command string in-target wget -P /tmp/ http://servidor_web/script.sh;
    in-target chmod +x /tmp/script.sh; in-target /tmp/script.sh

dejando que ese "script.sh" haga cosas como "sed -i 's/START=no/START=yes/'", siguiendo la estructura de Debian de ficheros en default y todas estas cosas.

Nota 3: Lo más importante. Este post no es suficiente para hacer que las instalaciones automáticas os funcionen. Necesita trabajo. Si os atascáis con algo, tweet o comentario, y lo intentaremos solucionar.


Comments