Pular para o conteúdo principal
BlogLinuxDia de Lançamento: Automatização do Distro Linux (apresentando Ubuntu 20.04)

Dia de Lançamento: Automatização do Distro Linux (apresentando Ubuntu 20.04)

automating-distributions

Olá! Sou Brad, Engenheiro de Sistemas da Linode. Hoje marca um dia agitado no mundo Linux com o lançamento de Ubuntu 20.04, a próxima versão LTS (suporte de longo prazo) de uma das distribuições mais populares. Como com Ubuntu 18.04 há dois anos, esperamos que esta se torne nossa imagem mais amplamente utilizada, que já está disponível para todos os clientes da Linode.

A disponibilidade da distribuição no mesmo dia tornou-se a norma aqui na Linode, graças à automação que desenvolvemos em torno da construção, testes e implantação de novas imagens. Mas o que é exatamente uma imagem (ou um modelo como às vezes são chamados), e o que é que vai fazer com elas? Para responder a essa pergunta, começaremos analisando como as instalações de sistemas operacionais normalmente funcionam.

Instalando um sistema operacional

Você pode estar familiarizado com o processo de instalação manual de um sistema operacional em um computador doméstico ou em um servidor. Geralmente envolve baixar uma ISO de instalação, gravá-la em um CD ou drive USB, e inicializar o sistema a partir daí. A partir daí, você normalmente executa uma série de menus (ou às vezes comandos manuais) que lhe permitem controlar vários aspectos da instalação, como qual disco rígido instalar, que software/pacotes você gostaria de incluir, e talvez alguma personalização, como definir um nome de usuário e senha. Quando tudo estiver feito, você terá um SO (esperançosamente) totalmente funcional que você pode inicializar e começar a usar.

Este processo funciona suficientemente bem para usuários individuais que realizam instalações únicas, mas se você precisar instalar mais do que um pequeno punhado de sistemas, então o processo de instalação manual é simplesmente inviável. É aqui que entram as imagens.

O que é uma imagem?

Uma imagem é essencialmente um sistema operacional pré-instalado que você pode implantar em tantos sistemas quantos você precisar. Ela funciona realizando uma instalação normal uma vez e depois fazendo uma cópia dessa instalação que você pode posteriormente "colar" em outro sistema. Há uma variedade de formas e formatos nos quais você pode armazenar imagens para uso posterior, mas na maioria das vezes são cópias byte por byte exatas da instalação original.

Agora só precisamos realizar uma instalação manual uma vez, e podemos reutilizá-la em qualquer outro lugar. Mas ainda podemos fazer melhor. A Linode suporta uma grande variedade de distribuições, desde os suspeitos habituais (Debian, Ubuntu, CentOS, OpenSUSE) até alguns que você pode não encontrar em outros fornecedores (Alpine, Arch, e até mesmo Gentoo). Cada um deles tem seu próprio cronograma de lançamento e suporte vitalício. Realizar instalações manuais para todas as nossas distros suportadas (mesmo que apenas uma vez) e levar tempo para garantir que as imagens resultantes funcionem e não contenham nenhum erro levaria uma enorme quantidade de tempo e seria muito propenso a acidentes. Assim, em vez disso, optamos por automatizar o próprio processo de construção da imagem, com a ajuda de uma ferramenta maravilhosa chamada Packer feita pela HashiCorp.

Automatizando a construção

Mesmo que cada distribuição Linux compartilhe uma base comum (a saber, o kernel Linux), todas elas são muito diferentes umas das outras, inclusive a forma como são instaladas. Algumas distros usam instruções de linha de comando, outras usam interfaces de menu, e algumas incluem maneiras de navegar e fornecer respostas automáticas a esses menus. Felizmente, Packer é uma ferramenta muito versátil e pode lidar com todos estes casos de uso.

