Docker básico: Docker Desktop y objetos Docker
Quiero ofrecerte lo más completo que me sea posible sobre Docker y sus grandes posibilidades, así como varias de sus herramientas (como Docker Desktop, Docker Engine, Docker Daemon, Docker Compose, hasta Kubernetes) de lo más básico a lo más avanzado.
Índice
- Docker básico: Usar imágenes (para todos los públicos).
- Docker Compose: Usar cómodamente imágenes (para todo quien quiera trabajar más cómodamente con Docker).
- Docker Compose en un proyecto: Uso de imágenes en un desarrollo (para aprender de verdad cualquier arquitectura de desarrollo).
- Imágenes Docker: Gestión de imágenes avanzada por consola (para usuarios avanzados).
- Dockerfile: Directivas y Dockerizar proyectos: trabajar con proyectos Dockerizados (para desarrolladores que quieran dockerizar su proyecto)
- Dockerfile avanzado: multietapa, repositorio y trucos: para especializarse en Dockerizacion (para que desarrolladores y managers controlen los detalles)
Cualquier persona con unos conocimientos mínimos de informática puede usar imágenes Docker y hoy día recomendaría a todo el mundo que aprenda sobre Docker, pues ofrece muchos beneficios y uno de los más básicos es el poder aprender en casa de manera práctica prácticamente cualquier tecnología actual que quieras (desde tecnologías más comunes como bases de datos o servidores, hasta poder llegar a tecnologías empresariales de Big Data y Cloud gratis, si así lo deseas y tienes ganas); otro beneficio sería entender por completo las abstracciones informáticas, si no tienes la suerte de que alguien te lo explique; entre otras beneficios adicionales que detallaré.
Si no tienes pocos o ningún conocimiento sobre Docker, recomiendo leer este artículo como el primero; no obstante, si ya te has pegado con Docker, no es necesario leer estos artículos en orden si ya sabes algo, pudiendo ir directamente al artículo que te interese según tus conocimientos y perfil:
- Para todos (este artículo): teoría básica y usar Docker sin comandos, ejecutar imágenes ya construidas con Docker Desktop.
- Desarrolladores: teoría avanzada con comandos, uso de Docker Compose, construcción de imágenes con Dockerfile y nos centraremos en la creación de microservicios Dockerizados.
- Sistemas: Kubernetes, repositorios y desplegar proyectos Dockerizados.
Este primer artículo quiero que sea muy rápido (pese a todo lo que tiene Docker que ofrecer) y que puedas entender y usar Docker enseguida, sin usar ningún comando en absoluto; por lo que voy a mezclar la teoría con el uso real de Docker para que lo entiendas de la manera más sencilla y que puedas valerte por ti mismo (la teoría estrictamente técnica ya está perfectamente explicada en la web de documentación oficial de Docker: https://docs.docker.com/ ).
Beneficios de Docker
Pero primero he de indicarte las bondades de Docker (y no me pagan nada por ello), pues hoy día la mejor manera de aprender sobre cualquier software técnico es usar Docker y, encima, aprenderás cómo se trabaja en una empresa moderna.
Solo con saber cómo se utilizan las imágenes preconstruidas de Docker te va a abrir un montón de puertas sin necesidad de tener apenas conocimientos, por ejemplo, así se me ocurren:
- ¿Quieres aprender SQL o tener tú propia base de datos en un momento? Pues, en cuestión de segundos y sin instalar nada, podrás usar cualquier base de datos que te imagines (MySQL, PostgreSQL, Cassandra, MongoDB, Neo4j, etc.) y practicar gratis desde tu casa.
- Que en la universidad estás practicando MapReduce mediante Streaming con Spark o con Flink, pero lo haces todo en local con Python o Java bajo esa sensación agridulce de que te falta por aprender cómo se trabaja en un entorno de verdad, pues montas una imagen y ya lo tienes simulado como si estuviera desplegado sobre un servidor empresarial ¿Qué quieres ver cómo funciona en un sistema multi-nodo? Pues copia y pega para desplegar más.
- ¿Necesitas entender cómo funcionan las colas de mensajería? Pues en un momento tendrás montado un Kafka o un RabbitMQ completamente funcional, hasta podrás ponerle conectores (como Debezium, por ejemplo).
- ¿Tienes código Java, Python, PHP, Ruby, Go, etc. o cualquiera que se te ocurra, pero no sabes o no tiene ganas de instalar el compilador en tu ordenador? No pasa nada, en unos segundos los tendrás ejecutando sin tener que instalar nada en tú ordenador.
- Que estás practicando con microservicios desplegados en servidores, pues sin instalar nada, monta un Tomcat, Jetty, Httpd, Node.js, Django, etc. en un momento completamente funcional.
- ¿Quieres aprender sobre la tecnología más avanzada de Big Data y/o IA a bajo nivel? Pues instala lo que quieras y aprende como un profesional que lo utiliza en una empresa real; por ejemplo, podrías usar: ElasticSearch con Kibana, Druid, Hbase, etc.
- ¿Requieres probar herramientas de visualización de datos en tu sistema? Pues adelante: Grafana, Prometheus, Superset, etc.
- Si eres desarrollador sabrás lo que es un “entorno de desarrollo” (otros entornos son integración, producción, etc.) y que a veces puede ser un poco desconcertante el nivel de abstracción que puede tener; pues qué pasa si te digo que entre el proyecto que programas en local y el “entorno de desarrollo” existe otro “entorno intermedio” que simula todo el “entorno de desarrollo” dándote una visibilidad absoluta de todo cuanto ocurre, pero en local, siempre limpio y bajo tú control. Habrás adivinado que se puede hacer con Docker.
Aparte de todo lo que se puede hacer a nivel de uso, también te cuento sus ventajas técnicas:
- Se descentralizan los fallos: Si un contenedor falla, no afectará a otros contenedores que se ejecutan en el mismo sistema.
- Se independizan las dependencias y las versiones: cada contenedor tiene sus propias dependencias y versiones, por lo que no se pisan entre sí (por ejemplo, si en nuestro ordenador primero instalamos Java 17, su instalador sobrescribirá la variable de entorno JAVA_HOME, pero luego, si instalamos Java 8 porque lo necesitamos para código viejo, éste también sobrescribirá la variable JAVA_HOME, por lo que el código nuevo que se ejecute en Java 17 dejará de funcionar; en Docker podremos tener un contenedor con Java 8 y otro con Java 17, cada uno con su código compatible).
¿Qué es Docker?
Todas las anteriores ventajas son de cosecha propia y como efecto secundario de para qué sirve realmente Docker. Pues realmente Docker es una plataforma para construir, desplegar y ejecutar aplicaciones (imágenes Docker) en contenedores (donde se ejecuta una instancia de una imagen).
No me extiendo más, pues la definición de Docker se aprende haciendo, así que empecemos por lo más básico (y ya lo más básico, que es el utilizar “imágenes Docker preconstruidas” que te mencioné antes, te proporcionará un montón de posibilidades).
Instalar Docker
De Docker lo más importante es “Docker CLI” que nos permitirá interactuar con el motor de Docker (“Docker Engine”). Para tenerlo instalado en nuestro ordenador, podremos elegir entre una de las dos maneras siguientes, ELIGE UNA, aunque si estás empezando con Docker te recomiendo “Docker Desktop” (a continuación, te comentaré un montón de nombres que te pueden sonar raros, no te preocupes, los vamos a ir viendo y entendiendo):
- “Docker CE” (Docker Comunity Edition; open source y gratis): Incluye “Docker Engine”, “Docker CLI”, “Docker Daemon”, “Docker Build” y “Docker Compose” (entre otros, que iremos viendo algunos en este artículo y otros en el siguiente artículo).
- “Docker Desktop” (también gratis): Incluye “Docker CE” (todo lo anterior), más una interfaz de usuario y Kubernetes local.
Lo más sencillo es instalar “Docker Desktop”, pero solo está disponible para Windows, Mac y ciertos sistemas Linux. Se puede descargar gratis desde: https://www.docker.com/get-started/
Si usas Windows
Docker funciona muy bien sobre Linux, por ello, cuando se indique durante la instalación que se elija entre Hyper-V y WSL 2, recomiendo usar WSL 2 (de primeras no necesitarás conocer nada más sobre WSL 2, pero para temas avanzados sí lo necesitarás y será mejor trabajar sobre Linux, esto es WSL 2, puesto que la mayoría de los sistemas Docker empresariales están montados sobre Linux).
WSL 2 NO está habilitado por defecto en Windows. Para habilitar rápidamente WSL 2, buscar en Windows “Activar o desactivar las características de Windows” y en la ventana que se abre habilitar “Subsistema de Windows para Linux”, aceptar y reiniciar el ordenador.
Y en la “Microsoft Store” ya podremos instalar la distribución Linux que queramos. Para empezar, recomiendo “Ubuntu”.
Una vez instalado lo abrimos y seguimos los pasos para terminar de configurarlo, que realmente será añadir un usuario de root y una contraseña (memorízala o anotarla, porque puede que la necesites).
Si ya tenías instalado WSL 2, recomiendo actualizarlo ejecutando en la línea de comandos de Windows el comando:
wsl --update
Nota si tienes problemas con la instalación de WSL 2: tienes información más completa sobre cómo habilitar WSL 2 en: https://learn.microsoft.com/es-es/windows/wsl/install
Cuando descarguemos el instalador, lo ejecutamos y comenzará el proceso de instalación, seguimos los pasos hasta el final.
Cuando termine la instalación, nos pedirá reiniciar el ordenador.
Y cuando reinicie, iniciaremos Docker. Quizás se nos abra la siguiente ventana para terminar de configurar Docker, elegir “Use recommend settings” y terminamos:
Instalar “Docker CE”
Puede que por alguna razón no podamos instalar “Docker Desktop” y necesitemos instalar “Docker CE”, por lo que te lo explico en el siguiente artículo. Luego puedes volver a éste para leer la teoría básica, pero no podrás usar la interfaz gráfica, puesto que no tiene, aunque en el siguiente artículo aprenderás lo mismo, pero desde comandos.
Iniciar “Docker Desktop”
Ejecutamos “Docker Desktop” (En Windows doble clic al acceso directo) y se nos abrirá una ventana con el programa. Lo primero que veremos es que si queremos registrarnos (“Sign up”), podemos hacerlo o no (“continue without signing in”), como veamos; aunque recomiendo registrarse para poder acceder a la “Docker Hub” desde esta aplicación.
Luego es posible que nos pida que a qué nos dedicamos.
Tras lo anterior, ya estaríamos dentro. Donde si todo ha ido bien lo primero que nos dice es que el motor de Docker está en ejecución (“Engine running”), además, podremos ver el estado de Docker junto al reloj de Windows (nos pondrá “Docker Dektop is running”).
Esta interfaz nos permitirá gestionar los contenedores de Docker, como veremos más adelante.
Siempre que queramos trabajar con Docker, lo tenemos que hacer sobre un Docker en estado iniciado (“started”).
Nota si nos dice “Docker Engine stopped”: podemos probar a reiniciar, si sigue dando problemas, es que algo nos falta y no está iniciándose correctamente, en Windows puede que WSL 2 no está bien instalado.
Nota para cuando terminemos de usar Docker: no es suficiente con salir de “Docker Desktop”, sino que es necesario detener el “Docker Engine” (que es lo que más recursos consume). Con “Docker Desktop”, cuando pulsemos en “Quit Docker Desktop” ya se encarga de detener el “Docker Engine” y terminará cerrando la aplicación “Docker Desktop”.
Docker Hub
“Docker Hub” es el repositorio de imágenes (como la “tienda de aplicaciones” de Docker) y se pueden ver las imágenes que existen de tres maneras:
- Desde la web: https://hub.docker.com/search (Donde veremos nada más entrar imágenes de tecnologías muy conocidas y que nos llamarán la atención, como la imagen de Python, Ubuntu, Redis, Nginx, etc.)
Nota importante sobre este repositorio “Docker Hub”: hay de todo, desde imágenes oficiales (“Docker Official Image”), las verificadas por el publicador (“Verified Publisher”), las patrocinadas (“Sponsored OSS”) y las que no te aseguran fiabilidad alguna (ten en cuenta que todo el mundo puede subir imágenes a “Docker Hub”, por lo que habrá imágenes que contengan virus o que directamente ni funcionen). Para obtener imágenes fiables, a la izquierda de la web se puede filtrar y recomiendo principalmente las imágenes oficiales (“Docker Official Image”), las verificadas por el publicador (“Verified Publisher”); si pulsas en el siguiente link ya te las dejo marcadas: https://hub.docker.com/search?q=&image_filter=official%2Cstore
- Desde “Docker Desktop”: el buscador está en la parte de arriba de la aplicación y se conecta a la misma web que te indiqué antes, por lo que encontrarás lo mismo (el icono de sello verde junto al título de la imagen, indica que es una “imagen Docker” oficial):
Objetos Docker: Imágenes y Contenedores
Es importante conocer los objetos Docker (En “Docker Desktop” podremos ver muchos de ellos clasificados en el menú vertical de la izquierda; así también nos sirve esta parte de tutorial rápido de “Docker Desktop”):
Imagen Docker: es una plantilla Software de solo lectura con “instrucciones” (“capas” en Docker) para crear un contenedor Docker. A “plantilla Software” me refiero a un paquete ya “construido” (“build”) desde una plantilla de verdad (el Dockerfile, que te interesará si eres desarrollador y lo veremos en profundidad en el siguiente artículo). Las imágenes se pueden subir a repositorios para compartirlas (semejante a “git”, como puede ser al repositorio público de “Docker Hub” o a un repositorio privado como “Harbor”).
Por ejemplo, en el siguiente dibujo te muestro una representación de una “imagen Docker” de “MySQL” que utilizaremos más adelante (el dibujo con esta representación es mía para que entiendas en profundidad como están montadas). En esta “imagen Docker” hay ya preparadas una serie de instrucciones de ejemplo (por alguien del mundo, tú no tienes que hacer esto en este artículo, por cierto, me he basado en la documentación real):
- Una primera instrucción sería tener un sistema operativo “Linux Oracle” (podría estar sore cualquier sistema operativo, Ubuntu, Debian, etc. Normalmente uno muy poco pesado).
- Otra instrucción podría ser tener instalado sobre ese sistema operativo un MySQL con su configuración ya preparada (por alguien que no eres tú).
- Y una última instrucción que sería “iniciar el servidor” de la base de datos (para que tú solo tengas que ejecutar el contenido de la Imagen sin tener que hacer nada de lo que te acabe de contar, solo tendrías que disfrutar de la tecnología, en este caso, podrías aprender SQL con una base de datos real y funcional).
Contenedor Docker: es un entorno aislado con todo lo necesario para ejecutarse (Java, Python, bases de datos, código del proyecto que hayas desarrollado, dependencias, scripts, etc.) y no tiene conocimiento del sistema operativo sobre el que se ejecuta Docker (“Docker Desktop”, que incluye “Docker Engine” y éste último incluye “Docker Daemon”; siendo el “Docker Daemon” el servidor que ejecuta las imágenes de Docker y las mantiene como contenedores). Para crear un contenedor se necesita de una imagen Docker y durante la creación hay que definir una serie de parámetros (como los Volúmenes o las Redes, que son otros objetos Docker que veremos más adelante). Por lo que desde una misma imagen podremos tener cuantos contenedores queramos, todos funcionando en el mismo ordenador o distribuidos en varios ordenadores (con pasar la imagen a otro ordenador, haciendo “pull” desde un repositorio o copiándola, es muy sencillo crear un contenedor desde esta).
Es importante tener en cuenta los dos tipos de comportamiento de los contenedores cuando los iniciamos (esto es importante entenderlo, porque si montas un contenedor y ves que se detiene de inmediato, es bastante posible que sea por esto o por un error):
- Contenedores efímeros: son contenedores que se inician y terminan casi de inmediato, tras terminar de ejecutar su hilo principal (la imagen de Python, que te mostré antes, crea este tipo de contenedores, pues interesa que se ejecute nuestro código Python que pongamos dentro y tan pronto termine, pues que se detenga y libere recursos; podríamos tener código Python en bucle infinito, por lo que el Contenedor se mantendrá activo esperando a que termine indefinidamente). Normalmente este tipo de contenedores son tan rápidos que no nos da tiempo a interactuar con ellos.
- Contenedores Daemon (o de larga duración): son contenedores que tienen su hilo principal ocupado eternamente, suelen ser servidores (servidores web, servidores de base de datos, etc.). Podremos interactuar con estos contenedores, ejecutar comandos en una terminal, ver su sistema de ficheros, etc. A continuación, probaremos uno de estos contenedores con un servidor de base de datos “MySQL” (que son los que interesan en este artículo y los que te recomiendo que utilices para aprender, por ejemplo, a escribir consultas SQL en la base de datos que quieras ¡Tienes todas a tu disposición de manera muy parecida!).
De seguido te muestro un dibujo de lo que haremos a continuación de verdad y para que veas la diferencia entre “imagen Docker” y “contenedor Docker”. Desde una “Imagen Docker” la ejecutamos (“run”) y nos creará un “contenedor Docker” funcionando con todo (un “Linux Oracle” con un MySQL que está iniciado y en ejecución sobre el Hardware de tu ordenador, pero separado de tú sistema operativo, por tanto, listo para ser usado) y con el que podremos trabajar (crear bases de datos y ejecutar consultas SQL). Cabe mencionar, que desde la “imagen Docker” podremos ejecutar tantos “contenedor Docker” como queramos (es decir, podríamos tener mil MySQL funcionando a la vez con tan solo pulsar un botón).
Descargar una imagen desde “Docker hub” con “Docker Desktop”
Para este artículo quiero voy a usar de ejemplo la imagen de “MySQL”. Si no conoces MySQL comentarte rápidamente que es un motor de bases de datos relacionales de los más conocidos y fácil de aprender (más información en https://www.mysql.com/), además, te voy a enseñar no solo a instalarlo, sino que a usarlo.
Para descargar la imagen de MySQL desde “Docker hub” vamos a la interfaz de “Docker Desktop” y arriba en el buscador (donde pone “Search”), escribimos: mysql
Nos aparecerá un listado con bastantes imágenes, pero aquí vamos a elegir la imagen que se llama “mysql” y vamos a elegir la versión llamada “8.3” (fijo esta versión apropósito, para que no tengas problemas en seguir este artículo, ya que otras versiones pueden cambiar).
Tras seleccionar la versión tendremos dos opciones para descargar la imagen:
- Pull: descarga la imagen de “Docker Hub”.
- Run: descarga la imagen de “Docker Hub”, crea un contenedor local y ejecuta la imagen dentro.
Para ir paso a paso seleccionaremos “Pull”:
Una vez que esté descargada, iremos en el menú de la izquierda a “Images”, donde veremos nuestra imagen descargada “mysql” y aquí para iniciar a la imagen iremos a la derecha a pulsar en la flecha de “Run” (este botón, aunque se llama también “Run” no descarga la imagen, solo crea el contenedor donde se ejecuta la imagen, puesto que ya está descargada):
Se nos abrirá una ventana que nos pide varios parámetros, aunque son todos opcionales para ejecutar a la imagen, algunas son obligatorias para que lo que está dentro de la imagen funcione (en este caso, la instalación de MySQL que está dentro de la imagen funcione bien).
- Container name: podremos poner un nombre al contendor si queremos (si no, se pone uno aleatorio), yo en el ejemplo pondré “miMySQL-container” para poder distinguir entre otros contenedores que podamos tener en el futuro. Por cierto, recomiendo poner el nombre que quieras (normalmente el mismo de la imagen), pero que incluya la palabra “contenedor” (o “container” en inglés), como puede ser “miContenedorMysql” o directamente “mysql-container”, pues así es más fácil de distinguir los contenedores de las imágenes y cuando llevas programando horas ayuda a distinguir rápidamente entre imágenes y contenedores (esto es una sugerencia mía, no es un estándar ni nada parecido).
- Ports: podremos mapear los puertos que queramos de nuestro ordenador (local) con los del contenedor (con los de su interior, que son los puertos que salen en gris a la derecha “3306” y “33060”). Esto será útil si trabajas con redes de contenedores y quieres conectarte a tu contendor, pero para ahora mismo no son necesarios, por lo que en este ejemplo no pondré nada. Si no ponemos nada, por defecto es como poner lo mismo que está en gris (en el ejemplo será “3306:3306” y “33060:33060”, es decir, que por ejemplo podremos conectarnos desde nuestro ordenador a “localhost:3306”).
- Volumes: Si queremos podremos definir o un “Bind mount” (que podríamos traducir algo así como “montaje vinculado”) o un “Docker Volume” (“Volumen Docker”). Lo veremos más adelante, así que de momento lo dejaremos vacío
- Environment variable: Aquí definiremos las variables entorno que necesitemos. Si has trabajado con bases de datos, quizás te preguntes que ¿Cuál es la contraseña de root de MySQL? Pues aquí le diremos que NO nos pida contraseña de root (esto es muy inseguro, por lo que para entornos de Producción no es recomendable, pero para jugar con la base de datos es lo más sencillo) y pondremos exactamente en el campo “variable” el texto exacto “MYSQL_ALLOW_EMPTY_PASSWORD” (cópialo sin comillas) y en “value” la afirmación en inglés “yes” (sin comillas). Por cierto, esto no me lo he inventado, está en la documentación de la imagen de MySQL: https://hub.docker.com/_/mysql
Nota por si quieres poner contraseña de root: En vez de la anterior variable de entorno, en el campo “variable” pon “MYSQL_ROOT_PASSWORD” (sin comillas) y en “value” la contraseña que queramos, por ejemplo, “contraseniaroot”, pero acuérdate de ella porque te la pedirá más adelante.
Pulsamos “Run” para que se nos cree nuestro contenedor Docker con la imagen MySQL y los parámetros de configuración que acabamos de poner.
Se nos abrirá el contenedor directamente (fíjate que automáticamente en el menú de la izquierda nos ha cambiado a “Containers”) que acabamos de crear, arriba verás el nombre que le pusimos a nuestro contenedor (en mi ejemplo “miMySQL-container”) y en la primera pestaña llamada “Logs” veremos las “trazas” (también llamados “registros” o “logs”) de nuestro contenedor, esperaremos unos segundos hasta que aparezca el log que diga “MySQL init process done. Ready for start up.” (Lo que nos indicará que nuestro contenedor con MySQL instalado ya estará listo para ser utilizado). Estos logs son importantes, puesto que aquí nos informará tanto se ha ido bien como si algo ha ido mal (veremos errores).
Aquí te animo a navegar en el menú lateral izquierdo entre “Containers” e “Images” para que veas las diferencias:
- Images: tenemos la imagen mysql que hemos descargado de “Docker Hub” (la imagen puede ocupar bastante en disco).
- Containers: tenemos nuestro contenedor “myMySQL-container” en ejecución que hemos creado desde la anterior imagen (como el contenedor está en ejecución, nuestro ordenador va a estar trabajando bastante).
Para continuar, vete a “Containers” y pulsa sobre el nombre de tu contenedor (en mi ejemplo “myMySQL-container”).
Iremos a la pestaña “Exec” de nuestro contenedor, ésta es la interfaz de nuestro contenedor, donde estará el sistema de archivos del sistema operativo de nuestro contenedor (como es un sistema operativo Linux, podremos escribir sus comandos para ver los directorios como: ls ) ¿Pero no dijimos que no íbamos a programar nada? Escribir un comando y consultas SQL no es programar 😉 Para iniciar la terminal de MySQL, nos bastará con escribir el comando: mysql
Nota si has puesto contraseña root: necesitas ejecutar: mysql -u root -p
Tras iniciar la terminal de MySQL podremos escribir consultas SQL que queramos, para este ejemplo he escrito las siguientes (te resumo rápido las sentencias SQL que he usado en el ejemplo, puesto que hay otros artículos de SQL y por si quieres aprovechar a aprender SQL con esto ya puedes practicar en un entorno real todo lo que quieras):
- CREATE DATABASE: crea una base de datos dentro del motor de MySQL.
- USE: para usar una de la base de datos que tengas creada.
- CREATE TABLE: dentro de la base de datos en uso, creará la tabla.
- INSERT INTO: insertar un registro con valores en una tabla creada.
- SELECT: Consultar los datos de una tabla.
- DROP TABLE: elimina una tabla existente.
CREATE DATABASE mi_bd;
USE mi_bd;
CREATE TABLE mi_tabla ( id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(50), email VARCHAR(50) );
INSERT INTO mi_tabla (nombre, email) VALUES ('Ramon', 'ramon@jarroba.com');
SELECT * FROM mi_tabla;
DROP TABLE mi_tabla;
Otra cosa importante es ¿Y dónde se guardan los datos de las tablas que cree en mi base de datos? Pues si te vas a la pestaña “Files” y navegas al directorio “/var/lib/mysql” (este directorio lo conozco por la documentación de MySQL), ahí estarán los ficheros con toda nuestra información que guardemos en la base de datos (es donde MySQL guarda todo) ¿Para qué te cuento esto? Porque si te fijas a la izquierda del directorio “mysql” aparece una nota “VOLUME”, como no hemos hecho nada con los volúmenes, entonces, se nos ha montado un volumen automático y todo volumen automático es temporal, es decir, que si detienes este contenedor vas a perder todas las bases de datos, tablas y toda la información que has introducido en MySQL (digamos que está en la volátil memoria RAM, no en disco duro).
¿Cómo hacemos para que los datos perduren cuando detengamos el contenedor? Lo veremos enseguida, pero para ello tenemos que volver a crear el contenedor.
Para continuar, y cuando hayas terminado de trabajar con nuestro contendor, arriba a la derecha hay varios controles (como el cuadrado de detener el contenedor, la flecha de iniciar el contenedor o el de reiniciarlo), pulsaremos en la papelera para detener el contenedor y destruirlo (esto solo elimina el contenedor, no la imagen descargada).
Objetos Docker: Volumes
Para persistir datos en disco, para cuando en el futuro volvamos a iniciar un contenedor que hayamos detenido en el pasado (es decir, reiniciamos un contenedor), y queremos que se mantengan los datos (persistencia), necesitamos volúmenes. En Docker hay dos tipos de volúmenes:
Docker Volume (Volumen Docker): los creamos nosotros con el nombre que queramos y los administra Docker (en “Docker Desktop” los veremos en el menú lateral izquierdo en “volumes”). Un volumen es independiente de los contenedores (por lo que podrías utilizar el mismo volumen para varios contenedores) y se pueden preservar en donde quieras (por ejemplo, te los puedes llevar en un pendrive). Los volúmenes hay que eliminarlos a mano, sino existe para siempre. Un volumen se añade al crear el contenedor desde la imagen y basta con indicar su nombre.
Bind mount (Montaje Vinculado): creamos una carpeta normal en el sistema operativo de nuestro ordenador (host) y esta carpeta la vincularemos con un directorio de dentro del contenedor. Cuando se detiene el contenedor, podremos seguir trabajando con los ficheros en nuestro ordenador Host, además de quedar persistidos en dicha carpeta. Es cómodo para desarrollo y para pasar ficheros rápidamente, pues lo que editemos en esta carpeta desde el host se verá reflejado de inmediato dentro del contenedor y viceversa. Pero es peligroso, pues estamos dejando al contenedor crear ficheros en nuestro sistema de ficheros del ordenador host (lo que podría corromper y dañar a nuestro sistema operativo si no se usa correctamente, como puede ser la generación de archivos hasta llenar el disco o traspasar virus desde el contenedor, si la imagen no es fiable). Bind mount no es gestionado por Docker, sino por nosotros, si queremos más seguridad, entonces mejor utilizar Volume.
Te dejo un dibujo con lo que montaremos a continuación, que será una “imagen Docker” con MySQL asignada a un “volumen Docker” para persistir sus datos y que tiene mapeado el puerto 3306 del contenedor al 3306 de tu ordenador (que es lo mismo que dejarlo en blanco en el “host port”, como hicimos previamente). Además, crearemos otra imagen más con “Apache HTTP Server” (más conocido como “Httpd”), con la carpeta “www” como un “Bind mount de Docker” para poder crear una página web en tiempo real mientras se sirve en el servidor “Httpd”, además, mapearemos el puerto 80 del contenedor (que es al que escucha “Httpd”) al puerto 8000 de nuestro ordenador (con lo que podremos ver nuestra página web desde nuestro navegador favorito en la dirección http://localhost:8000/ ).
Crear un volumen
Para crear un Volumen gestionado por Docker, vamos al menú de la izquierda del “Docker Desktop” y elegimos donde pone “Volumes”. Entonces, creamos un nuevo volumen pulsando en “Create a volume”.
Se nos abrirá una ventana que nos pedirá el nombre del volumen, que yo llamaré “MiVolumenDocker” (copia este nombre, ya que lo utilizaremos más adelante).
Al pulsar “Create”, inmediatamente veremos nuestro volumen creado en un listado (pues podremos tener cuántos volúmenes queramos).
Regresamos a “Images” y, como vimos en pasos previos, creamos un nuevo contenedor con la siguiente configuración (que es muy parecida a la de “Bind mount”, pero más fácil):
- Container name: ejemplo “miMySQL-container”.
- Volumes: en el campo “Host path” pondremos en nombre que le pusimos antes al volumen que creamos, que en mi ejemplo fue “MiVolumenDocker” y en el campo “Container path” apuntamos a lo que queramos persistirque en mi caso es “/var/lib/mysql” (Docker diferencia dependiendo de lo que pongas en “Host path”, si es una ruta a un directorio, entonces Docker crea un “Bind mount”, como después veremos; pero si lo que pones es una palabra, entonces para Docker es un “Volume”).
- Environment variable: en el campo “variable” y “value” pondremos sin comillas respectivamente “MYSQL_ALLOW_EMPTY_PASSWORD” y “yes”.
Pulsamos “Run” y se iniciará nuestro contenedor.
Dentro del contenedor, en la pestaña “Files” si vamos a la ruta “/var/lib/mysql” veremos que lo reconoce como “VOLUME” (si recuerdas, también aparecía “VOLUME” si no se definía ningún volumen, porque Docker creaba uno temporal que al eliminar el contenedor se borraba; ahora, la diferencia con el anterior es que este “VOLUME” es persistente, por tanto, si detenemos el contenedor y lo reiniciamos seguiremos manteniendo los datos).
Con esto, aunque detengamos el contenedor y lo reiniciemos, nuestros datos estarán persistidos en disco; cuando volvamos a iniciar el contenedor, los datos, por ejemplo las tablas e inserciones (“INSERT”) que hayamos hecho en la base de datos, seguirán ahí y no los habremos perdido.
Crear un Bind mount
Para montar una “bind mount”, simplemente pensamos en una carpeta de nuestro ordenador que queramos vincular (y todo lo que pongamos en ella se verá desde dentro del contenedor) y creamos un nuevo contenedor desde nuestra imagen.
Nota sobre la inseguridad de los “bind mount”: es importante que entiendas los problemas de seguridad que indiqué antes, esta imagen de “MySQL” es oficial, por lo que deberíamos de poder confiar en ella, pero siempre bajo nuestra responsabilidad.
Para este ejemplo vamos a ver la utilidad del “Bind mount”, por lo que utilizaremos la imagen de Apache HTTP Server (también llamado “httpd”; más información en https://httpd.apache.org/) que es muy utilizada para crear páginas webs, para ello descaraguermos la imagen como antes, pondremos en ejecución el contenedor que nos dejará dentro en ejecución servidor “httpd” y podremos trabajar en directo con ficheros HTTP, CSS y javascript, pudiendo ver los resultados en nuestro navegador tal y como si estuvieran subidos a un servidor empresarial de verdad.
Para ello, como vimos antes descargaremos la imagen “httpd” con la versión 2.4 (https://hub.docker.com/_/httpd), aquí directamente crearemos el contenedor con “Run” para ahorrarnos pasos.
Se nos abrirá la ventana de Run que nos pedirá los parámetros que yo definiré:
- Container name: ejemplo “MiServidorApache-container”.
- Ports: fíjate que el puerto del interior del contenedor es el “80”, este puerto es tan utilizado que lo más seguro es que tengamos problemas para utilizarlo en nuestro ordenador; por lo que aquí, voy a mapearlo con un puerto que yo quiera que no se esté utilizando en nuestro ordenador, por ejemplo, el 8000 (es decir, que el puerto 80 de dentro del contenedor quedará expuesto a mi ordenador como 8000).
- Volumes: en el campo “Host path” (ruta de nuestro ordenador que es el host) clicaremos en los tres puntos y elegiremos una carpeta de nuestro ordenador (yo he decido crearme una carpeta en el escritorio de Windows (escoge un sitio adecuado) llamada “www” (este nombre es una convención para poner los recursos web, también se suele llamar “htdocs” o “public_html”, pero puedes llamarla como quieras); luego, en “Container path” pondremos la ruta de dentro del contenedor que necesitemos ¿Y cuál necesitamos? Pues mirando la documentación oficial https://httpd.apache.org/docs/2.4/sections.html o más fácil en https://hub.docker.com/_/httpd nos indica que el espacio de trabajo es “/usr/local/apache2/htdocs/”, por lo que será esta ruta la que querramos mapear y donde coloquemos los ficheros web (HTTP, CSS, JavaScript).
Cuando pulsemos “Run”, se nos creará el contenedor en ejecución y cuando termine de cargar (es muy rápido, segundos). Docker ya se encarga de exponernos en nuestro local (localhost) y con el mapeo de puerto que antes definimos (el 8000); por lo que, si has seguido este artículo bastará ir a tu navegador web favorito y escribir: http://localhost:8000/
Si te fijas, en la web aparecerá “Index of/”, esto te lo genera el servidor Apache HTTP Server, que es la página por defecto si la carpeta de recursos web está vacía (el directorio “/usr/local/apache2/htdocs/”).
Dicho directorio, si recuerdas lo habíamos vinculado con “Bind mounts”, por lo que en la pestaña “Bind mounts” podremos ver la carpeta de nuestro ordenador en “Source (Host)” y en “Destination (Container)” veremos la ruta a la que apunta dentro del contendor.
En el contenedor, si vamos a la pestaña “Files” y vamos a “/usr/local/apache2/htdocs/”, veremos que aparece la etiqueta “MOUNT” que nos indica que esta carpeta no existe realmente dentro del contenedor, sino que está montada y vinculada (“bind mount”) a una carpeta de nuestro ordenador:
Minimizamos Docker Desktop y vamos a la carpeta que hemos creado y vinculado en nuestro ordenador, que en mi caso está en el escritorio de Windows con el nombre “www”. Ahora, si creamos o modificamos ficheros dentro de esta carpeta, el contenedor de inmediato verá los cambios en tiempo real. Para hacer la prueba crearemos un fichero llamado “index.html” (es importante que la extensión sea “html” y el nombre “index” es para que se tome como página inicial) que editaremos con nuestro editor favorito (Vim, Sublime Text, el bloc de notas de Windows, etc.) y escribiremos código HTML, que para mí ejemplo escribiré (y guardaré los cambios, es importante guardar):
<!DOCTYPE html>
<html>
<head>
<title>Mi Sitio Web</title>
</head>
<body>
<h1>Ejemplo de texto de www.jarroba.com</h1>
</body>
</html>
Y si volvemos al navegador y pulsamos en actualizar (o tecla “F5”), veremos de inmediato como el servidor dentro del contenedor a tomado los cambios de la carpeta y me permite ver la web que he creado:
Por cierto, aunque detengamos el contenedor y lo reiniciemos, nuestros datos estarán persistidos en disco (en mi ejemplo, los de la carpeta “www”) y, encima, los tendremos accesibles desde nuestro ordenador host, aunque el contenedor no esté funcionando.
Contenedores Docker vs Máquinas Virtuales (VM)
La gracia de un contenedor Docker es que se ejecuta directamente en el núcleo (kernel) del sistema operativo del ordenador sobre el que está instalado (host). Por el contrario, una máquina virtual emula Hardware sobre el que se ejecuta.
Ventajas de ejecutar directamente en el núcleo:
- Reduce la complejidad: facilita la programación y aumenta la velocidad de procesado (en comparación a emular Hardware).
- Facilita crear y depurar controladores: si desarrollas un controlador de un dispositivo físico te interesará probarlo directamente sobre el mismo, no sobre uno emulado.
- Sin límites: por defecto puede aprovechar todo el Hardware de la máquina. Por el contrario, una máquina virtual no podrá aprovechar todo el Hardware físico (principalmente porque tiene en ejecución dos sistemas operativos, el host y el virtual, ambos con sus espacios de usuario y de kernel, esto consume bastantes recursos físicos).
Ventajas de emular Hardware:
- Aislamiento: lo que se ejecuta dentro de una máquina virtual no interfiere con lo que se ejecuta en el Hardware del host.
- Flexibilidad: se pueden instalar y ejecutar varias aplicaciones en el mismo sistema operativo virtual (es como tener otro ordenador dentro del ordenador; por ejemplo, de host Windows con su escritorio y emulado un Ubuntu Linux con su escritorio).
- Emulación de Hardware: emular todo, desde la CPU, memoria, tarjeta de red, controladores USB, etc. Por ejemplo, tu ordenador tiene físicamente un disco duro de miles de Teras, pero podrías emular (simular) que tienes un disco duro muy pequeño (por ejemplo, para ver qué pasa si se le acaba la memoria al ordenador); o teniendo un procesador Intel, podrías emular que tienes un procesador AMD.
Un contenedor de Docker tiene el código de la aplicación, su entorno, las bibliotecas, las herramientas del sistema y el tiempo de ejecución. Por el contrario, una máquina virtual es una virtualización de una máquina completa, con sus ventajas: como ejecutar varias aplicaciones, compartir bibliotecas comunes entre diferentes aplicaciones (reduciendo el tamaño en disco), aunque con la desventaja de que pueden existir conflictos entre dependencias y versiones.
Un contenedor Docker NO tiene sistema operativo con interfaz de usuario (con escritorio, iconos, botones, puntero de ratón, etc.), solo se controla mediante comandos (“Docker Desktop”, Rancher https://ranchermanager.docs.rancher.com/ o Portainer https://www.portainer.io/ , no cuentan como interfaces de usuario, pues solo son para administrar contendores, es decir, iniciarlos y pararlos, pero no tienes control dentro del contenedor con una interfaz). Por su parte, una máquina virtual puede tener un sistema operativo con interfaz de usuario completa y sus aplicaciones con interfaz (todo un Windows o un Ubuntu instalado, con su escritorio con iconos donde podemos usar con el ratón con aplicaciones como el reproductor de música, por ejemplo). Tener interfaz de usuario facilita muchas tareas y proporciona más información de un solo vistazo, pero tiene el inconveniente de ser muy pesado en disco y de consumir mucho tiempo de procesador; no tener interfaz de usuario agiliza muchísimo y por eso los contenedores Docker se levantan tan rápido. Cabe indicar que existen “trucos” muy usados para tener interfaz de usuario en Docker, como levantar un servidor que proporcione una interfaz web (que podemos ver lo que está ocurriendo en una interfaz usable en el navegador Chrome o Edge, por ejemplo).
Docker es una plataforma de código abierto. Pero la tecnología de virtualización no tiene por qué serlo (por ejemplo, VirtualBox https://www.virtualbox.org/ es de código libre vs VMware https://www.vmware.com/ que no lo es).
Continúa el curso de Docker
Puedes continuar con la siguiente parte de este curso en: