Home
Usare Docker dentro Docker: si può

20 Gennaio 2021

Usare Docker dentro Docker: si può

di

È possibile utilizzare la tecnologia dei container software per mettere un container dentro un altro? E quali opportunità può presentare? Alcune personaggi autorevoli della comunità lo sconsigliano… e quindi dovevo assolutamente provarlo.

Hands on!

Sono quindi partita da zero, ossia dall’immagine Docker-in-Docker ufficiale. Collegandosi al Docker Hub, è infatti possibile visualizzare un repository chiamato proprio Docker dove sono state pubblicate diverse versioni di questo innesto di sistema di containerizzazione.

Docker in Docker

Docker dentro Docker, pronto da scaricare e usare.

Analizzando i tag, ho visto che era presente una versione particolare, chiamata dind, sulla quale però esista pochissima documentazione; l’unico esempio davvero calzante è quello pubblicato all’interno della pagina ufficiale del repository, mostrato nella figura seguente: viene mostrato come eseguire l’immagine Docker taggata dind, la quale avvia un container con il demone Docker già avviato.

Programmare con Python, con Serena Sensini

Esecuzione di dind e lancio di un container con Docker già avviato

Esecuzione di dind e lancio di un container con Docker già avviato

Per iniziare a smanettare un po’, ho provato i seguenti passaggi nella speranza di ottenere dei risultati interessanti. Intanto, ho eseguito l’immagine docker dopo averla scaricata, eseguendo i comandi:

$ docker pull docker && docker run --privileged -it docker

Iscriviti alla nostra newsletter

Piuttosto sorpresa, appena entrata nella shell ho verificato che il demone Docker fosse funzionante, ma non è stato così: l’errore che si presenta è il seguente:

$ Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

Se il demone non è stato avviato, proviamo a farlo manualmente: eseguiamo quindi dockerd. Ecco un altro errore:

$ Error starting daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: Iptables not found

Nessun problema, vuol dire che manca il pacchetto iptables; andiamo quindi ad installarlo:

$ apk add --no-cache iptables

proviamo nuovamente a lanciare il demone Docker:

$ dockerd

L’approccio appena descritto sopra ha un grosso difetto: è difficile basarci i servizi del mondo reale poiché, se qualcosa si blocca, dovremo ricominciare tutto da capo e non possiamo eseguire il nostro DinD (Docker in Docker!) in modo ricorsivo.

Containerizziamo allora la nostra soluzione. Per farla breve, potremmo creare un Dockerfile che abbia come immagine di base quella appena utilizzata; inoltre, potremmo anche decidere di installare direttamente i pacchetti mancanti (come fatto per iptables) e poi eseguire le operazioni di cui abbiamo bisogno.

FROM docker:18.09.6
LABEL maintainer="Serena Sensini"
ENV APP_NAME dind
ENV APP_PATH /opt/${APP_NAME}
RUN apk add --no-cache iptables bash

Come primo esperimento, eseguiamo due container al suo interno, ossia un’immagine di MySQL e un’app NodeJs; dopo aver avviato il nostro container padre, eseguiamo un container per il database:

$ docker run --name mysql -e MYSQL_ROOT_PASSWORD = password -d -p 3306: 3306 mysql

Ora dovremmo essere in grado di connetterci al nostro database. Proviamo con un client qualsiasi a connetterci al database e vediamo se risponde:

Connessione al database MySQL

Facciamo partire il database MySQL.

Nel passaggio successivo, lanciamo una semplice app NodeJs come sorella del nostro container MySQL; al solo fine di rendere funzionante l’esempio, modifichiamo il Dockerfile per copiare al suo interno l’app NodeJs e mostriamo il codice di quest’ultima che non fa altro che restituire il classico – ma mai banale – Hello World!

Dockerfile

FROM alpine
LABEL maintainer="Serena Sensini"
ENV APP_NAME dummy
ENV APP_INSTALL_PATH /opt/${APP_NAME}
WORKDIR ${APP_INSTALL_PATH}
COPY app ./runtime
COPY scripts .
RUN apk add --no-cache nodejs bash && \
chmod -R 777 ${APP_INSTALL_PATH}
EXPOSE 8080/tcp
ENTRYPOINT [ "./init.sh" ]