A primeira coisa que fazemos é instruir a Packer a criar uma máquina virtual (ou VM) que se assemelhe o mais próximo possível a um Linode. Isto significa emular o mesmo "hardware" e características que usamos para os Linodes reais. Desta forma, a instalação será realizada em um ambiente que se assemelha muito ao ambiente de tempo de execução final. Imagine instalar um sistema operacional em um drive USB e depois usar esse drive para inicializar um computador completamente diferente. Se você tiver sorte, as coisas podem funcionar, mas na maioria das vezes algum dispositivo de hardware não será detectado ou talvez ele não inicialize de forma alguma. Ao ter um ambiente de instalação que combine com o ambiente de funcionamento real, eliminamos estes problemas.

Assim que a VM for criada, a Packer a inicializará a partir da ISO de instalação da distro, que ela vai buscar a partir de uma URL especificada. O processo a partir daqui varia muito entre as distros. Para as distros orientadas por comando, como Arch, alimentamos um script bash que realiza uma instalação básica. Para as distros acionadas por menu, como a Ubuntu, usamos o método preferido da distribuição para fornecer respostas ao instalador (tipicamente ou Preseed em Debian-like distros ou Kickstart em distros tipo RHEL). Além de nossa VM, a Packer também cria um pequeno servidor HTTP que permite que quaisquer arquivos necessários sejam transferidos para a VM.

Tudo isso é controlado através de um arquivo JSON que define as configurações e opções de construção que a Packer irá utilizar. Para iniciar uma construção, precisamos simplesmente executar (por exemplo): packer build ubuntu-20.04.json.

Customização

Na maioria das vezes, realizamos instalações que são o mais baunilhado possível. Isto significa instalar quaisquer pacotes que a distro dada considerar como "padrão" (às vezes referidos como "base" ou "padrão"). Além destes pacotes padrão, também instalamos um pequeno punhado do que chamamos de pacotes "de suporte": utilitários básicos como iotop, mtr, e sysstat que podem ajudar a depurar quaisquer problemas que possam surgir. Como resultado, a equipe de suporte da Linode também pode razoavelmente assumir que estas ferramentas estão instaladas enquanto prestam assistência aos clientes.

Após a instalação estar concluída, mas antes que a VM seja desligada, fazemos algumas personalizações finais para garantir a funcionalidade adequada com todas as características da plataforma Linode. Por exemplo, asseguramos que o bootloader seja configurado com as configurações corretas para LISH (nossa ferramenta para acesso de console fora da banda). Em geral, porém, tentamos manter as coisas o mais próximo possível de suas configurações padrão. Desta forma, um usuário que prefere uma distro específica terá o que está familiarizado e não terá vontade de dirigir o carro de outra pessoa.

Embalagem

Após o término da instalação e configuração, a Packer desliga a VM e exporta sua imagem de disco para um arquivo. Pode parecer que terminamos, mas ainda restam alguns passos. O disco rígido de um computador típico começará com uma tabela de partições (ou MBR, ou GPT em sistemas mais novos). Os Linodes são um pouco únicos na medida em que o próprio carregador de inicialização GRUB realmente vive em nossos hosts, em vez de em cada Linode (a configuração ainda é lida a partir do Linode, entretanto). Isto significa que podemos realmente tirar a tabela de partição completamente, deixando-nos apenas com uma única partição.

Para conseguirmos isso, nós executamos fdisk -l disk.img na imagem do disco para determinar onde a partição começa e termina, e qual é o tamanho do bloco. Usamos então dd if=disk.img of=part.img bs=### skip=### count=### para "empurrar" a divisória usando o offset de partida de nosso comando anterior. Mais especificamente, cada "####" nesse comando é substituído pela saída de nosso comando anterior fdisk comando.

Assim como em um computador novo, a maior parte do espaço na unidade estará vazia, e isto se refletirá em nossa imagem de disco. Seria tolice copiar todos esses bytes "vazios" ao redor, então a próxima coisa que faremos é esvaziar a imagem (mais tarde, quando você implanta uma imagem em seu Linode, nós re-inflacionar para preencher o espaço disponível em sua instância). Como todas as nossas imagens utilizam partições ext4, podemos executar resize2fs -M part.imgO que diminuirá automaticamente nossa imagem até seu menor tamanho possível, removendo o espaço vazio. Finalmente, para garantir a integridade da imagem resultante, realizamos uma fsck sobre ele antes de comprimi-lo com gzip.

