Replicar entorno perl usando perlbrew

2019/10/25

Introducción

Durante el desarrollo, test y deploy de aplicaciones es conveniente poder replicar el mismo entorno en los diferentes pc’s y servidores con los que se trabaje. Además, es doblemente conveniente el poder realizar la configuración del entorno de forma offline, ya que esto disminuye el tiempo utilizado en descarga de archivos y también se mitiga el riesgo de no poder crear el entorno en caso de que sea imposible descargar alguna dependencia por falta de disponibilidad de algún servidor *.

En el caso de Perl, las herramientas que se utilizarán para replicar un entorno serán las siguientes:

  1. perlbrew: permite gestionar entornos y descargar distintas utilidades.

    Entre las ventajas se encuentran:

    • Autoinstalarse desde un archivo descargado previamente utilizando el comando self-install.

    • Instalar (compilar) versiones de Perl a partir de tarballs descargados previamente con el comando install.

      Nota: en Debian se necesita tener instalado en el sistema el paquete build-essentials para poder compilar perl.

      Nota: se necesita tener instalado patchperl, el cual parchea versiones viejas de perl para poder compilarlas en sistemas operativos nuevos.

      Nota: hay versiones de perlbrew que no permiten instalar Perl desde un tarball de forma offline. La versión 0.87 que se utilizará no tiene dicho problema.

    • Crear librerías las cuales permiten tener más de un conjunto distinto de módulos instalados para una misma versión de perl.

    Por otro lado, como desventajas se tienen:

    • No es posible instalar patchperl de forma offline utilizando el comando install-patchperl. Como alternativa a dicho comando se puede descargar manualmente el archivo, modificarlo, copiarlo al directorio destino y darle permisos de ejecución siguiendo los pasos indicados en el código fuente del comando install-patchperl. Los pasos quedarían como sigue:
      wget -q -O patchperl 'https://raw.githubusercontent.com/gugod/patchperl-packing/master/patchperl'
      cat patchperl \
          | sed '1 s,#!.*,#!/usr/bin/perl,' \
          > $PERLBREW_ROOT/bin/patchperl
      chmod +x $PERLBREW_ROOT/bin/patchperl
      
    • No es posible instalar cpanminus de forma offline mediante el comando install-cpanm. Igual que en el caso de patchperl, inspeccionando el código fuente del comando install-cpanm vemos que se puede instalar el programa cpanm de la siguiente forma:
      wget -q -O cpanm 'https://raw.githubusercontent.com/miyagawa/cpanminus/master/cpanm'
      cp cpanm $PERLBREW_ROOT/bin/
      chmod +x $PERLBREW_ROOT/bin/cpanm
      
  2. cpanminus: permite instalar módulos de Perl desde CPAN (Comprehensive Perl Archive Network). La principal ventaja que utilizaremos del comando cpanm es que permite definir un directorio caché donde almacenar y donde buscar módulos para instalar. Lamentablemente no hay forma de especificar las versiones de las dependencias entre módulos como hacer Carton. Se utilizará únicamente para instalar Carton.

  3. Carton: gestor de dependencias de módulos Perl, será la herramienta utilizada a la hora de instalar los distintos módulos ya que registra las versiones de todos los módulos instalados en el entorno.

    Los dos comandos que nos interesarán particularmente serán:

    • bundle: permite almacenar los tarball de los módulos especificados en el archivo cpanfile.snapshot en el directorio vendor/cache.

    • install --cached (en DEPLOYMENT MODE): instala las versiones de los módulos especificados en el archivo cpanfile.snapshot utilizando los tarball del directorio vendor/cache sin acceder a los mirror de CPAN.

      Nota: en la documentación de Carton se indica que es posible almacenar los modulos que utiliza un proyecto de forma tal que puedan ser instalados directamente por cpanm (evitando tener que instalar Carton). No se utilizará dicha opción.

Se comenzara describiendo como crear un entorno y luego como replicarlo de forma offline, utilizando para ello el contenido del directorio vendor, el cual podrá copiarse entre los equipos en los que se desee replicar el entorno.

Aplicación de ejemplo

Como aplicación de ejemplo se utilizará una aplicación realizada con Dancer2 a la que llamaremos dancer2-demo, más exactamente la que aparece en la página web como ejemplo, que será ejecutada por la versión 5.28.2 de perl y que constará de los siguientes archivos:

El motivo de la aplicación de ejemplo es tener un ejemplo concreto para realizar la creación y replicación de un entorno. Se elijió una aplicación hecha en Dancer2 ya que tiene un número interesante de dependencias, la implementación es bastante corta y puede probarse fácilmente utilizando wget o curl desde linea de comandos.

Creación del entorno

A continuación se listarán los pasos seguidos para crear un entorno con la versión 5.28.2 de perl.

La estructura de directorios será la siguiente:

$PERLBREW_ROOT: archivos relacionados a perlbrew, es donde se instalan las
                distintas versiones de perl y sus dependencias
