Premier Training & Business Partner Red Hat

LinuxKit, unikernel e dintorni

Fabrizio Soppelsa
Ti piacerebbe diventare anche tu uno di noi e
pubblicare i tuoi articoli nel blog degli RHCE italiani?

Alla DockerCon17 è stato rilasciato opensource LinuxKit, ulteriore Kit che si aggiunge ai vari InfraKit, DataKit e SwarmKit nell’ecosistema dei progetti Moby.

LinuxKit, a toolkit for building custom minimal, immutable Linux distributions.

Questo strumento, al momento in fase (molto) alpha, si rivolge ad utenti, hypervisor e pipeline di CI/CD che devono costruire in modo ripetibile, veloce e facile immagini Linux per container minime, immutabili e sicure da gestire poi con meccanismi IaC come Terraform o InfraKit.

Ripetibile, perché immagini uguali sono prodotte da configurazioni YAML uguali. Veloce, perché il build richiede pochi secondi. Facile, perché chiunque abbia provato a creare sistemi Linux (unikernel) minimali sa quanto può essere molesto e fuorviante il processo: la promessa di LinuKit è quella di rendere tutto fattibile con un comando.

Il risultato è un’immagine Linux (.img o .iso) pronta a girare su qemu, vmware, GCP o hyperkit (OS X) minima, perché si inizializza in pochi secondi e include solo lo stretto necessario in Containerd come configurato (binari, librerie), immutabile, perché fissa requisiti e versioni (soprattutto kernel), e sicura perché riduce al minimo la superficie di attacco.

Il progetto Moby

Contestualmente al lancio di LinuxKit, i prodotti di Docker (in Github) passano sotto il contenitore del progetto Moby. Come promesso non ci saranno cambiamenti di tool e nomi, ma la transizione è in corso. Un’altra volta ancora, innovazione a tutti i costi. Prima di tutti a morire, come al solito, la retrocompatibilità: alcuni repo façade sono in fase di completamento per non rompere i build Go…

I prodotti downstream dentro Moby sono stati separati in Community Edition (CE) e Enterprise Edition (CE).

Come modello community e enterprise, verrà seguito quello di Fedora e Red Hat.

LinuxKit

LinuxKit non è un CoreOS o una distribuzione specializzata per container, ma un toolkit per costruire immagini Linux (al volo, possibilmente) a partire da configurazioni YAML. LinuxKit al momento costruisce immagini partendo da Linux Alpine aggiungendo gli extra in Containerd (Docker stesso nella fattispecie), ma l’idea del progetto è di fare da incubatore a progetti unikernel e altri relativi alla sicurezza dei sistemi operativi.

Una configurazione YAML tipica fissa la versione del kernel e dell’equipaggiamento base (runc, containerd, certificati), e specifica i servizi da aggiungere.

Una build con sshd

Inutile dilungarsi in discussioni teoriche quando il tutto è più semplice da capire con un esempio. Si usa LinuxKit con i comandi moby e linuxkit, che vanno compilati. La toolchain Go viene containerizzata in Docker, quindi non serve installare il compilatore:

$ git clone github.com:linuxkit/linuxkit $GOPATH/src/github.com/linuxkit/linuxkit
$ cd $GOPATH/src/github.com/linuxkit/linuxkit
$ make

Verifichiamo:

➜ linuxkit git:(master) ./bin/moby version
moby version 0.0
commit: f2d6752751318477ec86e4677514d5a4890249c1

Versione 0.0, avevamo già detto che il progetto è nuovo?

Ora, dentro examples/ e projects/ ci sono alcuni YAML di riferimento per incominciare. Creiamo una Alpine a partire dall’esempio di sshd. Occorre aggiungere una chiave valida in sshd.yml prima. Poi:

➜ examples git:(master) ../bin/moby build sshd
Extract kernel image: linuxkit/kernel:4.9.x
Add init containers:
Process init image: linuxkit/init:63eed9ca7a09d2ce4c0c5e7238ac005fa44f564b
Process init image: linuxkit/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9
Process init image: linuxkit/containerd:18eaf72f3f4f9a9f29ca1951f66df701f873060b
Process init image: linuxkit/ca-certificates:e091a05fbf7c5e16f18b23602febd45dd690ba2f
Add onboot containers:
Create OCI config for linuxkit/sysctl:2cf2f9d5b4d314ba1bfc22b2fe931924af666d8c
Add service containers:
Create OCI config for linuxkit/rngd:c42fd499690b2cb6e4e6cb99e41dfafca1cf5b14
Create OCI config for linuxkit/dhcpcd:48e249ebef6a521eed886b3bce032db69fbb4afa
Create OCI config for linuxkit/sshd:e108d208adf692c8a0954f602743e0eec445364e
Add files:
root/.ssh/authorizedkeys
Create outputs:
sshd-bzImage sshd-initrd.img sshd-cmdline
sshd.iso
sshd-efi.iso