Teste

Depois que a imagem é construída e preparada, a próxima etapa do processo é garantir que ela realmente funcione. Nossa imagem recém-cunhada é implantada em um ambiente de teste, onde várias instâncias do Linode são provisionadas da imagem em várias configurações diferentes. Desenvolvemos uma suíte de testes automatizados que verifica todos os tipos de coisas diferentes, como conectividade de rede e um gerenciador de pacotes de trabalho, bem como vários recursos da plataforma Linode, como Backups e redimensionamento de disco; Jogamos o livro nessas instâncias. Se alguma verificação falhar, o processo será imediatamente abortado e a compilação falhará, juntamente com alguns detalhes sobre qual verificação falhou e por quê.

Construir e testar de forma automatizada como esta permite ciclos rápidos de desenvolvimento que, por sua vez, nos permitem liberar melhores imagens, mais rapidamente. Estruturamos nosso processo de testes de tal forma que acrescentar novas verificações é trivial. Se um cliente relatar um problema com uma de nossas imagens, podemos rapidamente liberar uma correção e adicionar outro item à nossa crescente lista de verificações -quase como um sistema imunológico!

O mesmo, mas diferente

A implantação de sistemas em massa a partir de uma imagem comum é ótima, mas e as coisas que são exclusivas de uma instância específica, tais como a senha raiz ou a configuração de rede? Nossas imagens são configuradas para usar DHCP, o que fará com que seu sistema receba automaticamente seu endereço IP atribuído e um hostname único de nossos servidores DHCP. Entretanto, também fornecemos uma variedade de "helpers" como o Network Helper (que irá configurar automaticamente a rede estática em seu Linode), e nossa ferramenta de redefinição de senha root (que define sua senha root inicial e que você também pode usar em emergências, caso precise redefini-la). Estas ferramentas permitem, por exemplo, que informações específicas sejam aplicadas ao seu Linode em cima da imagem base.

É claro que nem todas as distro lidam com essas tarefas da mesma forma, portanto, nossa ferramenta precisa estar ciente de como fazer essas coisas em todas as nossas distros apoiadas. Novas versões principais de uma distro normalmente exigirão algumas atualizações nestes sistemas a fim de que as coisas funcionem plenamente. Por exemplo, Debian tradicionalmente configura a rede em /etc/network/interfacesenquanto CentOS coloca configurações de rede em /etc/sysconfig/network-scripts. Felizmente, a maioria das distros fornece lançamentos beta antes do tempo, o que nos dá muito tempo para fazer essas mudanças e garantir que tudo esteja pronto para o dia do lançamento.

Conclusão

Como você pode ver, há muitas coisas que dão suporte a uma nova distro, então qual é a real vantagem de automatizar este processo? Bem, anos atrás antes de termos o processo que temos hoje, uma típica liberação de distro (desde a construção até os testes e a disponibilidade) levaria na melhor das hipóteses um dia inteiro, mas geralmente vários dias, e muitas pessoas estariam envolvidas. Em comparação, o lançamento de hoje do Ubuntu 20.04 exigiu apenas 5 linhas de mudanças de código e levou menos de uma hora do início ao fim. Esta abordagem de construção de imagens nos poupa muito tempo, aborrecimentos e resulta em construções consistentes que são minuciosamente testadas e em constante melhoria. Se você tiver alguma sugestão ou coisa que gostaria de ver, nos avise! Eu ando no IRC como blaboon na OFTC e lblaboon na Freenode. Se você estiver interessado em experimentar Packer por conta própria, eles têm uma ótima documentação que pode ser encontrada aqui. Também temos nosso próprio construtor Linode para Packer que você pode usar para criar suas próprias imagens personalizadas em nossa plataforma. Mais documentação para utilizar o construtor Linode para Packer pode ser encontrada em nossa biblioteca de Guias e Tutoriais aqui.


