Come ho avviato Docker all'interno di Docker e cosa ne è venuto fuori

Ciao a tutti! Nel mio articolo precedente, ho promesso di parlare del lancio di Docker in Docker e degli aspetti pratici di questo argomento. È tempo di mantenere la mia promessa. Un devops esperto potrebbe controbattere che chi ha bisogno di Docker dentro Docker, semplicemente inoltra il socket del demone Docker dall'host all'interno del contenitore e questo basta nel 99% dei casi. Ma non affrettatevi a lanciarmi biscotti, perché stiamo parlando di un reale lancio di Docker dentro Docker. Questa soluzione ha molte potenziali aree di applicazione e questa articolo parlerà di una di esse, quindi mettetevi comodi e distendete le mani di fronte a voi.

Come ho avviato Docker all'interno di Docker e cosa ne è venuto fuori

Inizio

Tutto è iniziato in una piovosa sera di settembre, quando stavo pulendo una macchina affittata a $5 su Digital Ocean, la quale si è bloccata completamente perché Docker ha riempito tutti i 24 gigabyte di spazio disco disponibile con le sue immagini e contenitori. L'ironia era che tutte queste immagini e contenitori erano transitori e servivano solo per testare la funzionalità della mia applicazione ogni volta che usciva una nuova versione di qualche libreria o framework. Ho provato a scrivere script shell e a impostare una pianificazione cron per liberare spazzatura, ma non ha funzionato: ogni volta finiva inevitabilmente con lo spazio disco del mio server consumato e il server bloccato (nel migliore dei casi). A un certo punto mi sono imbattuto in un articolo su come eseguire Jenkins in un contenitore e su come possa creare e cancellare pipeline di build attraverso un socket del demone Docker passato a esso. L'idea mi è piaciuta, ma ho deciso di andare oltre e provare a sperimentare con il lancio diretto di Docker dentro Docker. A quel tempo mi sembrava una soluzione logica scaricare le immagini Docker e creare contenitori di tutte le applicazioni di cui avevo bisogno per testare all'interno di un altro contenitore (chiamiamolo contenitore di staging). L'idea era quella di avviare il contenitore di staging con l'opzione -rm, che elimina automaticamente l'intero contenitore con tutto il suo contenuto quando viene arrestato. Ho grattato un po' con l'immagine Docker del Docker stesso (https://hub.docker.com/_/docker), ma si è rivelata troppo ingombrante e non sono riuscito a farla funzionare come desideravo, e volevo percorrere tutto il cammino da solo.

Pratica. Problemi

Ho deciso di far funzionare il contenitore come avevo bisogno e ho continuato i miei esperimenti, i cui risultati sono stati innumerevoli errori. Il risultato della mia auto-tortura è stato il seguente algoritmo:

  1. Avviamo il contenitore Docker in modalità interattiva.

    docker run --privileged -it docker:18.09.6

    Fate attenzione alla versione del contenitore, un passo a destra o a sinistra e il vostro DinD si trasforma in una zucca. In realtà, tutto si rompe abbastanza spesso con l'uscita di una nuova versione.
    Dobbiamo entrare immediatamente nella shell.

  2. Proviamo a scoprire quali contenitori sono attivi (Risposta: nessuno), ma eseguiamo comunque il comando:

    docker ps

    Sarete un po' sorpresi, ma sembra che il demone Docker non sia nemmeno avviato:

    error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 
    192.168.65.1:53: no such host

  3. Facciamo partire noi stesso:

    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 found

  4. Installa i pacchetti iptables e bash (è molto più piacevole lavorare in bash che in sh):

    apk add --no-cache iptables bash

  5. Avviamo bash. Finalmente siamo di nuovo nella shell che conosciamo.

  6. Proviamo a lanciare Docker di nuovo:

    dockerd &

    Dobbiamo vedere un lungo elenco 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 ascolta su /var/run/docker.sock

  7. Premiamo Invio. Siamo di nuovo in bash.

A partire da questo momento, possiamo provare a eseguire altri contenitori all'interno del nostro contenitore Docker, ma cosa succede se vogliamo avviare un altro contenitore Docker all'interno del nostro contenitore Docker o se qualcosa va storto e il contenitore "salta"? Dobbiamo ricominciare da capo.

Il mio contenitore DinD e nuovi esperimenti.

Come ho avviato Docker all'interno di Docker e cosa ne è venuto fuori
Per evitare di ripetere i passaggi sopra descritti più e più volte, ho creato il mio contenitore DinD:

https://github.com/alekslitvinenk/dind

Una soluzione DinD funzionante mi ha permesso di eseguire Docker all'interno di Docker in modo ricorsivo e di condurre esperimenti più audaci.
Uno di questi esperimenti (riuscito) con l'esecuzione di MySQL e Nodejs sto per descriverlo ora.
I più impazienti possono vedere come è andata qui

Guarda il video

Quindi iniziamo:

  1. Avviamo DinD in modalità interattiva. In questa versione di DinD dobbiamo mappare manualmente tutte le porte che possono essere utilizzate dai nostri contenitori secondari (ci sto già lavorando)

    docker run --privileged -it 
    -p 80:8080 
    -p 3306:3306 
    alekslitvinenk/dind

    Entriamo nel container, da dove possiamo subito avviare i container secondari.

  2. Avviamo MySQL:

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

  3. Ci connettiamo al database proprio come ci connetteremmo a esso localmente. Ci assicuriamo che tutto funzioni.

  4. Avviamo il secondo container:

    docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server

    Si noti che il mapping della porta qui sarà proprio 8080:8080, poiché abbiamo già mappato la porta 80 dall'host al container genitore sulla porta 8080.

  5. Andiamo su localhost nel browser e verifichiamo che il server risponda 'Hello World!'.

Nel mio caso, l'esperimento con i container Docker nidificati si è rivelato piuttosto positivo e continuerò a sviluppare il progetto e a usarlo per lo staging. Penso che sia una soluzione molto più leggera rispetto a Kubernetes e Jenkins X. Ma questa è solo la mia opinione soggettiva.

Credo che per l'articolo di oggi sia tutto. Nel prossimo articolo descriverò più dettagliatamente gli esperimenti sul lancio ricorsivo di Docker in Docker e il montaggio di directory all'interno dei container nidificati.

P.S. Se ritenete che questo progetto sia utile, vi prego di dargli una stella su GitHub, di fare un fork e di raccontarlo ai vostri amici.

Edit1 Ho corretto gli errori, ho messo a fuoco 2 video.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster