¡Hola a todos! En su
principio
Todo empezó una tarde lluviosa de septiembre cuando estaba limpiando la máquina que alquilé por 5 dólares en Digital Ocean y que estaba congelada porque Docker había llenado los 24 gigabytes de espacio disponible en el disco con sus imágenes y contenedores. La ironía era que todas estas imágenes y contenedores eran transitorios y sólo eran necesarios para probar el rendimiento de mi aplicación cada vez que se lanzaba una nueva versión de una biblioteca o marco. Intenté escribir scripts de shell y configurar una programación cron para limpiar la basura, pero no sirvió de nada: cada vez terminaba inevitablemente con el espacio en el 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 canalizaciones de compilación a través de un socket de demonio acoplable reenviado a él. Me gustó la idea, pero decidí ir más allá e intentar experimentar ejecutando Docker directamente dentro de Docker. En ese momento, me pareció una solución completamente lógica descargar imágenes de Docker y crear contenedores para todas las aplicaciones que necesitaba para probar dentro de otro contenedor (llamémoslo contenedor provisional). La idea era iniciar un contenedor provisional con el indicador -rm, que elimina automáticamente todo el contenedor y todo su contenido cuando se detiene. Jugué con la imagen de Docker desde el propio Docker (
Práctica. Conos
Me propuse hacer que el contenedor funcionara como necesitaba y continué mis experimentos, lo que resultó en una gran cantidad de cogollos. El resultado de mi autotortura fue el siguiente algoritmo:
-
Lanzamos el contenedor Docker en modo interactivo.
docker run --privileged -it docker:18.09.6
Presta atención a la versión del contenedor, da un paso hacia la derecha o hacia la izquierda y tu DinD se convierte en una calabaza. De hecho, las cosas se estropean con bastante frecuencia cuando se lanza una nueva versión.
Debemos meternos inmediatamente en el caparazón. -
Estamos intentando averiguar qué contenedores se están ejecutando (Respuesta: ninguno), pero ejecutemos el comando de todos modos:
docker ps
Te sorprenderá un poco, pero resulta que el demonio Docker ni siquiera se está ejecutando:
error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 192.168.65.1:53: no such host
-
Ejecutémoslo nosotros mismos:
dockerd &
Otra sorpresa desagradable:
failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: Iptables not found
-
Instale los paquetes iptables y bash (todo es más agradable de trabajar en bash que en sh):
apk add --no-cache iptables bash
-
Iniciemos bash. Finalmente volvemos al caparazón habitual.
-
Intentemos iniciar Docker nuevamente:
dockerd &
Deberíamos ver una larga hoja de registros que termina con:
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
-
Presione Entrar. Estamos de vuelta en la fiesta.
De ahora en adelante, podemos intentar lanzar otros contenedores dentro de nuestro contenedor Docker, pero ¿qué pasa si queremos lanzar otro contenedor Docker dentro de nuestro contenedor Docker o algo sale mal y el contenedor falla? Empezar de nuevo.
Contenedor DinD propio y nuevos experimentos.
Para evitar repetir los pasos anteriores una y otra vez, creé mi propio contenedor DinD:
La solución DinD funcional me dio la posibilidad de ejecutar Docker dentro de Docker de forma recursiva y realizar experimentos más aventureros.
Ahora voy a describir uno de esos experimentos (exitosos) con la ejecución de MySQL y Nodejs.
Los más impacientes podrán comprobar cómo fue aquí.
Entonces, comencemos:
-
Lanzamos DinD en modo interactivo. En esta versión de DinD, necesitamos mapear manualmente todos los puertos que nuestros contenedores secundarios pueden usar (ya estoy trabajando en esto)
docker run --privileged -it -p 80:8080 -p 3306:3306 alekslitvinenk/dind
Entramos en bash, desde donde podemos comenzar inmediatamente a lanzar contenedores secundarios.
-
Inicie MySQL:
docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql
-
Nos conectamos a la base de datos de la misma manera que lo haríamos localmente. Asegurémonos de que todo funcione.
-
Inicie el segundo contenedor:
docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server
Tenga en cuenta que la asignación de puertos será exactamente 8080:8080, ya que ya hemos asignado el puerto 80 desde el host al contenedor principal al puerto 8080.
-
Vamos a localhost en el navegador, nos aseguramos de que el servidor responda “¡Hola mundo!”
En mi caso, el experimento con contenedores Docker anidados resultó bastante positivo y continuaré desarrollando el proyecto y utilizándolo para la puesta en escena. Me parece que esta es una solución mucho más liviana que Kubernetes y Jenkins X. Pero esta es mi opinión subjetiva.
Creo que eso es todo por el artículo de hoy. En el próximo artículo, describiré con más detalle experimentos con la ejecución recursiva de Docker en Docker y el montaje de directorios en contenedores anidados.
PS Si encuentra útil este proyecto, dele una estrella en GitHub, bifurquelo y dígaselo a sus amigos.
Edit1 Errores corregidos, centrados en 2 vídeos.
Fuente: habr.com