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:
-
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 comandoinstall-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 depatchperl
, inspeccionando el código fuente del comandoinstall-cpanm
vemos que se puede instalar el programacpanm
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
-
-
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. -
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 archivocpanfile.snapshot
en el directoriovendor/cache
. -
install --cached
(en DEPLOYMENT MODE): instala las versiones de los módulos especificados en el archivocpanfile.snapshot
utilizando los tarball del directoriovendor/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 porcpanm
(evitando tener que instalarCarton
). 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:
-
app.pl
: aplicación de ejemplo:#!/usr/bin/env perl use Dancer2; get '/' => sub { "Hello World!" }; dance;
-
cpanfile
: dependencias de la aplicación a instalar utilizando Carton:requires "Dancer2", "0.208001";
-
cpanfile.snapshot
: archivo generado por Carton al momento de instalar las dependencias de la aplicación. Se debe guardar ya que contiene los módulos que fueron instalados junto a sus versiones. -
vendor
: directorio en el que se almacenarán las dependencias de la aplicación para realizar un deploy en forma offline que será creado durante la etapa de creación del entorno. Se recomienda excluir del repositorio y manejar por separado.
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`
-
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 queperlbrew
ya se encuentre instalado en el sistema se agrega al principio delPATH
la ruta al programa donde se instalarperlbrew
. Por último, la variableWORKDIR
será utilizada para indicar el directorio de trabajo donde se encuentra la aplicación que contiene el directoriovendor
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
-
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} || :
-
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 comandoself-install
. Para ya habilitar el shell que se está utilizando ejecutar en la consolasource $PERLBREW_ROOT/etc/bashrc
. -
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/).
-
Instalar
patchperl
. Como se indicó previamente en las contras de usar perlbrew, ya se indicó que no es conveniente utilizar el comandoinstall-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. -
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
-
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.
-
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 comandoinstall-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 acpanm
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"
-
Instalar
Carton
:cpanm install Carton
-
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. -
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
-
Por último se utiliza el comando
bundle
para obtener todas las dependencias instaladas porcarton
en el directoriovendor/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
.
-
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)
-
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 lineasource $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
-
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
-
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.*
-
Crear lib y establecerla por defecto:
perlbrew lib create perl-5.28.2@dancer2-demo perlbrew use perl-5.28.2@dancer2-demo
-
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 envendor/cpanm
:export PERL_CPANM_OPT="--mirror=file://$WORKDIR/vendor/cpanm"
-
Instalación de Carton:
cpanm install Carton
-
Instalación de dependencias en caché utilizando Carton:
carton install --cached
-
Prueba de la aplicación para determinar que el entorno fué correctamente replicado:
carton exec ./app.pl
Pendientes
-
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. -
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.
-
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
- Hace años me ocurrió que no pude realizar el deploy de una aplicación de python porque el servidor del que se extraía una dependencia estaba offline. ¡El problema es real!.