Cómo lancé Docker dentro de Docker y qué resultó de ello

¡Hola a todos! En mi artículo anterior, prometí hablar sobre cómo ejecutar Docker en Docker y los aspectos prácticos de esta actividad. Ha llegado el momento de cumplir mi promesa. Un devops experimentado podría argumentar que aquellos que necesitan Docker dentro de Docker simplemente pasan el socket del demonio de Docker desde el host al interior del contenedor, y eso es suficiente en el 99% de los casos. Pero no se apresuren a lanzar galletas hacia mí, ya que aquí se tratará de la ejecución real de Docker dentro de Docker. Esta solución tiene muchas posibles áreas de aplicación y de una de ellas trata este artículo, así que acomódense y estiren las manos frente a ustedes.

Cómo lancé Docker dentro de Docker y qué resultó de ello

Introducción

Todo comenzó en una lluviosa noche de septiembre, cuando estaba limpiando una máquina alquilada por $5 en Digital Ocean, que se había colgado debido a que Docker había llenado con sus imágenes y contenedores los 24 gigabytes de espacio en disco disponibles. La ironía era que todas estas imágenes y contenedores eran transitorios y solo se necesitaban para probar el funcionamiento de mi aplicación cada vez que salía una nueva versión de alguna biblioteca o framework. Intenté escribir scripts de shell y configurar un cron para limpiar la basura, pero eso no ayudó: cada vez inevitablemente terminaba con el espacio en disco de mi servidor consumido y el servidor colgado (en el mejor de los casos). En algún momento, me encontré con un artículo sobre cómo ejecutar Jenkins en un contenedor y cómo puede crear y eliminar pipelines de construcción a través del socket del demonio de Docker que se le pasa. Me gustó la idea, pero decidí ir un paso más allá y probar experimentar con la ejecución directa de Docker dentro de Docker. En ese momento, me parecía una solución bastante lógica descargar imágenes de Docker y crear contenedores de todas las aplicaciones que necesitaba para pruebas dentro de otro contenedor (llamémoslo contenedor de staging). La idea era ejecutar el contenedor de staging con la bandera -rm, que elimina automáticamente todo el contenedor con todo su contenido al detenerse. Investigué la imagen de Docker de Docker misma, pero resultó ser demasiado pesada y no pude hacer que funcionara como necesitaba, así que quise recorrer todo el camino yo mismo.https://hub.docker.com/_/docker), pero resultó ser demasiado pesado y no logré hacerlo funcionar como quería y quería recorrer todo el camino yo mismo.

Práctica. Golpes

Me propuse hacer que el contenedor funcionara como necesitaba y continué mis experimentos, cuyos resultados fueron innumerables tropiezos. El resultado de mi auto-flagelación fue el siguiente algoritmo:

  1. Iniciamos el contenedor de Docker en modo interactivo.

    docker run --privileged -it docker:18.09.6

    Tenga en cuenta la versión del contenedor, un paso en falso y su DinD se convierte en calabaza. De hecho, todo se rompe bastante a menudo con el lanzamiento de una nueva versión.
    Debemos entrar directamente al shell.

  2. Intentemos averiguar qué contenedores están en ejecución (Respuesta: ninguno), pero ejecutemos el comando de todos modos:

    docker ps

    Te sorprenderá un poco, pero resulta que el demonio de Docker ni siquiera está en ejecución:

    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. Vamos a iniciarlo nosotros mismos:

    dockerd &

    Otra desagradable sorpresa:

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

  4. Instalamos los paquetes iptables y bash (en bash es mucho más agradable trabajar que en sh):

    apk add --no-cache iptables bash

  5. Iniciamos bash. Finalmente, estamos de vuelta en nuestro shell familiar

  6. intentemos iniciar Docker nuevamente:

    dockerd &

    Deberíamos ver una larga lista de logs que termina en:

    INFO[2019-11-25T19:51:19.448080400Z] Daemon has completed initialization          
    INFO[2019-11-25T19:51:19.474439300Z] API listen on /var/run/docker.sock

  7. Presionamos Enter. Estamos nuevamente en bash.

A partir de este momento, podemos intentar ejecutar otros contenedores dentro de nuestro contenedor de Docker, pero ¿qué pasa si queremos levantar otro contenedor de Docker dentro de nuestro contenedor de Docker o algo sale mal y el contenedor 'se cae'? Comenzar todo de nuevo.

Nuestro propio contenedor DinD y nuevos experimentos

Cómo lancé Docker dentro de Docker y qué resultó de ello
Para no repetir los pasos descritos anteriormente una y otra vez, creé mi propio contenedor DinD:

https://github.com/alekslitvinenk/dind

La solución DinD funcional me permitió ejecutar Docker dentro de Docker recursivamente y llevar a cabo experimentos más audaces.
Ahora voy a describir un experimento (exitoso) de ejecutar MySQL y Node.js.
Los más impacientes pueden ver cómo fue aquí

Reproducir video

Entonces, comencemos:

  1. Iniciamos DinD en modo interactivo. En esta versión de DinD, necesitamos mapear manualmente todos los puertos que pueden usar nuestros contenedores secundarios (ya estoy trabajando en eso)

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

    Entramos en el bash, desde donde podemos comenzar a ejecutar contenedores secundarios de inmediato.

  2. Iniciando MySQL:

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

  3. Nos conectamos a la base de datos de la misma manera en que nos conectaríamos a ella localmente. Asegurémonos de que todo funcione.

  4. Iniciamos el segundo contenedor:

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

    Tenga en cuenta que el mapeo de puertos será precisamente 8080:8080, ya que ya hemos mapeado el puerto 80 del host al contenedor principal en el puerto 8080.

  5. Vamos a localhost en el navegador y nos aseguramos de que el servidor responda con «¡Hola, mundo!».

En mi caso, el experimento con contenedores Docker anidados resultó bastante positivo y continuaré desarrollando el proyecto y usándolo para el staging. Me parece que es una solución mucho más ligera que Kubernetes y Jenkins X. Pero esa es solo mi opinión subjetiva.

Creo que eso es todo para el artículo de hoy. En el próximo artículo describiré con más detalle mis experimentos con la ejecución recursiva de Docker dentro de Docker y el montaje de directorios en contenedores anidados.

P.D. Si considera que este proyecto es útil, por favor, déjele una estrella en GitHub, haga un fork y cuénteselo a sus amigos.

Edit1 Corregí errores, me enfoqué en 2 videos

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster