Docker’s Fundamentals parte 3

Una delle caratteristiche principali di Docker è la possibilità di costruire facilmente containers propri. Partire dalle immagini ufficiali presenti nel Docker Hub semplifica la vita dell’architetto dell’infrastruttura. Non soddisfa però tutte le esigenze che si possono presentare. Come sa ogni buon piastrellista: «è più facile adattare la mattonella al pavimento che il pavimento alle mattonelle». Proviamo quindi a cucinare la nostra ricetta, prima di passare al McDrive offertoci dal Docker Hub.

Il comando docker build costruisce l’immagine personalizzata eseguendo le istruzioni contenute nel Dockerfile. Il comando docker run lancerà l’immagine costruita da build creando il container, uno distinto per ciascuna invocazione del docker run.

Il Dockerfile assomiglia concettualmente ad un classico file batch. Il verbo build interpreta in modo sequenziale il contenuto testuale presente nel file, aspettandosi un’organizzazione prefissata nella sequenza dei comandi presenti.

# A basic apache server. To use either add or bind mount content under /var/www

FROM ubuntu:12.04

MAINTAINER Kimbro Staken version: 0.1

RUN apt-get update && apt-get install -y apache2 && apt-get clean && rm -rf /var/lib/apt/lists/

ENV APACHE_RUN_USER www-data

ENV APACHE_RUN_GROUP www-data

ENV APACHE_LOG_DIR /var/log/apache2

EXPOSE 80

CMD [“/usr/sbin/apache2”, “-D”, “FOREGROUND”]

La direttiva FROM indica l’immagine base da cui parte la build, in questo caso ubuntu:12.04. È la prima direttiva che docker build si aspetta di eseguire e definisce l’immagine di origine. Docker Hub ci aiuta anche nella build. Ci dà un’immagine base pre-ottimizzata e personalizzabile. Questa direttiva ci consente di usare un’approccio incrementale alla costruzione delle nostre immagini. Per pulizia possiamo partire da un’immagine con il solo sistema operativo di riferimento, con il minimo indispensabile per funzionare. Allo stesso modo, FROM parte da un’immagine qualsiasi, aggiungendo il risultato delle specifiche RUN e COPY all’immagine risultante. Possiamo partire da un’immagine Apache e aggiungere il pacchetto phpMyAdmin, ottenendo un’immagine da cui docker run crea un’interfaccia web verso un DBMS MySQL.

La direttiva MAINTAINER, indica l’autore e la versione dell’immagine. La direttiva RUN, esegue in fase di costruzione un gruppo di comandi. Il suo uso classico è richiamare il gestore di pacchetti per aggiungere software e cancellare i file e cartelle superflue ai futuri containers. Il RUN può essere: singolo o multilinea.

Il RUN singolo accorpa con le regole di pipe i comandi in un’unica stringa. Nell’esempio: crea il db dei pacchetti && installa Apache && cancella le cache && cancella l’archivio pacchetti.

Il RUN multilinea aumenta la leggibilità del Dockerfile, diminuendo le prestazioni dei containers risultanti! Ogni direttiva RUN crea uno strato a sola lettura nell’organizzazione dello union mount realizzato da AUFS *.

2016_04_09_Docker01
Figura 1 – Run Docker

Più alta è la pila degli strati aufs, maggiore è il tempo di visita e la conseguente restituzione dell’informazione richiesta.

2016_04_09_Docker02
Figura 2 – Schema AUFS

È consigliabile, nell’ottica di ottimizzare le performance del filesystem, utilizzare una singola direttiva RUN nel Dockerfile. Per immagini complesse è più vantaggioso procedere con un approccio incrementale, usando delle immagini intermedie. Oppure, con l’ottica della massima efficienza e flessibilità, comporre con docker-compose più containers atomici in una struttura complessa è la strada migliore.

La direttiva ENV crea ed assegna un valore di default alle variabili di environment. Nell’esempio vediamo definire utente e gruppo con cui verranno eseguiti i processi Apache e il path in cui scrivere i file di log. I valori assegnati sono sostituiti in caso di assegnazioni esplicite fatte nel docker run con l’opzione -e, alla creazione del container. I file di configurazione dell’Apache nel nostro esempio, con il formato «direttiva» ${«variabile di environment»}, usano i valori delle variabili stanziate al momento del docker run.

Con la direttiva EXPOSE definiamo la porta TCP interna al container che esporremo dall’ip del docker-node con l’opzione -p, in questo caso la porta 80 su cui ascolta il daemon Apache. Il Dockerfile termina con la direttiva CMD con cui assegnamo all’immagine il comando di default da eseguire al docker run dell’immagine, nel caso non sia indicato esplicitamente un comando da eseguire alla creazione del container.

* AUFS è un filesystem unificato. Significa che esso prende multiple directory nello stesso host, impilandole una sopra l’altra, dando una visione complessiva all’utente. Per questa caratteristica AUFS usa lo union mount.