$WORKDIR:       directorio de la aplicación en desarrollo
+- vendor:      directorio donde se almacenarán los archivos de forma offline
   +- perlbrew: archivos relacionados a la instalación de perlbrew
   +- cpanm:    archivos utilizados por cpanm para descargar Carton
   +- cache:    archivos de módulos guardados por `carton bundle`
  1. Establecer variables de entorno. Se utilizará la variable de entorno PERLBREW_ROOT para indicar donde se instalará la versión de perl a utilizar. Por defecto su valor es $HOME/perl5/perlbrew. Para evitar conflictos en el caso de que perlbrew ya se encuentre instalado en el sistema se agrega al principio del PATH la ruta al programa donde se instalar perlbrew. Por último, la variable WORKDIR será utilizada para indicar el directorio de trabajo donde se encuentra la aplicación que contiene el directorio vendor que es donde se almacenarán los archivos para recrear el entorno de manera offline:

    export PERLBREW_ROOT=${PERLBREW_ROOT:-$HOME/perl5/perlbrew}
    export PATH="$PERLBREW_ROOT/bin:$PATH"
    export WORKDIR=$HOME/dancer2-demo
    
  2. Creación de directorios de cache. Estos se utilizarán para almacenar los fuentes de los programas y librerías que luego sea necesario instalar para replicar el entorno. Se utilizará la siguiente estructura de directorios:

    mkdir -p $WORKDIR/vendor/{perlbrew,cpanm,cache} || :
    
  3. Descarga e instalación de perlbrew:

    wget -P $WORKDIR/vendor/perlbrew https://raw.githubusercontent.com/gugod/App-perlbrew/release-0.87/perlbrew
    perl $WORKDIR/vendor/perlbrew/perlbrew self-install
    

    Nota: aquí no hay que olvidar agregar la linea source $PERLBREW_ROOT/etc/bashrc en el archivo ~/.profile como indica la salida del comando self-install. Para ya habilitar el shell que se está utilizando ejecutar en la consola source $PERLBREW_ROOT/etc/bashrc.

  4. Descarga y copia en el caché de una versión particular de perl. Como versión a instalar se utiliza alguna de las devueltas por el comando perlbrew available el cual lista las versiones disponibles de perl.

    perlbrew download perl-5.28.2
    cp $PERLBREW_ROOT/dists/perl-5.28.2.tar.* $WORKDIR/vendor/perlbrew/
    

    Nota: se utiliza globbing ya que las versiones de perl están comprimidas en más de un formato (.tar.gz/.tar.xz; ver http://www.cpan.org/authors/id/S/SH/SHAY/).

  5. Instalar patchperl. Como se indicó previamente en las contras de usar perlbrew, ya se indicó que no es conveniente utilizar el comando install-patchperl. En su lugar se instalará manualmente:

    wget -q -P $WORKDIR/vendor/perlbrew 'https://raw.githubusercontent.com/gugod/patchperl-packing/a9fc33a47253bca890c68905fcb79ad0305c5c5e/patchperl'
    cat $WORKDIR/vendor/perlbrew/patchperl \
        | sed '1 s,#!.*,#!/usr/bin/perl,' > $PERLBREW_ROOT/bin/patchperl
    chmod +x $PERLBREW_ROOT/bin/patchperl
    

    Nota: aquí se supone que existe un interprete de perl instalado en el sistema en el directorio /usr/bin/perl. Si la ruta fuera otra se deben modificar los comandos anteriores.

    Nota: ya que patchperl no tiene releases o tags, se utilizará un commit específico.

  6. Instalar versión de perl. Ahora que fué instalado patchperl podemos instalar una versión específica de perl:

    perlbrew install $WORKDIR/vendor/perlbrew/perl-5.28.2.tar.*
    

    Nota: como está reportado en el issue 658, hay versiones de perlbrew en los cuales no funciona el instalar perl usando la ruta del tarball. Como ejemplo, en la versión 0.86 el comando anterior falla y en la versión 0.87 funciona.

    Nota: para una compilación rápida (sin realizar tests) puede utilizarse el flag --notest

  7. Crear lib y establecerla por defecto. Esto permite tener más de un conjunto distinto de librerías para una misma versión de perl.

    perlbrew lib create perl-5.28.2@dancer2-demo
    perlbrew use perl-5.28.2@dancer2-demo
    

    Nota: esto es útil para el caso de estar trabajando en distintas aplicaciones que posean distintas dependencias.

  8. Instalar y configurar cpanm. Como se mencionó anteriormente en la introducción, lo haremos para poder instalar Carton.

    Al igual que en el caso del comando install-patchperl, el comando install-cpanm solo funciona con acceso a internet, por lo cual se ejecutará un comando equivalente pero esta vez utilizando un número de release en lugar de un commit, ya que cpanm versiona sus releases:

    wget -q -P $WORKDIR/vendor/perlbrew 'https://raw.githubusercontent.com/miyagawa/cpanminus/1.7044/cpanm'
    cp $WORKDIR/vendor/perlbrew/cpanm $PERLBREW_ROOT/bin
    chmod +x $PERLBREW_ROOT/bin/cpanm
    

    Luego hay que establecer la variable de entorno PERL_CPANM_OPT para indicarle a cpanm que guarde en un caché los módulos descargados y que al momento de instalar un módulo primero lo busque en el caché y luego en http://www.cpan.org:

    export PERL_CPANM_OPT="--cascade-search --save-dists=$WORKDIR/vendor/cpanm --mirror=file://$WORKDIR/vendor/cpanm --mirror=http://www.cpan.org"
    
  9. Instalar Carton:

    cpanm install Carton
    
  10. Ya que en la aplicación de ejemplo se tiene un archivo de nombre cpanfile con la lista de módulos a instalar, se instalarán estos utilizando Carton:

    carton install
    

    Nota: el comando anterior crea el archivo cpanfile.snapshot el cual contiene la lista de todos los módulos instalados junto a su versión.

  11. Para probar que todo fué instalado correctamente se ejecutará la aplicación de ejemplo:

    a. carton exec ./app.pl b. perl -Ilocal/lib/perl5 app.pl

  12. Por último se utiliza el comando bundle para obtener todas las dependencias instaladas por carton en el directorio vendor/cache:

    carton bundle
    

En este punto ya se puede almacenar el contenido del directorio vendor e ir a la siguiente etapa: replicar el entorno.

Replicación del entorno

A continuación se listarán los pasos seguidos para replicar de forma offline el entorno creado en el punto anterior utilizando los archivos del directorio vendor.

  1. Establecer variables de entorno. Al igual que en el paso anterior se establecerán las variables de entorno:

    export PERLBREW_ROOT=${PERLBREW_ROOT:-$HOME/perl5/perlbrew}
    export PATH="$PERLBREW_ROOT/bin:$PATH"
    export WORKDIR=$(pwd)
    
  2. Instalación y activación de perlbrew:

    perl $WORKDIR/vendor/perlbrew/perlbrew self-install
    

    Como se hizo en el punto 3. de la instalación, se debe agregar en el archivo ~/.profile la linea source $PERLBREW_ROOT/etc/bashrc.

    grep -q $PERLBREW_ROOT/etc/bashrc ~/.profile || cat >> ~/.profile <<END
    
    if [ -e ${PERLBREW_ROOT}/etc/bashrc ]; then
        source ${PERLBREW_ROOT}/etc/bashrc
    fi
    END
    
  3. Como se hizo anteriormente, se instalará la versión de patchperl previamente descargada:

    cat $WORKDIR/vendor/perlbrew/patchperl \
        | sed '1 s,#!.*,#!/usr/bin/perl,' > $PERLBREW_ROOT/bin/patchperl
    chmod +x $PERLBREW_ROOT/bin/patchperl
    
  4. Instalar versión específica de perl. Para ello se utiliza el tarball previamente descargado que se encuentra en vendor/perlbrew:

    perlbrew install $WORKDIR/vendor/perlbrew/perl-5.28.2.tar.*
    
  5. Crear lib y establecerla por defecto:

    perlbrew lib create perl-5.28.2@dancer2-demo
    perlbrew use perl-5.28.2@dancer2-demo
    
  6. Instalar y configurar cpanm. Igual a como se hizo con patchperl, se instala la versión descargada previamente:

    cp $WORKDIR/vendor/perlbrew/cpanm $PERLBREW_ROOT/bin
    chmod +x $PERLBREW_ROOT/bin/cpanm
    

    Se configurará cpanm de forma tal de utilizar solamente el caché previamente creado en vendor/cpanm:

    export PERL_CPANM_OPT="--mirror=file://$WORKDIR/vendor/cpanm"
    
  7. Instalación de Carton:

    cpanm install Carton
    
  8. Instalación de dependencias en caché utilizando Carton:

    carton install --cached
    
  9. Prueba de la aplicación para determinar que el entorno fué correctamente replicado:

    carton exec ./app.pl
    

Pendientes

  1. Scripts para replicar el entorno

    Hay pasos durante la replicación del entorno que lanzan un subshell, por ejemplo perlbrew use. Sería necesario para escribir el script ver como modificar el entorno sin lanzar el subshell.

  2. Evaluación de plenv en lugar de perlbrew

    Entre las alternativas a perlbrew se encuentra plenv. Vale la pena evaluar las ventajas y desventajas de utilizar plenv.

  3. Uso de cpanm en lugar de carton en producción

    En la documentación de carton, una alternativa a carton install --cached es:

    cpanm -L local --from "$PWD/vendor/cache" --installdeps --notest --quiet .
    

    Esto último puede ser útil en producción para evitar tener que instalar carton, ya que no sería necesario. En los equipos de desarrollo no ayudaría, ya que es posible que se quiera agregar un nuevo módulo y se necesitaría carton para instalar el módulo y las dependencias.

Notas