Ecco l’output:

➜ examples git:(master) ls -lh sshd
-rw-r--r-- 1 fsoppelsa staff 6.7M Apr 28 11:52 sshd-bzImage
-rw-r--r-- 1 fsoppelsa staff 27B Apr 28 11:52 sshd-cmdline
-rw-r--r-- 1 fsoppelsa staff 40M Apr 28 11:52 sshd-efi.iso
-rw-r--r-- 1 fsoppelsa staff 32M Apr 28 11:52 sshd-initrd.img
-rw-r--r-- 1 fsoppelsa staff 40M Apr 28 11:52 sshd.iso
-rw-r--r-- 1 fsoppelsa staff 1.7K Apr 28 10:44 sshd.yml

Immagini pronte. Lanciamo la VM (nel mio caso su hyperkit):

➜ examples git:(master) ../bin/linuxkit run sshd
[ 1.674388] Freeing unused kernel memory: 1548K (ffff8e7ac987d000 - ffff8e7ac9a00000)
[ 1.679172] Freeing unused kernel memory: 1184K (ffff8e7ac9cd8000 - ffff8e7ac9e00000)

Starting containerd

Welcome to LinuxKit


                        ##         .
                  ## ## ##        ==
               ## ## ## ## ##    ===
           /"""""""""""""""""___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
           ______ o           __/
                          __/
              ___________/


/ # INFO[0000] starting containerd boot...

In circa 3 secondi parte. Ecco cosa fa girare:

/ # runc list
ID PID STATUS BUNDLE CREATED OWNER
dhcpcd 414 running /containers/services/dhcpcd 2017-04-28T16:56:06.1132568Z root
rngd 451 running /containers/services/rngd 2017-04-28T16:56:06.1299713Z root
sshd 458 running /containers/services/sshd 2017-04-28T16:56:06.1408088Z root

Via DHCPd sulla rete interna host, l’interfaccia eth0 prende un indirizzo:

/ # ip a s eth0
4: eth0: <BROADCAST,MULTICAST,UP,LOWERUP> mtu 1500 qdisc pfifofast state UP qlen 1000
  link/ether 02:50:00:00:00:07 brd ff:ff:ff:ff:ff:ff
  inet 192.168.65.8/24 brd 192.168.65.255 scope global eth0

Per fare ssh dentro questa VM di esempio su hyperkit, bisogna avere accesso alla rete interna host Docker, cosa fattibile tramite un container:

➜ examples git:(master) docker run -v ~/.ssh:/root/.ssh -ti jdeathe/centos-ssh ssh 192.168.65.8
The authenticity of host '192.168.65.8 (192.168.65.8)' can't be established.
ECDSA key fingerprint is 19:7b:25:df:47:a4:56:2c:e8:59:6b:f4:a4:01:47:83.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.65.8' (ECDSA) to the list of known hosts.
Welcome to LinuxKit
moby-025000000007:# hostname
moby-025000000007
moby-025000000007:# whoami
root
moby-025000000007:#

Scenari futuri

L’esempio di ssh è quello più banale. Sono già partiti progetti per iniziare a modellare servizi seri partendo da configurazioni LinuxKit (il mio preferito, in projects/kubernetes).

L’idea è quella di trainare tutto questo hype verso la direzione degli unikernel. I sistemi a unikernel non hanno un kernel vero e proprio, ma lo spazio di indirizzi tra kernel e userspace è fuso: le applicazioni compilano staticamente le parti di kernel e le syscall necessarie dentro il proprio binario. Se mi serve un oggetto unikernel per fare ping, non mi servono le syscall di accesso al filesystem o ai processi e la parte di crittografia del kernel. Così, l’oggetto ping unikernel compila se stesso, le raw socket e le primitive di networking e basta.

Qualcuno capace di accedere a un oggetto unikernel non ha modo di lanciare shell o usare script o librerie extra inutilizzate, perché semplicemente non ci sono. È abbastanza interessante? Per unikernel vedasi MirageOS. Però, momento, creare sistemi unikernel è un casino. Ed ecco che arriverà LinuxKit.

Certo, noi tutti amiamo i container (no?), ma unikernel è la prossima big thing.

Info about author

Fabrizio Soppelsa