Vai al contenuto principale
BlogLinuxGiorno di uscita: Automatizzare la distro Linux (con Ubuntu 20.04)

Giorno di uscita: Automatizzare la distro Linux (con Ubuntu 20.04)

automatizzare le distribuzioni

Ciao a tutti! Sono Brad, un ingegnere di sistemi di Linode. Oggi è un giorno ricco di eventi nel mondo Linux con il rilascio di Ubuntu 20.04, la prossima versione LTS (supporto a lungo termine) di una delle distribuzioni più popolari. Come per Ubuntu 18.04 due anni fa, ci aspettiamo che questa diventi la nostra immagine più diffusa, che è già disponibile per tutti i clienti Linode.

La disponibilità delle distro nello stesso giorno è diventata la norma qui a Linode, grazie all'automazione che abbiamo sviluppato per costruire, testare e distribuire nuove immagini. Ma cos'è un'immagine (o un modello, come viene talvolta chiamato) e cosa comporta la sua creazione? Per rispondere a questa domanda, inizieremo a vedere come funzionano le installazioni del sistema operativo.

Installazione di un sistema operativo

Forse conoscete il processo di installazione manuale di un sistema operativo su un computer di casa o su un server. Di solito si scarica una ISO di installazione, la si masterizza su un CD o un'unità USB e si avvia il sistema da lì. Da qui si passa a una serie di menu (o a volte di comandi manuali) che permettono di controllare vari aspetti dell'installazione, come ad esempio il disco rigido su cui installare, i software/pacchetti che si desidera includere e forse alcune personalizzazioni come l'impostazione di un nome utente e di una password. Una volta terminato tutto, si ha un sistema operativo (si spera) perfettamente funzionante che può essere avviato e utilizzato.

Questo processo funziona abbastanza bene per i singoli utenti che eseguono installazioni una tantum, ma se dovete installare più di una piccola manciata di sistemi, il processo di installazione manuale non è semplicemente fattibile. È qui che entrano in gioco le immagini.

Cos'è un'immagine?

Un'immagine è essenzialmente un sistema operativo preinstallato che può essere distribuito su tutti i sistemi necessari. Funziona eseguendo una sola volta una normale installazione e creando poi una copia di tale installazione che può essere successivamente "incollata" su un altro sistema. Esistono diversi modi e formati in cui è possibile memorizzare le immagini per un uso successivo, ma nella maggior parte dei casi si tratta di copie esatte byte per byte dell'installazione originale.

Ora dobbiamo eseguire un'installazione manuale solo una volta e possiamo riutilizzarla ovunque. Ma possiamo ancora fare di meglio. Linode supporta un'ampia varietà di distribuzioni, che vanno dalle solite sospette (Debian, Ubuntu, CentOS, OpenSUSE) ad alcune che non si trovano su altri provider (Alpine, Arch e persino Gentoo). Ognuno di essi ha un proprio programma di rilascio e una propria durata di supporto. Eseguire installazioni manuali per tutte le nostre distro supportate (anche solo una volta) e prendersi il tempo per assicurarsi che le immagini risultanti funzionino e non contengano errori richiederebbe una quantità enorme di tempo e sarebbe molto incline agli incidenti. Abbiamo quindi scelto di automatizzare il processo di creazione delle immagini, con l'aiuto di un meraviglioso strumento chiamato Packer, realizzato da HashiCorp.

Automatizzare la creazione

Anche se ogni distribuzione Linux condivide una base comune (il kernel Linux), sono tutte molto diverse tra loro, compreso il modo in cui vengono installate. Alcune distribuzioni utilizzano istruzioni a riga di comando, altre utilizzano interfacce a menu e altre ancora includono modi per navigare automaticamente e fornire risposte a tali menu. Fortunatamente, Packer è uno strumento molto versatile e può gestire tutti questi casi d'uso.

La prima cosa da fare è istruire Packer a creare una macchina virtuale (o VM) che assomigli il più possibile a un Linode. Ciò significa emulare lo stesso "hardware" e le stesse caratteristiche che utilizziamo per i Linode reali. In questo modo, l'installazione verrà eseguita in un ambiente che assomiglia molto all'ambiente di runtime finale. Immaginate di installare un sistema operativo su un'unità USB e poi di utilizzare tale unità per avviare un computer completamente diverso. Se si è fortunati, può funzionare, ma il più delle volte qualche dispositivo hardware non viene rilevato o non si avvia affatto. Un ambiente di installazione che corrisponde all'ambiente di lavoro reale elimina questi problemi.

