Trucos para plantillas de packer

2019/07/03

Packer es un programa utilizado para automatizar la creación de golden images o machine images.

El objetivo de este post es enumerar algunos trucos para facilitar la creación de los scripts utilizados para generar las imagenes.

Casos de ejemplos

Hay veces que conviene comenzar con un template funcionando y ajustarlo que tener que realizar el template de cero.

Como ejemplo de buenos repositorios de template se tiene

Hay que notar que varias veces las imagenes de los cd’s de instalación contienen errores y deben utilizarse hacks para poder crear las imagenes con packer. Un ejemplo de esto es el issue 3521: Preseed and Bypass Try/Install screen in ubuntu 14.04, 16.04

Uso de yaml

Por defecto packer utiliza archivos json para los archivos de configuración (templates). La contra más grande del formato json es que no permite realizar comentarios mientras se está creando la plantilla o comentar varias lineas mientras es necesario realizar una depuración en la configuración.

Una alternativa a utilizar json es utilizar el formato yaml, convirtiendo luego el template a formato json para su uso por packer. Para ello se puede utilizar el siguiente snippet en debian, instalando previamente el paquete python3-yaml (sudo apt-get install -Vy python3-yaml):

def convert(in_, out):
    json.dump(yaml.load(in_), out, sort_keys=True, indent=4)

El script completo se puede encontrar en el archivo yaml2json.

Nota: el soporte de yaml para templates en packer ya fué rechazado.

Separación en etapas

Dado que crear una imagen de una vez no es sencillo, conviene separar la creación en varias etapas.

Creación del sistema base vs Customización

La separación que me ha resultado más útil es entre la instalación del sistema base (mínimo) utilizando el cd de instalación y la posterior customización del sistema. Para ello la primer etapa utiliza un archivo .iso (el instalador) y en la segunda se utiliza la imagen de la vm exportada. En el caso de utilizar VirtualBox:

Instalación de paquetes vs Customización de paquetes

Otra separación que me ha dado resultado es cuando se debe configurar un paquete cuya instalación posee muchas dependencias que deben ser instaladas. En estos casos la descarga e instalación de paquetes insume un tiempo importante y es posible que ocurran fallas al momento de realizar la configuración mediante scripts, por lo cual conviene separar la instalación del paquete de su configuración. Como ejemplo se puede tener la instalación y configuración del display manager:

Luego, cuando ya esté funcionando el script de configuración se pueden unir las etapas anteriores:

provisioners:
  - type: shell
    scripts:
      - scripts/install-lightdm.sh
      - scripts/configure-lightdm.sh

Uso de makefiles

Para evitar crear la imagen de cero cuando hay algún paso en una etapa intermedia es útil utilizar make para calcular las dependencias.

Un ejemplo del contenido del archivo Makefile es el siguiente:

all: stage2

# aliases
stage1: output/stage1/debian-base.ova
stage2: output/stage2/debian-customized-disk001.vmdk

# dependencies
output/stage1/debian-base.ova: $(shell ./calculate-dependencies stage1.yaml)
output/stage2/debian-customized-disk001.vmdk: $(shell ./calculate-dependencies stage2.yaml)

# rules
output/stage1/debian-base.ova:
output/stage2/debian-customized-disk001.vmdk:
        packer build -force $<

%.json: %.yaml
        @./yaml2json < $< > $@

clean:
        rm -fr stage?.json output

.PHONY: clean

En el archivo anterior la pieza fundamental es el script calculate-dependencies, el cual obtiene las dependencias del archivo yaml y las devuelve en la salida estandar, para ser utilizada por el makefile. (Notar que el script anterior debe devolver como primer elemento el nombre del archivo pasado por parámetro con extensión .json para que se pueda utilizar correctamente la regla packer build -force $<.)

Dicho script funciona cargando el archivo yaml y obteniendo los archivos listados en los elementos (por ahora): virtualbox-iso, virtualbox-ovf, file, shell. No se tiene en cuenta el borrado de archivos, pero es útil en caso de modificaciones.