Proceso de empaquetado (pbuilder debsign dput)

Empaquetando para Huayra GNU/Linux (amd64, i386)

Requerimientos:

  • pbuilder
  • gnupg
  • dput
  • devscripts
  • dh-make

Para instalarlos en huayra se tiene que ejecutar el siguiente comandos:

sudo apt-get install pbuilder devscripts dput gnupg dh-make

Instalar pbuilder

Pbuilder se encarga de hacer el paquete dentro de un chroot, instalando las dependencias (Build-deps) necesarias dentro del mismo.
Esto logra que no tengamos que ensuciar nuestra máquina de paquetes cada vez que tengamos que hacer uno nuevo.

Primero tenemos que armar un (o los que quieras) chroot base, pero al menos tenes que generar uno por arquitectura (i386 y amd64).

Generación el paquete

Crear base-XXX.tgz con pbuilder:

sudo pbuilder create --basetgz /var/cache/pbuilder/huayra-torbellino-i386.tgz --distribution jessie --debootstrapopts --arch --debootstrapopts i386 --mirror ftp://ftp.debian.org/debian

Para amd64:

sudo pbuilder create --basetgz /var/cache/pbuilder/huayra-torbellino-amd64.tgz --distribution jessie --debootstrapopts --arch --debootstrapopts amd64 --mirror ftp://ftp.debian.org/debian

