Hola a todos! En mi artículo anterior , prometí hablar sobre el lanzamiento de Docker en Docker y los aspectos prácticos de la aplicación de esta lección. Es hora de cumplir nuestra promesa. Un devodor experimentado, tal vez, argumentaría que aquellos que necesitan Docker dentro de Docker simplemente arrojan el zócalo del demonio Docker desde el host dentro del contenedor y esto es suficiente en el 99% de los casos. Pero no te apresures a arrojarme galletas, porque hablaremos sobre el lanzamiento real de Docker dentro de Docker. Esta solución tiene muchos campos de aplicación posibles y este artículo trata sobre uno de ellos, así que siéntese y estire los brazos frente a usted.
Inicio
Todo comenzó en una lluviosa tarde de septiembre cuando estaba limpiando un auto de alquiler de Digital Ocean por $ 5, que colgaba muy apretado porque Docker llenó los 24 gigabytes de espacio disponible en disco con sus imágenes y contenedores. La ironía era que todas estas imágenes y contenedores eran transitorios y solo se necesitaban para probar el rendimiento de mi aplicación cada vez que salía una nueva versión de una biblioteca o marco. Traté de escribir scripts de shell y configurar el calendario de coronas para la limpieza de basura, pero esto no se guardó: cada vez, inevitablemente, el espacio en disco de mi servidor se agotaba y el servidor se bloqueaba (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 tuberías de ensamblaje a través del zócalo Doemon Daemon. Me gustó la idea, pero decidí seguir adelante e intentar experimentar con el lanzamiento directo de Docker dentro de Docker. Entonces me pareció una decisión completamente lógica bombear imágenes de la ventana acoplable y crear contenedores de todas las aplicaciones que necesito para probar dentro de otro contenedor (llamémoslo un contenedor provisional). La idea era ejecutar un contenedor provisional con el indicador -rm, que elimina automáticamente todo el contenedor con todo su contenido cuando se detiene. Rebusqué con la imagen de la ventana acoplable de la propia ventana acoplable ( https://hub.docker.com/_/docker ), pero resultó ser demasiado voluminosa y no pude hacer que funcionara como lo necesitaba y quería hacerlo todo el tiempo.
Practica Golpes
Me propuse hacer que el contenedor funcionara como lo necesitaba y continué mis experimentos, lo que resultó en una gran cantidad de conos. El resultado de mi auto tortura 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, un paso hacia la derecha o hacia la izquierda y tu DinD se convertirá en una calabaza. De hecho, todo se rompe con bastante frecuencia con el lanzamiento de una nueva versión.
Debemos entrar inmediatamente en el caparazón.
Intentando averiguar qué contenedores se están ejecutando (Respuesta: ninguno), pero ejecutemos el comando de todos modos:
docker ps
Te sorprenderás 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
Ejecútelo usted mismo:
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 (es más agradable trabajar en bash que en sh):
apk add --no-cache iptables bash
Empezamos bash. Finalmente estamos de vuelta en el caparazón habitual
intenta iniciar Docker nuevamente:
dockerd &
Deberíamos ver una hoja de registro larga que termina:
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.
A partir de ahora, podemos intentar lanzar otros contenedores dentro de nuestro contenedor Docker, pero ¿qué sucede si queremos elevar otro contenedor Docker dentro de nuestro contenedor Docker o algo sale mal y el contenedor se "volará"? Comience todo de nuevo.
Propio contenedor DinD y nuevos experimentos
Para no repetir los pasos anteriores una y otra vez, creé mi propio contenedor DinD:
https://github.com/alekslitvinenk/dind
La solución de trabajo de DinD me dio la oportunidad de ejecutar Docker dentro de Docker de forma recursiva y realizar experimentos más audaces.
Un experimento (exitoso) con la ejecución de MySQL y Nodejs, voy a describirlo ahora.
Los más impacientes pueden ver cómo fue aquí
Entonces, comencemos:
Inicie DinD de forma interactiva. 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
Nos encontramos en una fiesta, desde donde podemos comenzar inmediatamente a lanzar contenedores subsidiarios.
Iniciamos 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 nos conectaríamos a ella localmente. Asegúrate de que todo funcione.
Lanzamos el segundo contenedor:
docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server
Tenga en cuenta que la asignación de puertos aquí será exactamente 8080: 8080 , ya que ya hemos asignado el puerto 80 desde el host al contenedor principal en el puerto 8080.
Vamos a localhost en el navegador, estamos convencidos de que el servidor responde "¡Hola Mundo!".
En mi caso, el experimento con los contenedores acoplados adjuntos fue bastante positivo, y continuaré desarrollando el proyecto y usándolo para la puesta en escena. Me parece que esta es una solución mucho más ligera que los mismos Kubernetes y Jenkins X. Pero esta es mi opinión subjetiva.
Creo que esto es todo para el artículo de hoy. En el próximo artículo, describiré con más detalle los experimentos con el lanzamiento recursivo de Docker en Docker y el montaje de directorios en contenedores anidados.
PD: si este proyecto le resulta útil, dele un asterisco en GitHub, bifurque y dígaselo a sus amigos.
Edición1 Errores corregidos , enfocados en 2 videos