Criando pacotes Debian assinados com GPG - Nando Vieira
Uma das grandes vantagens de se trabalhar em sistemas baseados em Debian é a grande disponibilidade de pacotes. Quase todos os projetos importantes são distribuídos também como pacotes .deb, extensão dos pacotes Debian.
E criar pacotes Debian é bastante simples, embora as informações sejam muitos espalhadas e, por que não, confusas para quem não é sysadmin. Neste artigo vou mostrar como é o processo que sigo para empacotar o Ruby, fazendo a assinatura do pacote e repositório com GPG.
Gerando sua chave GPG
Para assinar nosso repositório e pacotes, nós precisaremos gerar uma chave GPG. Execute o comando gpg --gen-key. Escolha as opções recomendadas. Antes de gerar sua chave, você precisará gerar "entropia", o que significa dizer que dados randômicos serão criados à partir da atividade de sua máquina. Isso pode demorar muito! Felizmente, existe um pacote que permite fazer isso muito rapidamente.
$ sudo apt-get -y install rng-tools
Depois que o pacote for instalado, execute o comando abaixo:
Agora, gere sua chave GPG:
gpg: directory `/home/vagrant/.gnupg' created
gpg: new configuration file `/home/vagrant/.gnupg/gpg.conf' created
gpg: WARNING: options in `/home/vagrant/.gnupg/gpg.conf' are not yet active during this run
gpg: keyring `/home/vagrant/.gnupg/secring.gpg' created
gpg: keyring `/home/vagrant/.gnupg/pubring.gpg' created
Real name: Nando Vieira
Email address: fnando.vieira@gmail.com
"Nando Vieira <fnando.vieira@gmail.com>"
gpg: /home/vagrant/.gnupg/trustdb.gpg: trustdb created
gpg: key 8CEE231C marked as ultimately trusted
pub   2048R/8CEE231C 2012-07-27
Key fingerprint = 926C C20B F27D 554E 0E5D  3699 9DB7 CC09 8CEE 231C
uid                  Nando Vieira <fnando.vieira@gmail.com>
sub   2048R/36DD9698 2012-07-27
Criando nosso pacote .deb
Nós iremos gerar nosso pacote Debian à partir do código-fonte do Ruby. Vale lembrar que fiz todo este processo em um box Vagrant, isolando todo e qualquer efeito colateral que possa acontecer.
ATENÇÃO: Se você decidir por fazer isso no Vagrant, lembre-se de fazer uma cópia de backup do diretório ~/.gnupg antes de destruir o box. Caso contrário, você não terá como assinar novos pacotes com a mesma chave.
Crie um diretório chamado ruby-deb.
$ mkdir ruby-deb
$ cd ruby-deb
Baixe o tarball do programa que você quer empacotar. No nosso caso, vou usar o tarball http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p286.tar.gz. Depois que o download do tarball terminar, extraia o arquivo.
$ tar xvf ruby-1.9.3-p286.tar.gz
Agora nós iremos instalar o pacote dh-make, que permite converter um diretório de código-fonte em uma estrutura válida de acordo com a Política do Debian.
$ sudo apt-get -y install dh-make vim
De dentro do diretório ruby-1.9.3-p286, execute o comando dh_make. Isso irá gerar um diretório debian. Este diretório funciona como um manifesto de como seu pacote será gerado.
$ DEBFULLNAME='Nando Vieira' dh_make -e fnando.vieira@gmail.com -f ../ruby-1.9.3-p286.tar.gz
Maintainer name  : Nando Vieira
Email-Address    : fnando.vieira@gmail.com
Date             : Wed, 17 Oct 2012 16:36:35 +0000
Package Name     : ruby
Version          : 1.9.3-p286
Done. Please edit the files in the debian/ subdirectory now. ruby
Ele contém uma série de arquivos do Emacs que podem ser removidos.
$ rm debian/*.{ex,EX}
De todos os arquivos desse diretório, o mais importante é o arquivo debian/control. Ele define as dependências do pacote, versão, dentre outras informações. Edite-o conforme o exemplo abaixo:
Maintainer: Nando Vieira <fnando.vieira@gmail.com>
Build-Depends: debhelper (>= 8.0.0), autotools-dev, libssl-dev, libyaml-dev, libreadline6-dev, libffi-dev, zlib1g-dev
Homepage: http://ruby-lang.org
Package: ruby-stable
Depends: ${shlibs:Depends}, ${misc:Depends}, libyaml-0-2, libssl1.0.0, libffi6, zlib1g
Description: Interpreter of object-oriented scripting language Ruby, version 1.9.3
O campo Build-Depends deve conter as dependências que seu código-fonte precisa para ser compilado. Já o campo Depends define quais as dependências que devem ser instaladas quando o pacote for instalado.
Edite o arquivo debian/changelog. Atualize este arquivo com as informações sobre as mudanças introduzidas por este pacote. Ele também deve ter o versionamento do pacote.
ruby (1.9.3-p286-1) precise; urgency=low
-- Nando Vieira <fnando.vieira@gmail.com>  Wed, 17 Oct 2012 16:36:35 +0000
ATENÇÃO: O nome e e-mail que é colocado no arquivo debian/changelog devem ser exatamente os mesmos que foram adicionados na chave GPG.
Antes de gerar os pacotes, nós iremos instalar as dependências de compilação. São as mesmas que você adicionou no campo Build-Depends.
$ sudo apt-get install -y debhelper devscripts autotools-dev libssl-dev libyaml-dev libreadline6-dev libffi-dev zlib1g-dev
Agora é a hora de gerar os pacotes. Como a versão 1.9.3 precisa de uma versão de Ruby para poder fazer a compilação, vamos instalar o pacote disponível no Ubuntu.
$ sudo apt-get -y install ruby1.9.3
Agora, gere o pacote:
Hora de tomar um café! Esse passo demora bastante. No fim, se tudo deu certo, seu pacote terá sido criado com a mesma arquitetura que você está gerando o pacote. Isso significa que se você estiver em um sistema 64-bits, terá gerado um pacote também 64-bits.
Inspecionando o comando debuild vi que é possível especificar a arquitetura do pacote que será gerado com a opção -a, o que permitiria gerar um pacote 32-bits à partir de um sistema 64-bits. Infelizmente, para compilar o Ruby ela não funciona. Uma solução seria usar algo como o pbuilder, mas criar os ambientes de distribuição é extremamente demorado, então preferi automatizar o processo em um script bash e gerar as duas arquiteturas em boxes diferentes do Vagrant.
Uma coisa importante é que seu pacote já foi assinado com a chave GPG. Você pode instalá-lo com o comando dpkg.
$ sudo dpkg -i ../ruby-stable_1.9.3-p286-1_amd64.deb
Embora funcione bem, instalar o pacote manualmente não é maneira mais adequada. Por isso, nosso próximo passo será criar o repositório.
Criando seu repositório Debian
Criar um repositório é tão simples quanto criar o pacote. Primeiro, nós iremos instalar o pacote reprepro.
Agora, nós iremos criar o diretório onde nosso repositório será definido.
Dentro deste diretório crie o arquivo conf/distributions com o seguinte conteúdo:
Origin: apt.hellobits.com
Description: Custom packages
Pull: precise
Agora, podemos adicionar o nosso pacote ao repositório. Você terá que informar sua senha da chave GPG, para assinar o repositório.
$ reprepro --ask-passphrase -Vb . includedeb precise ../ruby-stable_1.9.3-p286-1_amd64.deb
Como nosso repositório está assinado, precisaremos exportar a chave GPG, que deverá ser adicionada antes que os pacotes possam ser instalados. Para fazer isso, execute o comando abaixo. Lembre-se que esse arquivo precisa estar disponível publicamente, então é uma boa ideia deixar no próprio repositório.
$ gpg --armor --export fnando.vieira@gmail.com > hellobits.key
Agora precisamos servir este repositório publicamente. Se você não tiver nada muito complexo (ou grande), pode usar o Heroku. Crie o arquivo .htaccess na raíz do diretório repo com o conteúdo abaixo.
Crie também um arquivo index.php vazio.
Ao criar estes dois arquivos, você poderá servir seu repositório usando os buildpacks do Heroku, nesse caso servindo apenas arquivos estáticos. Antes, eu estava servindo com o middleware Rack::Directory, mas vi essa dica no projeto apt-heroku criado recentemente pelo Fabio Kung, que também permite gerenciar repositórios com bastante facilidade. Só não estou usando o projeto do Kung porque não sei como funciona com arquivos assinados com GPG, e fiquei com preguiça de ir atrás.
Crie seu projeto no Heroku, envie os arquivos e pronto! Você tem um repositório Debian com pacotes assinados prontinho para ser usado.
Instalando pacotes de seu repositório Debian
Para adicionar a chave GPG do repositório ao Ubuntu, você vai precisar executar o comando apt-key.
Depois, crie o arquivo /etc/apt/sources.list.d/hellobits.conf com as informações sobre o nosso repositório.
Atualize a lista de pacotes e instale o pacote que você gerou.
$ sudo apt-get install ruby-stable
Embora não seja um processo de outro mundo, também não é nada trivial gerar pacotes Debian.
Novamente, recomendo que você faça uma cópia de backup do diretório ~/.gnupg, que contém a sua chave GPG. Além dela, é interessante manter uma cópia do diretório debian, para não ter que fazer todo o processo sempre que for gerar uma atualização do pacote; neste caso, você precisará mexer apenas no arquivo debian/changelog.