segunda-feira, 26 de outubro de 2015

Compilando imagens do Debian Live com Bitbucket, SourceForge e Google Cloud



Recentemente, implantamos Linux em alguns dos computadores da empresa. Para esses usuários, que lidam a maior parte do tempo com o browser, a migração não foi problemática: não havia a necessidade de software específico para eles. Como utilizamos o Google Apps for Work, então não temos nenhum problema de compatibilidade, e podemos contar com backups, colaboração em tempo real, e portabilidade da informação.

Para facilitar a implantação, eu precisava de uma forma de fazer uma seleção de scripts, aplicar algumas customizações e configurações internas para aderir à nossas políticas de software, e foi aí que tive a idéia de criar uma imagem customizada do Debian.

Eu uso a nuvem do Google diariamente, seja em minhas atividades de trabalho ou seja em meus projetos pessoais. Neste post eu vou comentar como eu conectei diferentes serviços à nuvem do Google para viabilizar um desses projetos pessoais e sem fins lucrativos: o ronolinux.

Esse projeto nada mais é do que de uma compilação de imagens live, resultado de uma seleção minimalista de pacotes para facilitar a implantação do Linux em meus casos de uso. Ele também serve como um projeto modelo para quem deseja masterizar seu próprio DVD/USB-live com Debian personalizado.

Debian Live

O projeto que eu utilizei como base no ronolinux foi o Debian Live, agora Live Systems. Este projeto consiste em um conjunto de scripts para a configuração e compilação de imagens live baseadas no Debian e derivados. Este é o projeto que produz as imagens live oficiais do Debian, então tem suporte no repositório e é mantido por um desenvolvedor Debian.

Bom, mas o que tem o Debian Live a ver com a nuvem do Google? Eu tinha um pequeno problema com relação ao ronolinux. Compilar a imagem leva um tempo, requer uma boa conexão com a internet, um bom espaço em disco para cache. Fazer isso no notebook, via wifi, acabava por gerar alguns problemas:
  • Eu tinha que levar meus dados de um lugar para o outro, estava tudo no notebook.
  • Eu tinha que aguardar o build terminar localmente para então desligar o notebook. Isso era ruim, porque eu queria deixar ele rodando no final do dia, pra não adiar uma correção pro dia seguinte.
  • O build consome muita memória e CPU em alguns estágios, e eu não conseguia prosseguir com outras atividades na máquina que estava compilando a imagem.
  • Eu queria iterar no desenvolvimento em momentos nos quais eu não tinha a máquina de build em mãos, ou quando ela não estava ligada.
  • Para testar as imagens, eu tinha que ou copiar em mídia, ou fazer o upload de arquivos de alguns gigabytes.

Nuvem para o resgate!

Não só porque está na moda, no meu caso era a solução perfeita: rodar os builds na nuvem! Para isso eu fiz uma máquina virtual Debian Jessie no Compute Engine e começei a compilar as imagens por lá.

Com isso eu tinha diversas vantagens. Como eu poderia apenas abrir o browser e conectar por SSH na máquina virtual, não precisava mais carregar o notebook pra lá e pra cá. Além disso, eu podia também contar com algumas vantagens do Compute Engine, tais como uma boa conexão de rede para baixar pacotes, e o disco persistente para fazer cache entre uma compilação e otura, além de poder escolher diferentes opções de disco, CPU e memória.

O Compute Engine é tão bem integrado com o Debian que temos até um mirror do repositório acessível de dentro do Google Cloud, otimizando ainda mais o build. Mas eu não parei por aí. Afinal de contas, estamos na era da integração contínua, e compilar as imagens é feito a partir de um código-fonte simples que configura como e quais pacotes vão na ISO.

Push to deploy!

Eu queria implementar um recurso extra: fazer o build ser acionado por um push no repositório. Para isso, o que eu fiz foi implementar um handler HTTP  em Go, utilizando o pacote vmproxy, que eu desenvolvi para permitir executar VMs do Compute Engine a partir do App Engine, sob-demanda, bem como "desligá-las" quando não estão mais em uso.

Desta forma, não só eu pude configurar uma webhook no Bitbucket para automatizar o build, mas também publicar o resultado no SourceForge, que tem um bom espaço para armazenamento e uma integração por rsync para o upload, o que o tornou uma opção exclenente para hospedar o resultado das imagens.

O melhor disso tudo é que eu posso usar máquinas virtuais com disco SSD, bom desempenho de CPU e Memória, e ainda contar com uma redução fantástica de custos: posso usar uma máquina preemptível, que é muito mais barata do que a máquina virtual convencional!

Neste ponto você pergunta: - Mas você não está fazendo imagens live? O problema do upload de imagens ficou resolvido, mas e pra testar, não tem que baixar tudo de novo?

Exatamente! Para resolver isso, eu aprendi uma coisa ao trabalhar como Debian Live. Automaticamente, o sistema gera um arquivo .zsync. O zsync é uma ferramenta ideal para sincronizar arquivos, especialmente nesse caso que são arquivos ISO, alterados frequentemente. O zsync baixa o arquivo de controle, e depois só baixa os pedaços da imagem nova que você ainda não tem. Isso é ótimo, e eu pude comprovar: reaproveitei mais de 85% do arquivo de imagem entre um build e outro!

Meu workflow agora ficou assim:
  1. De qualquer lugar, posso fazer apenas um push para o Bitbucket com uma mudança de configuração: incluir pacote, adicionar hook, etc.
  2. O Bitbucket aciona meu webhook no App Engine, que liga a VM com o script de startup.
  3. O script faz o checkout do Bitbucket, compila as imagens, e publica no SourceForge. No final, desliga a VM e salva um backup dos logs no Cloud Storage.
  4. Eu configurei uma notificação no SourceForge, e sempre que ele recebe uma versão nova do ronolinux, eu recebo um email.
  5. Para testar, eu baixo a versão atualizada do meu ISO com o zsync, reaproveitando o máximo da imagem anterior que eu já tinha na máquina de testes, ou baixando uma nova, pra testar em qualquer lugar.

Conclusão

Utilizando recursos hoje já disponíveis, é possível elaborar mecanismos complexos para resolver problemas de forma simples e prática, e sem pagar muito por isso. O que eu vou ter de custos com o Google Cloud não compra um computador novo, que ainda me custaria energia pra rodar apenas esse projeto simples e sem fins lucrativos que é o ronolinux. Com a nuvem do Google e os serviços Bitbucket e SourceForge, eu pude conectar as peças e obter um workflow que otimiza o meu tempo e torna o build simples e rápido.

Estou agora considerando reduzir o tempo de 1h pra gerar as duas "edições" do ronolinux, desktop e developer, em paralelo, o que deve deixar tudo em torno de 30min depois do commit.

Você pode encontrar o código-fonte, incluindo os scripts de build do Compute Engine no meu projeto do Bitbucket. As imagens que estou produzindo ainda estão em fase prelimitar de testes, mas caso queira conferir estão aqui no SourceForge.

:happy hacking!