Los archivos de chroot base-XXX.tgz se encuentran en /var/cache/pbuilder por defecto (pero podemos cambiarlo configurando los paths que usa pbuilder en nuestro ~/.pbuilderrc y ponerlos donde queremos.

En el directorio de resultados del pbuilder (/var/cache/pbuilder/result) se encontraran los archivos generados (.deb, .dsc, .changes, etc), pero nos conviene ponerlos dentro del argún directorio de nuestro home via ~/.pbuilderrc.

NOTA : Para generar el paquete hace falta ser root porque se usa chroot, pbuilder pide la clave vía sudo cuando sea necesario.
En tal caso, como no tendríamos acceso a escribir en el directorio de resultado de pbuilder (salvo que cambiemos permisos), lo que hacemos es configurar en nuestro ~/.pbuilderrc el path que queremos con la variable BUILDRESULT (que puede ser dentro de nuestro home como mencionamos recientemente).

Ejemplo de pbuilderrc (con soporte para i386 y amd64):

$ cd
$ cat .pbuilderrc 

# defaults

DEFAULT_ARCH=amd64
DEFAULT_NAME=huayra
DEFAULT_DIST=torbellino

if [ -z "${ARCH}" ]; then
  ARCH=$DEFAULT_ARCH    
fi

if [ -z "${NAME}" ]; then
  NAME=$DEFAULT_NAME    
fi

if [ -z "${DIST}" ]; then
  DIST=$DEFAULT_DIST    
fi

MIRRORSITE=http://mirrors.dcarsat.com.ar/debian/
if [ "$NAME"="huayra" ]; then 
  OTHERMIRROR=http://devel.huayra.conectarigualdad.gob.ar/huayra
fi

BASETGZ="/var/cache/pbuilder/$NAME-$DIST-$ARCH.tgz" 
BUILDRESULT=/home/usuario/conectar/paquetes/result/$NAME/$DIST/$ARCH

# si queremos habilitar los hooks
#HOOKDIR="/home/usuario/.pbuilder/hook.d" 
# para obtener soporte de red dentro del chroot
USENETWORK=yes

NOTA: Con este pbuilderrc, si pasamos la variable ARCH, NAME y DIST elegimos de que arquitectura será el paquete que estamos generando. Y formamos el nombre del archivo chroot base-XXX.tgz que vamos a usar al generar el paquete.

IMPORTANTE:

Se debe tener en cuenta con cual distro base de debian (wheezy, jessie) se debe crear los base-xxx.tgz, segun la versión de Huayra (1.x, 2.x) pero siempre para los paquetes nuevos la distro debe ser torbellino (unstable)

Huayra Huayra codename Debian base
1.1 brisa wheezy
2.0 pampero wheezy
2.1 pampero wheezy
3.0 sud jessie
unstable torbellino jessie

Es importante tener creado el directorio para almacenar los paquetes:

mkdir -p "$HOME/paquetes/result" 

También se puede ejecutar pbuilder con el parámetro --buildresult <path> para elegir el directorio de resultado donde se generan los deb's.

Luego ya podemos generar el deb:

Ir al directorio del proyecto, el que contiene un directorio "debian"

cd mipaquete-1

Generar paquete con pdebuild (debido a que no se pasa la variable ARCH, se genera amd64 como arquitectura):

pdebuild 

Para i386 se debe pasar la arquitectura de forma explicita:

ARCH=i386 pdebuild

NOTA: por defecto se usará el archivo huayra-torbellino-amd64.tgz (segun nuestro ~/.pbuilderrc) salvo que cambiamos las variables NAME, DIST y ARCH respectivamente.

dpkg-buildpackage: source package mipaquete
dpkg-buildpackage: source version 1-1
dpkg-buildpackage: source changed by Fernando Toledo <ragnarok@docksud.com.ar>
 dpkg-source --before-build mipaquete
 fakeroot debian/rules clean
dh clean
   dh_testdir
   dh_auto_clean
   dh_clean
 dpkg-source -b mipaquete
dpkg-source: info: using source format `3.0 (native)'
dpkg-source: info: building mipaquete in mipaquete_1-1.tar.gz
dpkg-source: info: building mipaquete in mipaquete_1-1.dsc

<< TRUNCADO (el log es bastante largo) >>

(NOTESE que el comando para generar es pdebuild y no pbuilder como hicimos para generar el chroot base)

Una vez que el build concluye, en caso que sea correcto, tenemos en el directorio de resultado los archivos correspondientes al paquete en cuestión:

mipaquete_1-1.debian.tar.gz
mipaquete_1-1.dsc
mipaquete_1-1_amd64.build
mipaquete_1-1_amd64.changes
mipaquete_1-1_amd64.deb

Variables para entorno de empaquetado

Se pueden generar una variables para que las usen los scripts de desarrollo. Por ejemplo cuando usamos dch (debian changelog) para agregar una nueva entrada en debian/ChageLog se tome el mail automaticamente. Estas variables pueden ir en ~/.bashrc (si se usa bash por ejemplo):

DEBEMAIL="ragnarok@docksud.com.ar" 
DEBFULLNAME="Fernando Toledo" 

export DEBEMAIL DEBFULLNAME

Firmar el paquete

Para subir el paquete a los repositorios y que sea aceptado, es necesario que esté firmado (gnupg) y que nuestra firma esté habilitada en el repo.

Crear firma:

ragnarok@jola:~$ gpg --gen-key
gpg (GnuPG) 1.4.12; Copyright (C) 2012 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Por favor seleccione tipo de clave deseado:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sólo firmar)
   (4) RSA (sólo firmar)
Su elección: 1
las claves RSA pueden tener entre 1024 y 4096 bits de longitud.
¿De qué tamaño quiere la clave? (2048) 
El tamaño requerido es de 2048 bits
Por favor, especifique el período de validez de la clave.
         0 = la clave nunca caduca
      <n>  = la clave caduca en n días
      <n>w = la clave caduca en n semanas
      <n>m = la clave caduca en n meses
      <n>y = la clave caduca en n años
¿Validez de la clave (0)? 0
La clave nunca caduca
¿Es correcto? (s/n) s

Necesita un identificador de usuario para identificar su clave. El programa
construye el identificador a partir del Nombre Real, Comentario y Dirección
de Correo Electrónico de esta forma:
    "Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>" 

Nombre y apellidos: Fernando Toledo
Dirección de correo electrónico: ragnarok@docksud.com.ar
Comentario: Dale Doke!
Ha seleccionado este ID de usuario:
    "Fernando Toledo (Dale Doke!) <ragnarok@docksud.com.ar>" 

¿Cambia (N)ombre, (C)omentario, (D)irección o (V)ale/(S)alir? v

Necesita una frase contraseña para proteger su clave secreta.

Ingrese su clave: ******* 
Repita su clave: *******

Es necesario generar muchos bytes aleatorios. Es una buena idea realizar
alguna otra tarea (trabajar en otra ventana/consola, mover el ratón, usar
la red y los discos) durante la generación de números primos. Esto da al
generador de números aleatorios mayor oportunidad de recoger suficiente
entropía.

No hay suficientes bytes aleatorios disponibles. Por favor, haga algún
otro trabajo para que el sistema pueda recolectar más entropía
(se necesitan 284 bytes más).
...........+++++
.+++++
gpg: trustdb.gpg: se ha creado base de datos de confianza
gpg: clave B0C10F8D marcada como de confianza absoluta
claves pública y secreta creadas y firmadas.

gpg: comprobando base de datos de confianza
gpg: 3 dudosa(s) necesarias, 1 completa(s) necesarias,
modelo de confianza PGP
gpg: nivel: 0  validez:   1  firmada:   0  confianza: 0-, 0q, 0n, 0m, 0f, 1u
pub   2048R/B0C10F8D 2013-01-23
      Huella de clave = C477 B23D 110B C2E7 219A  89E1 14EB 1C70 B0C1 0F8D
uid                  Fernando Toledo (Dale Doke!) <ragnarok@docksud.com.ar>
sub   2048R/885E36DD 2013-01-23

Enviar firma a los admins y/o subirla a servidores de claves

Tenemos que exportar nuestra clave publica para que pueda ser enviada a los admins del repositorio
o para subirla a algún servidor de claves (recomendado):

ragnarok@jola:~$ gpg --send-keys B0C10F8 
gpg: enviando clave B0C10F8 a hkp servidor keys.gnupg.net

Exportar a un archivo

ragnarok@jola:~$ gpg --export --armor  B0C10F8  >mi_clave.asc

El archivo que acabamos de crear llamado mi_clave.asc es el que se debe enviar.

Teniendo estos pasos listos, es posible proceder a firma el paquete con nuestra clave generada:

debsign -k B0C10F8D mipaquetes_1-1_amd64.changes

signfile mi_paquete_1-1.changes B0C10F8D

Necesita una frase contraseña para desbloquear la clave secreta
del usuario: "Fernando Toledo (Dale Doke!) <ftoledo@docksud.com.ar>" 
clave DSA de 2048 bits, ID B0C10F8D, creada el 2013-01-26

Successfully signed dsc and changes files

En este momento nuestro paquete esta firmado y listo para subir.

NOTA: Se pueden configurar una variable (en ~/.devscripts) para evitar tener que poner el ID de tu clave y que debsign la detecte de forma automática:

DEBSIGN_KEYID="B0C10F8D" 

Con estas variables luego hacemos simplemente:

debsign mipaquetes_1-1_amd64.changes

Subida del paquete al repositorio (reprepro)

El paso final desde el lado del desarrollador es enviar el paquete para que en el servidor se procese con reprepro y se integre finalmente al repositorio publico.

Usa de las formas para enviar el paquete es usando dput.

Este comando se encarga de subir todos los archivos que correspondan al paquete que tengamos.

Tenemos que crear un archivo ~/.dput.cf con la configuración de los repos donde podemos subir los paquetes. Ejemplo:

ragnarok@jola:~$ cat .dput.cf 
[DEFAULT]
default_host_main = huayra-repo

[huayra-repo]
fqdn = devel.huayra.conectarigualdad.gob.ar
method = scp
login = repo
incoming = /home/repo/linuxparatodos/apt/incoming

NOTA: En nuestro caso, hay un script en cron cada 5 minutos que se encarga de procesar los paquetes que están en cola en el directorio incoming.

Ahora, vamos a necesitar que nuestra llave pública SSH (no gpg como la que usamos para firmar) esté también habilitada en el servidor.
En tal caso, va a ser posible que se puedan subir los archivos.

Podemos generar la clave en caso de no tenerla:

ragnarok@jola:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ragnarok/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): ******************
Enter same passphrase again: ******************
Your identification has been saved in /home/ragnarok/.ssh/id_rsa.
Your public key has been saved in /home/ragnarok/.ssh/id_rsa.pub.
The key fingerprint is:
72:3f:ca:a8:10:38:d1:8a:b1:62:f1:fa:1d:53:d2:21 ragnarok@jola
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|                 |
|                 |
|     E .         |
|      + S        |
|.o   . = .       |
|+ +   o   o      |
|++ + ..o . .     |
|B...==+.o        |
+-----------------+

Debemos enviar nuestro archivo con la clave publica id_rsa.pub al admin.

Luego ya podemos intentar subir el paquete:

dput mipaquete_1-1_amd64.changes

Si está todo bien, en el servidor se encarga de inyectar nuestro paquete al repositorio y lo tendremos disponible en breve a través de apt en las máquinas clientes.

Hook en caso de que falle el build

Modificar el archivo ~/.pbuilderrc y agregar una variable HOOKDIR

HOOKDIR="/home/usuario/.pbuilder/hook.d" 

Luego crear un archivo /home/usuario/.pbuilder/hook.d/C10shell_build_fail
con lo siguiente:

#!/bin/sh
# invoke shell if build fails.

apt-get install -y --force-yes vim less bash
cd /tmp/buildd/*/debian/..
/bin/bash < /dev/tty > /dev/tty 2> /dev/tty

Hacer este script ejecutable

chmod +x  /home/usuario/.pbuilder/hook.d/C10shell_build_fail

Si pbuilder falla, se ejecuta este script (dentro del chroot) que instala algun paquete que necesitemos para trabajar (vim, less, bash) y nos deja en el directorio del source. Para salir limpiamente usamos exit. Este metodo nos sirve para revisar que falló del build.

Tambien podemos agregar un hook (conla letra B como prefijo) llamado por ejemplo B10shell_build_ok que se ejecuta en caso de que pbuilder construya correctamente el paquete. De esta forma, tabien quedamos dentro del chroot pero con el build satisfactorio. Podemos ver logs o revisar alguna información. Luego cuando salimos con "exit", los .deb's generados se copian al directorio buildresult

Notas para build entre ambas arquitecturas

Hay varios puntos a tener en cuenta para poder generar los paquetes para las dos arquitecturas (i386 y amd64)

  • Tener los base.tgz de acuerdo a cada arquitectura (base-i386.tgz y base-amd64.tgz) y con el pbuilderrc elegimos de acuerdo a la variable cual se va a utilizar
  • Si ya generamos y subimos al repo un build de amd64 usando el .changes normalmente, significa que ya se subió el sources y el orig.tar.gz. Entonces cuando ahora generemos el paquete para la nueva arquitectura (i386) solo tenemos que subir los archivos dependiente de esta plataforma. (binarios)
    Por este motivo, se pasa un parámetro al pbuilder para que cree un .changes sin los sources para hacer el upload
ARCH=i386 pdebuild --debbuildopts -B

Si no lo generamos de esta manera, cuando subamos el .changes con dput al reprepro vamos a tener un error de checksum por los md5 porque ya habian sido subido anteriormente el source.

No es importante el orden de cual arquitectura se genere primero, siempre y cuando el resto se generen sin los sources (--debbuildopts -B)

Nota para la primer subida del paquete al repo (incluir orig.tar.gz)

En el caso que agreguemos un nuevo paquete (no nativo) al repositorio, es necesario que también se suba el .orig.tar.gz
Si la versión del paquete termina en 0 o en 1 (ej: mi_paquete-2.4-*1*), esto se hace de forma automática.

Pero si la versión es diferente de 0 o 1, hay que constriur el paquete de tal forma que lo incluya.

dpkg-buildpackage -sa

En nuestro caso usando pbuilder:

pdebuild --debbuildopts -sa

De esta manera, en la subir del paquete se agregar al .changes el orig.tar.gz

Acelerar el proceso de pbuilder

Si tu equipo tiene bastante memoria, es recomendable montar el directorio de trabajo build como un sistema de archivos de memoria
Con ésta configuración se puede incrementar la velocidad de Lectura/Escritura en general durante el proceso de construcción de los paquetes:

Agregar al /etc/fstab la siguiente linea:

tmpfs    /var/cache/pbuilder/build    tmpfs   defaults,auto    0    0

No te olvides de montar el nuevo directorio:

mount /var/cache/pbuilder/build

Luego a tu ~/.pbuidlerrc se debe agregar ésta variable para evitar que se hagan hardlinks entre sistemas de archivos deferentes (que no está permitido)

APTCACHEHARDLINK=no

Ahora ya se puede ejecutar pdebuild normalmente y veremos que el tiempo de construcción se redujo.

Fuente: http://www.davromaniak.eu/index.php?post/2011/07/12/Pbuilder-and-tmpfs-can-be-friends

Una forma de prueba del paquete dentro de un entorno de pbuilder

Crear un directorio "repo" que contenga los archivos del paquete:

mipaquete_1-1.debian.tar.gz
mipaquete_1-1.dsc
mipaquete_1-1_i386.build
mipaquete_1-1_i386.changes
mipaquete_1-1_i386.deb
mipaquete_1.orig.tar.gz

Y convertirlo en un repositorio usable por apt:

cd repo
dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz
dpkg-scansources . /dev/null | gzip -9c > Sources.gz
cd ..

Iniciar pbuilder indicando que monte nuestro directorio "repo"

sudo pbuilder --login --bindmounts repo

Ya dentro del entorno de pbuilder agregar el directorio repo como repositorio de apt en un archivo en /etc/apt/sources.list.d:

echo -e "deb file:///repo testing main \n"  >/etc/apt/sources.list.d/repo_local.list
echo -e "deb-src file:///repo testing main n" >>/etc/apt/sources.list.d/repo_local.list

Ahora podes hacer apt-get update e instalar el paquete

apt-get update
apt-get install mipaquete

Estando siempre dentro del chroot, podemos hacer algunas pruebas sobre el paquete para comprobar si funciona como se espera.

Si se necesita usar las X desde el entorno de pbuilder, entonces son necesarios un par de pasos más:
Desde fuera de pbuilder, el host, ejecutar:

Xephyr -screen 640x480 :1 &!

Dentro del entorno de pbuilder ejecutar:

export DISPLAY=:1

De esta forma, los que ejecutemos dentro del chroot lo tendremos en un display (nested X) creado por Xephyr

Documentación:

http://www.netfort.gr.jp/~dancer/software/pbuilder-doc/pbuilder-doc.html