Ciao a tutti! Nel mio , ho promesso di parlare dell'esecuzione di Docker in Docker e degli aspetti pratici di questa attività. È giunto il momento di mantenere la mia promessa. Un devops esperto potrebbe obiettare che per chi ha bisogno di Docker dentro Docker, è sufficiente passare il socket del demone Docker dall'host all'interno del container, e questo è sufficiente nel 99% dei casi. Ma non affrettatevi a lanciarmi biscotti, perché si tratta dell'esecuzione reale di Docker all'interno di Docker. Questa soluzione ha molte possibili aree di applicazione e uno di esse è il tema di questo articolo, quindi accomodatevi e allungate le mani davanti a voi.

Inizio
Tutto è iniziato in una piovosa sera di settembre, quando ho pulito una macchina noleggiata a $5 su Digital Ocean, che si era bloccata a causa del fatto che Docker aveva riempito i suoi 24 gigabyte di spazio su disco disponibile con immagini e contenitori. L'ironia stava nel fatto che tutte queste immagini e contenitori erano transitorie e servivano solo per testare il funzionamento della mia applicazione ogni volta che veniva rilasciata una nuova versione di qualche libreria o framework. Ho provato a scrivere script di shell e a configurare la pianificazione cron per rimuovere i file spazzatura, ma questo non ha funzionato: ogni volta si concludeva inevitabilmente con lo spazio su disco del mio server completamente pieno e il server bloccato (nel migliore dei casi). A un certo punto ho trovato un articolo su come eseguire Jenkins in un contenitore e su come potesse creare e rimuovere pipe di build attraverso un socket del demone di Docker. L'idea mi è piaciuta, ma ho deciso di andare oltre e provare a sperimentare con l'esecuzione di Docker all'interno di Docker. All'epoca mi sembrava una soluzione logica scaricare le immagini di Docker e creare contenitori per tutte le applicazioni di cui avevo bisogno per testare all'interno di un altro contenitore (chiamiamolo contenitore di staging). L'idea era di eseguire il contenitore di staging con il flag -rm, che elimina automaticamente l'intero contenitore con tutto il suo contenuto al momento dell'arresto. Ho smanettato con l'immagine di Docker di Docker stesso (), ma si è rivelato troppo ingombrante e non sono riuscito a farlo funzionare come volevo e volevo percorrere tutto il percorso da solo.
Pratica. Difficoltà
Ho preso come obiettivo far funzionare il contenitore come necessario e ho continuato i miei esperimenti, che hanno portato a un numero imprecisato di difficoltà. Il risultato del mio auto-inflitto dolore è stato il seguente algoritmo:
Avviamo il contenitore Docker in modalità interattiva.
docker run --privileged -it docker:18.09.6Fate attenzione alla versione del contenitore, un passo a destra o a sinistra e il vostro DnD si trasforma in una zucca. In effetti, tutto si rompe piuttosto spesso con il rilascio di una nuova versione.
Dobbiamo entrare subito nella shell.Proviamo a scoprire quali contenitori sono in esecuzione (Risposta: nessuno), ma eseguiamo il comando comunque:
docker psSarete un po' sorpresi, ma sembra che il demone Docker non sia nemmeno in esecuzione:
error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 192.168.65.1:53: no such hostProviamo ad avviarlo da soli:
dockerd &Un'altra spiacevole sorpresa:
failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: Iptables not foundInstalliamo i pacchetti iptables e bash (lavorare in bash è comunque più piacevole che in sh):
apk add --no-cache iptables bashAvviamo bash. Finalmente siamo di nuovo nella shell che conosciamo.
Proviamo a lanciare Docker di nuovo:
dockerd &Dobbiamo vedere una lunga serie di log che termina con:
INFO[2019-11-25T19:51:19.448080400Z] Il demone ha completato l'inizializzazione INFO[2019-11-25T19:51:19.474439300Z] API in ascolto su /var/run/docker.sockPremiamo Invio. Siamo di nuovo in bash.
Da questo momento in poi possiamo provare a lanciare altri contenitori all'interno del nostro contenitore Docker, ma cosa succede se vogliamo avviare un altro contenitore Docker dentro il nostro contenitore Docker o se qualcosa va storto e il contenitore 'si arresta'? Dobbiamo ricominciare da capo.
Contenitore DinD personalizzato e nuovi esperimenti
Per non ripetere i passaggi sopra descritti ancora e ancora, ho creato il mio contenitore DinD:
La soluzione DinD funzionante mi ha permesso di eseguire Docker all'interno di Docker in modo ricorsivo e di fare esperimenti più audaci.
Ora sto per descrivere uno di questi (riusciti) esperimenti con MySQL e Nodejs.
I più impazienti possono vedere com'è andata qui.

Quindi, iniziamo:
Avviamo DinD in modalità interattiva. In questa versione di DinD dobbiamo mappare manualmente tutte le porte che potrebbero utilizzare i nostri contenitori secondari (ci sto già lavorando).
docker run --privileged -it -p 80:8080 -p 3306:3306 alekslitvinenk/dindEntriamo nella shell, da cui possiamo subito iniziare a lanciare i contenitori secondari.
Avviamo MySQL:
docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysqlCi connettiamo al database proprio come ci connetteremmo localmente. Verifichiamo che tutto funzioni.
Avviamo un secondo contenitore:
docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-serverSi noti che il mapping delle porte sarà proprio 8080:8080, dato che abbiamo già mappato la porta 80 dall'host al contenitore genitore sulla porta 8080.
Andiamo su localhost nel browser e verifichiamo che il server risponde «Hello World!».
Nel mio caso, l'esperimento con i contenitori Docker annidati si è rivelato piuttosto positivo e continuerò a sviluppare il progetto e a utilizzarlo per lo staging. Mi sembra che sia una soluzione molto più leggera rispetto a Kubernetes e Jenkins X. Ma questa è solo la mia opinione personale.
Penso che per l'articolo di oggi sia tutto. Nel prossimo articolo descriverò in dettaglio gli esperimenti con l'esecuzione ricorsiva di Docker in Docker e il montaggio delle directory all'interno dei contenitori annidati.
P.S. Se consideri questo progetto utile, ti preghiamo di dargli una stella su GitHub, di forkare e di raccontare ai tuoi amici.
Edit1 Ho corretto gli errori, ho messo il focus su 2 video
Fonte: habr.com