Una volta creata la macchina virtuale, Packer la avvierà dalla ISO di installazione della distro, recuperata da un URL specificato. Il processo varia molto da una distro all'altra. Per le distro guidate da comandi, come Arch, viene fornito uno script bash che esegue un'installazione di base. Per le distribuzioni guidate da menu, come Ubuntu, utilizziamo il metodo preferito dalla distribuzione per fornire le risposte all'installatore (tipicamente Preseed per le distribuzioni simili a Debian o Kickstart per le distribuzioni simili a RHEL). Oltre alla nostra VM, Packer crea anche un piccolo server HTTP che consente di trasferire nella VM tutti i file necessari.

Tutto questo è controllato da un file JSON che definisce le impostazioni e le opzioni di compilazione che Packer utilizzerà. Per avviare una compilazione, è sufficiente eseguire (ad esempio): packer build ubuntu-20.04.json.

Personalizzazione

Per la maggior parte, eseguiamo installazioni il più possibile "vanilla". Ciò significa installare i pacchetti che la distro in questione considera "predefiniti" (a volte indicati come "base" o "standard"). Oltre a questi pacchetti predefiniti, installiamo anche una piccola manciata di quelli che chiamiamo pacchetti di "supporto": utilità di base come iotop, mtr e sysstat, che possono aiutare a debuggare qualsiasi problema possa sorgere. Di conseguenza, il team di assistenza Linode può ragionevolmente presumere che questi strumenti siano installati durante l'assistenza ai clienti.

Al termine dell'installazione, ma prima di spegnere la macchina virtuale, effettuiamo alcune personalizzazioni finali per garantire la corretta funzionalità con tutte le caratteristiche della piattaforma Linode. Ad esempio, ci assicuriamo che il bootloader sia configurato con le impostazioni corrette per LISH (il nostro strumento per l'accesso alla console fuori banda). In generale, però, cerchiamo di mantenere le impostazioni predefinite il più possibile. In questo modo, un utente che preferisce una distro specifica avrà ciò che gli è familiare e non si sentirà come se stesse guidando la macchina di qualcun altro.

Imballaggio

Al termine dell'installazione e della configurazione, Packer spegne la macchina virtuale ed esporta l'immagine del disco in un file. Potrebbe sembrare che abbiamo finito, ma ci sono ancora alcuni passaggi da fare. Il disco rigido di un computer tipico inizia con una tabella di partizione (MBR o GPT nei sistemi più recenti). I Linode sono un po' unici in quanto il bootloader di GRUB risiede sui nostri host, piuttosto che su ogni Linode (la configurazione viene comunque letta dal Linode). Questo significa che possiamo eliminare completamente la tabella delle partizioni, lasciando solo una singola partizione.

Per ottenere questo risultato, si esegue fdisk -l disk.img sull'immagine del disco per determinare l'inizio e la fine della partizione e la dimensione del blocco. Si utilizza quindi dd if=disk.img of=part.img bs=### skip=### count=### per "inforcare" la partizione usando l'offset iniziale del comando precedente. Più precisamente, ogni "###" in quel comando viene sostituito con l'output del nostro precedente comando fdisk comando.

Proprio come in un nuovo computer, la maggior parte dello spazio sull'unità sarà vuoto e questo si rifletterà nell'immagine del disco. Sarebbe stupido copiare tutti questi byte "vuoti" in giro, quindi la prossima cosa da fare è sgonfiare l'immagine (in seguito, quando si distribuisce un'immagine sul proprio Linode, si gonfiare di nuovo per riempire lo spazio disponibile sull'istanza). Dal momento che tutte le nostre immagini utilizzano partizioni ext4, possiamo eseguire resize2fs -M part.imgche ridurrà automaticamente l'immagine alla dimensione più piccola possibile, eliminando lo spazio vuoto. Infine, per garantire l'integrità dell'immagine risultante, si esegue un ultimo fsck prima di comprimerlo con gzip.