Não é um cliente Linode? Inscreva-se aqui com um crédito de 20 dólares.


Comentários (4)

  1. Author Photo

    This is brilliant and very timely (for me) as I happened to spend some of last weekend to “reverse engineer” the build process (and discovered the GRUB config quirks) while tried to test migrating a Linode VM over to a on-premises (lab) VM Host and vice versa. Maybe this would be a good write-up, if you are searching for tutorial/blog topics. Many thanks for publishing this!

  2. Nathan Melehan

    Hey A. –

    That sounds like a cool topic! If you’re interested, we actually have a paid freelance contributor program for our documentation library called Write For Linode. You can learn more about the program and apply to it here: https://www.linode.com/lp/write-for-linode/

    • Author Photo

      Hi Nathan
      Thanks for this, it looks very tempting. I started to work on the process for the first migration but I was stopped by Grub2. As described in the Packaging section above, the stripped out boot partition stops me to boot up the the image in my VM Host and I haven’t been able boot up the image dd’d out of Linode. If I create a vanilla VM image with the same Ubuntu version as in my Linode VM, the (virtual) disk is partitioned with two partitions, sda1 hosting grub (I assume this is what you strip out in the build process) and sda2, which is “/”. The image “exported” out of Linode, on the other hand has only a single partition as described above. Is there any documentation describing how to undu the stripping out of sda1, or how insert a new boot (sda1) partition back into the image? Many thanks, A

      • Author Photo

        Ok, I managed to get through booting my local clone in the end and it turns out that the startup process didn’t crash (as I thought), it was just slow*. It is because (unsurprisingly) it has a hard-coded static IP address which now lives on the wrong network, so I had to wait until the network config time-out* during the boot-up process.

        That’s easy enough I’ll just change the config in /etc/network/interfaces (the default/standard place in Ubuntu, and as also mentioned in this article). Looking at the “interfaces” file it, is blank with a note that things have moved on (since I last had to deal with linux networking) and it is now handled by something called “netplan”. [grrrrr….]

        No matter, it can’t be that hard, let’s see what /etc/netplan says. Well, the yaml file says my ethernet interface should be called `enp0s3` and should be getting the address from dhcp. But my actual interface name is `eth0` and has a static address. Where is this coming from?! [&$#^%#]

        Time to “brute force” search the entire config.
        `find /etc/ -exec grep ‘12.34.56.78’ {} \; 2>/dev/null` results in 3 hits, one is by an application so there are only two potential places to change, it might be easy enough to check**:

        `grep -Rn ‘12.34.56.78’ * 2>/dev/null`

        systemd/network/05-eth0.network
        systemd/network/.05-eth0.network

        It was auto-generated by Linode’s Network Helper (as described in the article) which is not available in my lab, unsurprisingly, so let’s just copy back the original config:

        `cp 05-eth0.network 05-eth0.network.bak`
        `cp .05-eth0.network 05-eth0.network`
        `shutdown -r now`

        Bingo!!! The VM came up with a new dynamic IP address and I can ping and nslookup to my heart content!!! I haven’t checked if the actual web application survived the extraction, and what else may have broken in the process.

        *and probably a lot more linode specific configs that are inaccessible to my local clone.
        **The actual IP address is not this

        Lessons learned: It is a lot more complicated to migrate out of Linode to a local VM or different cloud and require a lot of effort to fix/adapt the extracted application and the OS, it would be a lot faster just to build the lab up from the ground up. It might be a simpler process to move the other way around (i.e. develop in my own lab and pull the result into Linode) but wouldn’t hold my breath trying.

        Not sure if my experience warrants an article beyond this (chain of) comment(s). But it was a great weekend project and an inspirational learning exercise, many thanks, Linode!

Deixe uma resposta

Seu endereço de e-mail não será publicado. Os campos obrigatórios estão marcados com *