app/server.js

const http = require('http');
const port = 8080;
const requestHandler = (req, res) => {
res.write("Hello World!");
res.end();
}
http
.createServer(requestHandler)
.listen(port, () => {
console.log(`Server running at http://localhost:${port}/`);
	}
)
$ docker run -d --rm -p 8080: 8080 alekslitvinenk / hello-world-nodejs-server

Ora, dopo aver eseguito correttamente quest’ultima immagine, possiamo aprire il browser e vedremo un risultato come questo:

Hello World

Hello World!

Conclusioni

Se eseguissimo un container Docker che al suo interno ospita esso stesso Docker installato, sarebbe possibile eseguire Docker all’interno di un’immagine Docker?

Come abbiamo visto, la risposta è sì; tuttavia, si tratta di una pratica generalmente non consigliata, perché causa molti problemi tecnici di basso livello, che hanno soprattutto a che fare con il modo in cui Docker è implementato sul sistema operativo, e che sono spiegati in dettaglio nel post di Jérôme Petazzoni riportato all’inizio dell’articolo.

La realtà dei fatti è che spesso chi lavora nel settore IT si trova davanti le sfide più improbabili: un caso potrebbe essere quello di costruire un ambiente in cui copio la mia applicazione, la avvio tramite container, la controllo, e la arresto, tutto questo usando un container. Potrebbe capitare infatti di avere a che fare con un sistema già containerizzato all’interno del quale si devono installare delle applicazioni, le quali sono a loro volta containerizzate: se questo sembra uno scioglilingua, in realtà è una situazione che capita più spesso di quanto si pensi (e non si tratta di un esercizio di stile).

Anche per questa ragione, esistono diverse tecnologie che rispondono alle esigenze di containerizzazione e che si stanno facendo sempre più largo nel mondo del settore IT: sul sito Open Container Initiative è possibile trovare alcune delle informazioni su strumenti alternativi che sono comunque molto validi, sebbene non sempre diffusi come Docker. Un esempio è Podman: esistono diversi repository in rete che mostrano in che modo è possibile usarlo come alternativa a Docker oppure installarlo all’interno di un container Docker, per poter scaricare immagini e avviare servizi, ma non solo. Ne parlerò!

Puoi approfondire questi concetti sul libro Docker.

Immagine di apertura di Diego Fernandez su Unsplash.

L'autore

  • Serena Sensini
    Serena Sensini è un ingegnere informatico con esperienza nella progettazione e nello sviluppo di soluzioni web e stand-alone from scratch. Appassionata di AI, Deep Learning e Data Analysis, e di linguaggi come Python e R, lavora come Enterprise Architect presso Dedalus e collabora con diverse associazioni no profit con cui tiene corsi e seminari.

Vuoi rimanere aggiornato?
Iscriviti alla nostra newletter

Novità, promozioni e approfondimenti per imparare sempre qualcosa di nuovo

Gli argomenti che mi interessano:
Iscrivendomi dichiaro di aver preso visione dell’Informativa fornita ai sensi dell'art. 13 e 14 del Regolamento Europeo EU 679/2016.

Corsi che potrebbero interessarti

Tutti i corsi
progettare-una-landing-page-cover Corso Online

Progettare una Landing Page - Che Funziona

Vuoi migliorare l'efficacia dei testi di una landing page? Valentina Di Michele e Andrea Fiacchi ti insegnano cosa fare e cosa evitare per progettare i contenuti di una pagina che converte.

99,00

con Valentina Di Michele, Andrea Fiacchi

machine-learning-per-tutti-cover Corso Online

Machine Learning & Big Data per tutti

Vuoi scoprire cosa significano Machine Learning e Big Data e come i computer possono realmente imparare in maniera automatica? Questo corso di Andrea De Mauro fa al caso tuo.

con Andrea De Mauro

corso-data-governance Simone Aliprandi Corso Online

Data governance: diritti, licenze e privacy

I dati sono ovunque intorno a noi ma per poterli utilizzare in sicurezza bisogna confrontarsi con temi complessi che riguardano licenze, proprietà intellettuale e privacy. Se non ti senti sicuro o hai paura di prendere la decisione sbagliata, il corso di Simone Aliprandi fa per te.

con Simone Aliprandi