Test

Dopo che l'immagine è stata costruita e preparata, la fase successiva del processo consiste nell'assicurarsi che funzioni effettivamente. L'immagine appena creata viene distribuita in un ambiente di test, dove un gruppo di istanze Linode viene fornito dall'immagine in una serie di configurazioni diverse. Abbiamo sviluppato una suite di test automatizzata che verifica tutti i tipi di cose diverse, come la connettività di rete e un gestore di pacchetti funzionante, oltre a varie caratteristiche della piattaforma Linode, come Backups e il ridimensionamento del disco. Se un controllo fallisce, il processo viene immediatamente interrotto e la compilazione fallisce, insieme ad alcuni dettagli su quale controllo è fallito e perché.

Costruire e testare in modo automatizzato consente cicli di sviluppo rapidi che a loro volta ci permettono di rilasciare immagini migliori, più velocemente. Abbiamo strutturato il nostro processo di test in modo che l'aggiunta di nuovi controlli sia banale. Se un cliente ci segnala un problema con una delle nostre immagini, possiamo rilasciare rapidamente una correzione e aggiungere un altro elemento al nostro crescente elenco di controlli, quasicome un sistema immunitario!

Uguale, ma diverso

La distribuzione di massa di sistemi da un'immagine comune è ottima, ma che dire degli elementi unici di un'istanza specifica, come la password di root o la configurazione di rete? Le nostre immagini sono configurate per l'uso di DHCP, il che fa sì che il sistema riceva automaticamente l'indirizzo IP e un hostname unico dai nostri server DHCP. Tuttavia, forniamo anche una serie di "aiutanti", come Network Helper (che configura automaticamente la rete statica sul vostro Linode) e il nostro strumento di reimpostazione della password di root (che imposta la password di root iniziale e che potete usare anche in caso di emergenza, se avete bisogno di reimpostarla). Questi strumenti consentono di applicare informazioni specifiche per l'istanza al vostro Linode, oltre all'immagine di base.

Naturalmente, non tutte le distro gestiscono questi compiti allo stesso modo, quindi i nostri strumenti devono sapere come eseguire queste operazioni su tutte le distro supportate. Le nuove versioni principali di una distro richiedono in genere alcuni aggiornamenti a questi sistemi per farli funzionare completamente. Ad esempio, Debian configura tradizionalmente la rete in /etc/network/interfaces, mentre CentOS colloca le configurazioni di rete in /etc/sysconfig/network-scripts. Fortunatamente, la maggior parte delle distro fornisce versioni beta in anticipo, il che ci dà tutto il tempo per apportare queste modifiche e garantire che tutto sia pronto per il giorno del lancio.

Conclusione

Come si può vedere, ci sono molte cose da fare per supportare una nuova distro, quindi qual è il vero vantaggio di automatizzare questo processo? Anni fa, prima di avere il processo che abbiamo oggi, il rilascio di una tipica distro (dalla costruzione ai test alla disponibilità) richiedeva al massimo un'intera giornata, ma di solito diversi giorni, e molte persone erano coinvolte. In confronto, il rilascio odierno di Ubuntu 20.04 ha richiesto solo 5 righe di modifiche al codice e ha richiesto meno di un'ora dall'inizio alla fine. Questo approccio alla creazione di immagini ci fa risparmiare molto tempo e fastidio e ci permette di ottenere build coerenti, testate a fondo e in costante miglioramento. Se avete suggerimenti o cose che vorreste vedere, fatecelo sapere! Sono presente su IRC come blaboon su OFTC e lblaboon su Freenode. Se siete interessati a provare Packer, la documentazione è ottima e si trova qui. Abbiamo anche il nostro costruttore di Linode per Packer, che potete usare per creare le vostre immagini personalizzate sulla nostra piattaforma. Ulteriore documentazione per l'utilizzo del costruttore Linode per Packer è disponibile nella nostra libreria Guide e Tutorial qui.


Non sei un cliente Linode? Iscrivetevi qui con un credito di 20 dollari.


Commenti (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!

Lascia una risposta

Il vostro indirizzo e-mail non sarà pubblicato. I campi obbligatori sono contrassegnati da *