Guía para Desarrolladores Principiantes en Docker
Índice de contenido
- Conceptos Claves
- Similitudes con Python, los ambientes virtuales, Node y PHP
- ¿Dónde se guardan las dependencias?
- Docker
- Imagen (Image)
- Contenedor (Container)
- Docker Daemon (dockerd)
- Docker Client (docker)
- Instalación
- Qué estamos instalando
- Verificación de la instalación
- Comandos imprescindibles
- Funcionamiento básico
- Ver imágenes
- Ver Contenedores
- Eliminar imágenes
- ¿Qué significa RMI?
- Detener contenedores
- Identificando contenedores
- Deteniendo contenedores
- Eliminar contenedores
- Logs contenedores
- Modo Interactivo bash
- Consideraciones previas
- Diferencia con Docker Run -it
- Para qué sirve sleep 1000
- ¿Qué pasa si no pones sleep?
- Comando docker stats
- Limitando recursos de un contenedor
- Probando el consumo del contenedor
- Construir Imágenes Personalizadas: Dockerfile
- Construyendo Imágenes Personalizadas
- Dockerfile
- 1. Crea el Archivo de Instrucciones
- 2. Define la Imagen Base (FROM)
- 3. Establece el Directorio de Trabajo (WORKDIR)
- 4. Copia tus Archivos Locales (COPY)
- 5. Ejecuta Comandos de Configuración (RUN)
- 6. Especifica el Comando de Inicio (CMD)
- 7. Informa sobre los Puertos (EXPOSE)
- Ejemplo Completo de Dockerfile
- Comando docker build
- App en Flask
- Paso a Paso: Construyendo el Dockerfile
- Construir y Ejecutar la Imagen
- Ejecutar el Contenedor
- Con Gunicorn
- Sustituyendo el servidor de desarrollo por Uvicorn
- App en Django
- ENV PYTHONDONTWRITEBYTECODE=1
- ENV PYTHONUNBUFFERED=1
- Conectando Docker con la Máquina Local: Explicación Práctica: host.docker.internal
- Intentando con host.docker.internal
- Volumenes
- ¿Qué son los volúmenes?
- Donde partimos
- Problemas al trabajar con Docker en desarrollo
- Creación y uso de volúmenes
- Montando el volumen en un contenedor
- Docker Compose: ¿Qué demonios es esto y qué pasó con los volúmenes?
- Recordatorio: los volúmenes
- ¿Qué es Docker Compose?
- ¿Y cómo los comunicamos?
- Resumen de la definición
- Uso básico de Docker Compose
- El proyecto de ejemplo con Flask y Redis
- Dockerfile y consideraciones
- El archivo docker-compose.yml
- Servicios
- Levantando la aplicación
- Problema pendiente: sincronización de cambios
- Consideraciones importantes
- Primeros pasos
- Imágenes
- Volumen
Esta es una formación básica para aprender a usar Docker, por lo tanto, SOLAMENTE tratamos los elementos básicos y necesarios para que puedas empezar ha realizar administrar Docker y hacer el deploy de tus primeros proyectos; en esta página tienes la documentación completa:
https://docs.docker.com/get-started/
Conceptos Claves
Como en todo en la vida, primero debemos tener claros algunos conceptos antes de pasar a la práctica. En los frameworks usualmente hablamos del patrón MVC, MTV, entre otros.
Y aquí ocurre lo mismo: necesitamos entender cómo está formado este programa llamado Docker. ¿Qué demonios es esto? Porque créeme que cuando pasemos a la práctica, todo se entenderá mucho más fácilmente.
Similitudes con Python, los ambientes virtuales, Node y PHP
El uso de contenedores, imágenes y Docker es muy similar a los ambientes virtuales en Python.
- Python usa Pipenv, Conda, o simplemente venv.
- Laravel y Node instalan dependencias dentro del proyecto (vendor/, node_modules/).
Pero Python instala por defecto todo a nivel del sistema operativo, lo cual es un problema.
Ejemplo práctico:
Tienes un proyecto hecho en Django hace 3 años (versión Django 4), y hoy necesitas crear otro proyecto pero con Django 7.
Si instalaras todo directo en el sistema operativo, choque asegurado.
Y no solo pasa con Python:
- No puedes tener 3 PHP diferentes activos en el mismo sistema.
- Tampoco puedes mezclar dependencias de forma desordenada sin aislar cada proyecto.
- Por eso, en Python creamos un ambiente virtual por proyecto, lo cual encapsula y aísla sus dependencias. Y es justo ahí donde aparece el paralelismo con Docker.
¿Dónde se guardan las dependencias?
En Laravel tenemos vendor/, en Node tenemos node_modules/.
En Python, el equivalente es una carpeta llamada usualmente .venv o .pvenv, donde se guardan solo las dependencias de ese proyecto.
Eso no ocurre automáticamente: tú debes instalar y activar el ambiente virtual, igual que con Docker, que también debes instalar y configurar manualmente.
Con esto, puedes entender para que podemos usar Docker, como un ambiente en donde podemos ejecutar de manera aislada nuestros proyectos y las similitudes con imágenes y contenedores, en las cuales, las imágenes son simplemente las dependencias, como ocurre con dependencias como Django o Laravel, que son simplemente archivos estáticos y contenedores, que es cuando ya se estan ejecutando o interpretan las imágenes.
Docker
Docker es una plataforma que permite “empaquetar” aplicaciones con todas sus dependencias (librerías, configuración, etc.) para que puedan ejecutarse de forma consistente en cualquier entorno (tu máquina, servidores, nube).
Puedes ver Docker como una especia de ambiente virtual, como los que tenemos en Python mediante los venv, en el cual, podemos instalar paquetes (imágenes sería el equivalente en Docker) que son las dependencias de nuestro proyecto; la ventaja de esto, es que, se ejecutan de manera aislada del sistema operativo; con esto, podemos tener múltiples dependencias con versiones distintas para proyectos distintos instalados en el mismo sistema operativo pero, virtualizado mediante los contenedores en Docker; por ejemplo, podemos tener múltiples versiones de Python instaladas para distintos proyectos.
Otro ejemplo, es como la carpetas vendor de PHP o de node_modules de Node, en la cual, tenemos las dependencias (imágenes sería el equivalente en Docker) para cada proyecto; no es exactamente esto, pero, con esta idea te será más fácil entender como funciona Docker
Docker no es solo una herramienta de desarrollo y se usa ampliamente en producción, y Railway es un ejemplo muy claro de ello.
Imagen (Image)
Una imagen de Docker es como una “plantilla” inmutable, es decir, de solo lectura que contiene todo lo necesario para ejecutar una aplicación: sistema de archivos, dependencias, código, variables de entorno, etc; con esto, se crean los contenedores en Docker que es el siguiente punto que vamos a tratar.
- Las imágenes están formadas por capas (layers) que representan cambios incrementalmente aplicados unas sobre otras.
- Una vez creada, no se modifica: si quieres cambiar algo, creas una nueva imagen o haces “build” sobre una base existente.
Imagina que una imagen de Docker es como un archivo .exe en tu computadora.
El .exe contiene todo el código y los recursos necesarios para ejecutar un programa (bibliotecas, dependencias, configuraciones...), pero mientras no lo ejecutes, el programa no está corriendo ni ocupa recursos.Del mismo modo, una imagen de Docker es un paquete estático que incluye el sistema base, el entorno, las dependencias y la aplicación lista para funcionar. Pero no hace nada por sí sola hasta que creas un contenedor a partir de ella —que sería el equivalente a ejecutar el .exe.
Otra analogía es con las clases, una clase definida:
class Category(models.Model):
title = models.CharField(max_length=500)
slug = models.SlugField(max_length=500)Es como una imagen, por si, no hacemos nada con ella, pero es cuando la ejecutamos (un contenedor) es decir, creamos una instancia, es que se emplea dicha clase/imagen.
Una imagen es como una plantilla inmutable, de solo lectura.
Es una referencia, un entorno con su sistema base y dependencias incluidas.
Ejemplos reales de imágenes disponibles:
- python
- ubuntu
- nginx
- mysql
- postgres
Contenedor (Container)
Un contenedor es la instancia en ejecución de una imagen. Piensa en la imagen como el plano o molde, y el contenedor como la casa construida a partir de ese plano.
Una vez que lanzas un contenedor, este funciona como un proceso aislado, con su propio sistema de archivos (basado en la imagen), entorno, red, etc.
Los contenedores comparten el kernel del sistema operativo host, lo que los hace más ligeros que máquinas virtuales completas.
Al ser un proceso, puedes ejecutarlo, crearlo, detenerlo, moverlo o eliminar el proceso; para eso, se emplea comandos como docker create container, pull, cet:
$ docker run -i -t ubuntu /bin/bashImagina que un contenedor de Docker es como ejecutar un programa .exe en tu computadora.
Mientras la imagen de Docker es el archivo guardado en tu disco (listo pero inactivo), el contenedor es ese mismo programa ya en ejecución: con su ventana abierta, sus procesos corriendo y su propio entorno funcionando de forma independiente.
Cuando cierras el programa, el proceso termina, pero el .exe sigue allí intacto.
De igual forma, cuando detienes o eliminas un contenedor, la imagen original sigue disponible para crear otro contenedor nuevo en cualquier momento.
Los contenedores en Docker:
- Autocontenidos: cada contenedor incluye todo lo que necesita para funcionar, sin depender de programas o librerías instaladas en la máquina donde se ejecuta.
- Aislados: los contenedores se ejecutan de forma independiente del sistema y de otros contenedores, lo que mejora la seguridad y evita conflictos.
- Independientes: puedes crear, detener o eliminar un contenedor sin afectar a los demás. Cada uno se gestiona por separado.
- Portátiles: un contenedor puede ejecutarse en cualquier lugar. El mismo que usas en tu computadora funcionará igual en un servidor o en la nube.
Otros conceptos funcionales:
Docker Daemon (dockerd)
El Docker Daemon es el proceso que realmente ejecuta y administra todo en Docker.
Se encarga de:
- Crear y ejecutar contenedores.
- Descargar o construir imágenes.
- Manejar redes, volúmenes y otros recursos de Docker.
- Comunicarse con otros daemons (por ejemplo, en entornos distribuidos o en clústeres).
En resumen:
Es el “motor” de Docker, el que hace el trabajo pesado.
Normalmente corre en segundo plano como un servicio del sistema y es el que recibe los comandos recibidos por el cliente que es el siguiente apartado que vamos a comentar.
Docker Client (docker)
El cliente de Docker es la herramienta con la que tú interactúas — por ejemplo, cuando escribes comandos como:
docker run -d -p 8080:80 nginxEste comando no ejecuta el contenedor directamente.
El cliente simplemente envía una solicitud al daemon (usando la Docker API) diciéndole qué hacer, y el daemon es quien lo ejecuta realmente.
Además, un mismo cliente puede comunicarse con múltiples daemons (por ejemplo, un Docker local y otro remoto en la nube).
| Componente | Qué hace | Ejemplo |
| ---------------------- | -------------------------------------------------------- | --------------------------------------------------------- |
| **Cliente (`docker`)** | Recibe tus comandos. | `docker build`, `docker run`, `docker ps` |
| **Daemon (`dockerd`)** | Ejecuta las órdenes del cliente y gestiona los recursos. | Crea imágenes, inicia contenedores, configura redes, etc. |
En esta imagen, tomada desde la web de Docker, puedes ver claramente la distinción entre el cliente Docker Client (docker) (los comandos) y el demonio de Docker (dockerd) que es el que recibe los comandos y hace los cambios a nivel de nuestras imágenes y contenedores, que SON LA PIEZA FUNDAMENTAL Y BÁSICA EN DOCKER:

Instalación
La instalación de Docker es muy sencilla. Para empezar, busca en Google “Docker Install”. Entre los resultados, selecciona la página oficial de Docker (Docker Start).
Una vez cargada la página, se mostrará la opción de descarga según tu sistema operativo: macOS, Windows, Linux, macOS con Intel, etc. Simplemente descárgalo e instálalo siguiendo los pasos habituales: Next, Next, Next.
Qué estamos instalando
Al instalar Docker, se instalan dos componentes principales:
- Interfaz gráfica: te permite administrar contenedores y configuraciones de manera visual.
- CLI (Command Line Interface): la línea de comandos que te permite ejecutar comandos de Docker desde la terminal. Aunque el nombre suene técnico, es muy sencillo de usar.
Verificación de la instalación
Una vez finalizada la instalación, abre Docker y verás la interfaz gráfica cargando:

Para verificar la instalación de la CLI, abre cualquier terminal y escribe:
dockerSi todo está correcto, se mostrará la lista de comandos disponibles, confirmando que ambos componentes están instalados y listos para usar:
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Common Commands:
run Create and run a new container from an image
exec Execute a command in a running container
ps List containers
build Build an image from a Dockerfile
bake Build from a file
pull Download an image from a registry
push Upload an image to a registry
images List images
login Authenticate to a registry
logout Log out from a registry
search Search Docker Hub for images
version Show the Docker version information
info Display system-wide informationComandos imprescindibles
En este listado, puedes ver algunas acciones que podemos realizar el Docker, como realizarlo mediante la CLI y su equivalente en la UI:
- docker images: Ver imágenes: docker images (Pestaña Images)
- docker run <ID / nombre>: Crear contenedor: docker run (Botón “Run” sobre una imagen)
- docker ps -a: Ver contenedores: docker ps -a (Pestaña Containers)
- docker logs <Container ID>: Ver logs: docker logs <id> (Sección “Logs”)
- docker stop <ID / nombre> / docker rm <ID / nombre>: Detener/eliminar: docker stop/docker rm (Botones Stop / Delete)
- docker rmi <ID / nombre> elimina una imagen
- docker exec -it bash Entrar dentro de un contenedor ACTIVO en modo interactivo (habilita el bash para lanzar comandos)
- docker run -it <Container ID>(Ej ubuntu) Crea el contenedor y lo deja en modo interactivo (habilita el bash para lanzar comandos)
Un comando imprescindible es el siguiente:
docker run -d -p 8080:80 nginx- docker run → Crea y arranca un nuevo contenedor.
- -d → Lo ejecuta en modo “detached” (en segundo plano, no se queda "pegado" en la terminal).
- -p 8080:80 → Expone el puerto 80 del contenedor en el puerto 8080 de tu PC.
- nginx → Usa la imagen oficial de Nginx desde Docker Hub.
Funcionamiento básico
Del comando anterior, quitando los aspectos técnicos como el detached, o la configuración de los puertos, tenemos dos aspectos fundamentales en Docker que es la imagen y el contenedor:
- Las imágenes descargadas (como nginx)
- Los contenedores que crea a partir de esas imágenes
Ver imágenes
En términos funcionales pasa lo siguiente:
- Descarga la imagen nginx desde Docker Hub (si no la tienes ya, si quieres ver las imágenes, recuerda docker images).
- Crea un contenedor en su propio entorno interno y NO en una carpeta en particular.
- Expone el puerto 80 del contenedor en el puerto 8080 de tu host (tu Mac), gracias a la red virtual que Docker configura.
$ docker images
>> REPOSITORY TAG IMAGE ID CREATED SIZE
>> nginx latest 3b7732505933 12 days ago 255MB
$ docker run 3b7732505933
O
$ docker run nginx
No le estás diciendo ni que se quede activo, ni qué puertos exponer, así que parece “que no pasó nada”. En realidad sí se ejecutó, pero se cerró inmediatamente o quedó corriendo sin exponer nada.En el caso anterior, NO tiene sentido ejecutar la imagen de nginex ya que, la misma para poder levantar el proceso satifactoriamente, se debe de especificar las opciones del puerto, como hicimos antes:
$ docker run -d -p 8080:80 nginxO mediante redis:
$ docker run -d redisRedis si podría trabajar sin exponerle el puerto ya que, por defecto el queda escuchando en el puerto 6379 y por lo tanto, para la implementación anterior, solo sería accesible desde otros contenedores Docker, es decir, de manera interna y no desde el PC perse (fuera de Docker).
Ver Contenedores
Si quisiéramos ver los contenedores de Docker (desde la UI lógicamente la pestaña de Contenedores):
Inicialmente, vamos a ejecutarlo sin el parámetro -a. Para este ejemplo, seguramente en tus pruebas anteriores también tendrás algo. Yo tengo un par de contenedores de las pruebas que hicimos con docker run, ya que, recordemos, cuando ejecutamos docker run con parámetros o sin parámetros, siempre se crea algún contenedor. Entonces, yo tengo al menos dos con los cuales trabajar
Muestra SOLO los contenedores que están corriendo/ejecutandose:
$ docker ps
>> CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
>> e678f12698bf nginx "/docker-entrypoint.…" 3 days ago Exited (0) 5 minutes ago peaceful_mclaren
>> c880881a55f8 3b7732505933 "/docker-entrypoint.…" 3 days ago Exited (0) 3 days ago modest_northcuttFíjate que nos devuelve información sobre el contenedor o los contenedores. Aquí aparece algo interesante, que se apoya en lo comentado antes: los contenedores son la pieza de ejecución de las imágenes.
Si no tienes nada iniciado, no verás absolutamente nada. Pero, ¿qué pasa si agregamos el parámetro -a?
Muestra TODOS los contenedores:
$ docker ps -aEn ambos casos:
>> CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESAhora aparecen los contenedores que tenemos. La opción -a devuelve todos los contenedores, sin importar si están iniciados o no. Por otro lado, docker ps sin parámetros muestra únicamente los contenedores que se están ejecutando.
Ver las imágenes:
$ docker images
>>> REPOSITORY TAG IMAGE ID CREATED SIZE
>>> nginx latest 3b7732505933 12 days ago 255MBEn resumen:
- docker ps -a → todos los contenedores (activos o inactivos).
- docker ps → solo los contenedores activos.
¿Por qué se llama ps y no containers?
Seguramente te preguntas: “Si para las imágenes usamos docker image, ¿por qué aquí no usamos docker containers?”
Esto es una tradición de Linux: ps significa process status, es decir, el estado del proceso. Un contenedor es, esencialmente, un proceso iniciado.
El término containers es más moderno y se incorporó alrededor de 2017, pero el comando ps se mantiene como legacy, una convención histórica de Docker.
Con estos conceptos, podemos entender mejor los fundamentos de Docker: las imágenes como base y los contenedores como piezas clave para ejecutar esos procesos.
Eliminar imágenes
Al igual que siempre, podemos pasarle el ID o el nombre de la imagen que queremos eliminar.
Por ejemplo, si tenemos una imagen llamada nginx, podemos escribir:
$ docker rmi nginx - rmi significa remove image
¿Qué significa RMI?
RMI significa Remove Image, tal como antes teníamos con Docker RM, pero esta vez la I indica que se trata de una imagen. Con esto, ya queda bastante claro su propósito.
Detener contenedores
Docker Stop, como pueden suponer, lo que hace es detener un contenedor. A mí me gustaría que se llamara docker container stop, que sería un poco más claro, pero bueno, así es como está implementado. En la siguiente clase veremos el comando equivalente para eliminar un contenedor.
Para detener un contenedor, simplemente debemos pasarle una de dos cosas:
- El identificador del contenedor (ID).
- El nombre del contenedor.
Fíjate que los parámetros, como el nombre, se pueden personalizar, pero eso lo veremos más adelante.
Identificando contenedores
Recordemos que anteriormente usamos docker ps, que nos devuelve información sobre los contenedores en ejecución. Allí podemos ver tanto el ID como el nombre del contenedor, lo que nos permite copiarlos y pegarlos fácilmente para usar con docker stop.
Deteniendo contenedores
Para detener un contenedor, este debe estar iniciado.
Usando el nombre:
$ docker stop nombre_del_contenedor
Resultado: se detuvo correctamente.
Usando el ID:
$ docker stop ID_del_contenedor
Eliminar contenedores
Para eliminar un contenedor es similar al de detener y el contenedor debe estar detenido, ejecutamos:
Usando el nombre:
$ docker rm nombre_del_contenedorO usando el ID:
$ docker rm ID_del_contenedorLogs contenedores
Permite ver los logs de un contenedor:
$ docker logs -f --tail 20 -t contenedor- --tail = cuántas líneas quieres ver
- --tail 20 últimas 20 líneas
- -t = (timestamp) agrega la hora a cada línea
- -f = (follow) queda "escuchando", y te muestra todo lo nuevo que vaya saliendo en vivo, sin cerrar (el contenedor debe de estar ejecutándose)
Modo Interactivo bash
El siguiente comando que quiero comentar es Docker Exec, que nos permite ejecutar comandos dentro de un contenedor.
Consideraciones previas
Es importante entender que el contenedor debe estar habilitado y en ejecución. Dependiendo de la imagen, ejecutar comandos puede ser extremadamente útil:
- Si tenemos una imagen como Ubuntu, podemos interactuar directamente con el sistema operativo.
- Si es un Apache o Nginx, probablemente no sea posible ejecutar comandos de manera interactiva.
- A menos que quieras modificar archivos: docker exec -it <apache-container> tail -f /var/log/apache2/error.log
- En el caso de bases de datos, podemos ejecutar comandos SQL directamente.
En resumen, todo depende del propósito de la imagen.
El modo interactivo es simplemente habilitar una terminal en la cual ejecutar comandos; para ello, se emplean los siguiente modos:
- -i (interactive) Deja escribir comandos en la terminal
- -t (tty (terminal)) Te da una terminal “real”
Ejemplos:
$ docker run -it ubuntu
$ docker exec -it a1b2c3d4e5 bash # a1b2c3d4e5 EJ de ID de un contenedor ejecutandoseDependiendo de la imagen, puede que si tenga sentido ejecutar comandos; por ejemplo, un shell interactivo de Ubuntu:
$ docker run -it ubuntuUn poco más elaborado:
$ docker run -d --name mi-ubuntu ubuntu sleep 1000- -d → lo ejecuta en segundo plano
- --name mi-ubuntu → le da un nombre para no usar el ID
- ubuntu → la imagen base
Entrar al contenedor con bash:
$ docker exec -it a1b2c3d4e5 bash
$ docker exec -it mi-ubuntu bashAhora estás dentro del contenedor.
Puedes ejecutar comandos como en cualquier Linux:
$ ls
$ pwd
$ apt updateDiferencia con Docker Run -it
- Docker Run -it: inicia un contenedor y automáticamente abre una terminal interactiva.
- Docker Exec -it: ingresa en un contenedor que ya está activo, permitiéndonos ejecutar comandos.
Para qué sirve sleep 1000
Cuando haces:
docker run -d --name mi-ubuntu ubuntu sleep 1000sleep 1000 es el comando que corre dentro del contenedor.
Mantiene el contenedor activo por 1000 segundos (unos 16 minutos).
Como usamos -d (detached / en segundo plano), el contenedor necesita un proceso que siga corriendo, si no, Docker lo detendrá inmediatamente.
¿Qué pasa si no pones sleep?
docker run -d --name mi-ubuntu ubuntuUbuntu no tiene un proceso por defecto que se quede corriendo.
Entonces el contenedor arranca y se detiene al instante, porque no hay nada que mantener activo.
Si luego haces docker ps, no lo verás en la lista de contenedores activos, solo en docker ps -a como Exited.
✅ Por eso usamos sleep para mantenerlo vivo y poder entrar con docker exec -it <id> bash.
Comando docker stats
Vamos a conocer el comando docker stats, que sirve para ver estadísticas de uso de recursos en los contenedores (de ahí su nombre).
$ docker statsPor ahora no tengo contenedores en ejecución, así que, si ejecuto el comando al inicio, no mostrará absolutamente nada.
Para tener algo que analizar, ejecutemos una imagen, por ejemplo, la de Nginx.
El comando sería algo así:
$ docker run -d --name my-nginx -p 8080:80 nginxPor aquí puedes ver que se muestra:
- La memoria total disponible en el equipo (en este caso, unos 7.5 GB).
- El consumo del contenedor Nginx.
- El uso de CPU asignado al contenedor.
Limitando recursos de un contenedor
Muchas veces queremos limitar la cantidad de recursos que asignamos a un contenedor.
Recordemos que el contenedor representa la parte de ejecución de una aplicación, por lo que es buena práctica establecer límites.
Por ejemplo, podemos usar las opciones --memory y --cpus al crear el contenedor:
$ docker run -d --name my-nginx --memory="50m" --cpus="0.5" nginxSi ejecutamos nuevamente docker stats, veremos que el límite ya no es de 7 GB, sino de 50 MB.
Probando el consumo del contenedor
Por último, voy a ejecutar un comando que no tiene que ver directamente con Docker, pero que nos servirá para generar carga y ver el consumo.
$ for i in {1..1000}; do curl -s http://localhost:8080 > /dev/null; doneConstruir Imágenes Personalizadas: Dockerfile
Recordemos que una imagen como un paquete único que contiene todo lo necesario para ejecutar un proceso Y PODEMOS CREAR LOS PROPIOS, en nuestro caso, serían nuestros proyecto en PHP, Node Python, etc; las imágenes personalizadas por nosotros contendrá un entorno Node/Python/PHP, el código de la misma. Para crear nuestras propias imágenes, debemos de crear un archivo especial en nuestro proyecto llamado Dockerfile.
Básicamente, estas son las piezas fundamentales sobre las cuales podemos crear nuestros contenedores para ejecutar aplicaciones. Por ahora, todo puede parecer un poco estático: instalamos imágenes de sistemas operativos o servidores, pero… ¿cómo interactuamos con ellas?
Construyendo Imágenes Personalizadas
Para crear nuestras propias imágenes usamos los famosos archivos llamados Dockerfile. Con estos archivos podemos definir cómo se construye nuestra imagen.
Recuerda: una imagen puede ser cualquier cosa: un sistema operativo, un lenguaje de programación, un servidor… o incluso un proyecto propio. En este caso, vamos a crear una imagen de nuestro proyecto en Flash.
Para construir una imagen personalizada:
- Creamos un Dockerfile en la raíz de nuestro proyecto.
- Definimos las reglas necesarias para que la imagen funcione correctamente.
- Indicamos, si es necesario, qué otras imágenes son requeridas para que nuestra imagen tenga sentido. Por ejemplo, nuestro proyecto en Flash necesita la imagen de Python para funcionar.
Dockerfile
Un Dockerfile es simplemente un archivo de texto que contiene todas las instrucciones necesarias para construir una imagen de Docker. la estructura que tendrá, depende del proyecto y lo que quieras hacer, pero, usualmente cuenta con estos pasos fundamentales:
El Dockerfile es la semilla, la pieza fundamental que nos permite crear nuestras propias imágenes. Por eso, encontrarás muchísimas páginas y ejemplos, porque su funcionamiento es sencillo de comprender: basta con partir de un proyecto base, que puede ser prácticamente cualquier cosa.
1. Crea el Archivo de Instrucciones
En la raíz de tu proyecto, crea un archivo llamado exactamente Dockerfile (con la D mayúscula y sin ninguna extensión).
- Este archivo se crea en la raíz del proyecto, sea PHP, Laravel, CodeIgniter, Flash, FastAPI, Django, Node… lo que sea.
- A partir de allí, definimos un conjunto de reglas. La estructura cambia dependiendo del proyecto, pero en la mayoría de los casos sigue un patrón similar.
2. Define la Imagen Base (FROM)
Especifica el punto de partida de tu imagen usando la instrucción FROM. Esto determina el sistema operativo y el entorno inicial. Por ejemplo, para un proyecto Node.js podrías usar:
FROM node:lts-alpine- En nuestro ejemplo, usamos Python para Flash, o Node para proyectos en Node.
- Si tu proyecto necesita, por ejemplo, SQL, también puedes indicar la imagen de MySQL.
3. Establece el Directorio de Trabajo (WORKDIR)
Con la directiva WORKDIR, defines la carpeta dentro del contenedor donde se ejecutarán todos los comandos posteriores y donde se copiarán tus archivos. Por ejemplo:
WORKDIR /appEste es el lugar donde se instalarán las dependencias, se copiará el proyecto, se ejecutarán comandos y se expondrán puertos.
Por convención, se usa /app, pero puedes nombrarlo como quieras.
4. Copia tus Archivos Locales (COPY)
Utiliza la instrucción COPY para transferir los archivos de tu máquina local al interior de la imagen. Para llevar todos los contenidos del directorio actual (el contexto) al directorio de trabajo del contenedor, harías:
COPY . .- Generalmente copiamos todo el contenido de nuestro proyecto al directorio de trabajo.
5. Ejecuta Comandos de Configuración (RUN)
La instrucción RUN ejecuta comandos durante el proceso de construcción de la imagen, ideal para instalar dependencias o configurar el entorno. Por ejemplo, para instalar dependencias de Node.js:
RUN yarn install --production6. Especifica el Comando de Inicio (CMD)
CMD indica cuál es el comando predeterminado que se ejecutará cuando se inicie un contenedor a partir de esta imagen. Para lanzar una aplicación Node.js:
CMD ["node", "src/index.js"]- Para proyectos de servidor, esto suele incluir instalar dependencias y arrancar la aplicación.
- En Python, por ejemplo, python app.py inicia la aplicación.
- En Node, usaríamos npm install y luego npm start.
7. Informa sobre los Puertos (EXPOSE)
Si tu aplicación está configurada para escuchar en un puerto específico (ej. 3000), usa EXPOSE. Esto le notifica a Docker qué puertos estarán abiertos para la comunicación en tiempo de ejecución.
EXPOSE 3000Ejemplo Completo de Dockerfile
Combinando todas estas directivas, un Dockerfile para una aplicación Node.js se vería así:
Dockerfile
# syntax=docker/dockerfile:1
FROM node:lts-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000En resumen, el Dockerfile define cómo se construye tu imagen, desde la base hasta los comandos de ejecución y puertos. Cada proyecto requiere adaptaciones específicas, pero la estructura general sigue los pasos que hemos descrito:
- Imagen base (FROM)
- Directorio de trabajo (WORKDIR)
- Copiar archivos del proyecto (COPY)
- Exponer puertos (EXPOSE)
- Ejecutar comandos (RUN o CMD)
- En la siguiente clase veremos cómo elaborar este Dockerfile paso a paso para nuestro proyecto y cómo construir la imagen lista para ejecutarla en un contenedor.
Comando docker build
El comando docker build construye una imagen de Docker (nuestra imagen personalizado) a partir de las instrucciones contenidas en un Dockerfile y un contexto especificado.
$ docker build -t app-flask-chat-01 .- -t, Se utiliza la bandera -t (tag), la imagen resultante recibe un nombre y una etiqueta
- el punto al final (.) significa copiar TODO el proyecto desde el directorio actual que es el que tiene:
App en Flask
Pensando en la estructura anterior, veamos como podemos crear un Dockerfile, para crear una imagen personalizada de un proyecto en Flask:
https://github.com/libredesarrollo/01-jan-chat
Creamos el Dockerfile:
# Usa una imagen base de Python oficial, por ejemplo la versión 3.12 pero mas pequena que la completa que es simplemente python
FROM python:3.12-slim
# Establece el directorio de trabajo dentro del contenedor, puede ser cualquier otro pero, por convension es app
WORKDIR /app
# Copia el archivo de requisitos e instala las dependencias
# --no-cache-dir desactivar el almacenamiento en caché de los paquetes descargados e instalados.
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copia TODO el contenido del proyecto (incluyendo app.py) al directorio de trabajo
COPY . .
# Expone el puerto en el que corre Flask (por defecto 5050)
# if __name__ == '__main__':
# app.run(debug=True, host="0.0.0.0", port=5050)
EXPOSE 5050
# Comando para correr la aplicación
# Usa `python app.py` si modificaste app.run(host='0.0.0.0')
# o usa un comando más robusto si instalaste Gunicorn:
# CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
CMD ["python", "app.py"]Paso a Paso: Construyendo el Dockerfile
Ahora sí, comenzamos con el Dockerfile.
Recuerda que puedes inspirarte buscando imágenes base en Docker Hub, la biblioteca oficial.
Como nuestro proyecto está en Python, partiremos de una imagen de Python.
1. Seleccionar la imagen base
Usualmente, partimos de otra imagen base. En este caso, elegimos una imagen de Python, pero para que sea más ligera, usaremos la versión Python Slim:
FROM python:3.12-slimEsta versión es más liviana y eficiente, ya que contiene solo lo esencial para ejecutar Python.
2. Definir el directorio de trabajo
Por convención, usamos /app como directorio principal:
WORKDIR /appAhí se copiará todo el proyecto, y también será donde se ejecuten los comandos definidos más adelante.
3. Copiar dependencias e instalarlas
Lo siguiente es copiar el archivo de dependencias y luego instalarlas:
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txtEsto garantiza que el entorno dentro del contenedor tenga todo lo necesario.
El flag --no-cache-dir evita que se guarde caché, manteniendo la imagen más ligera.
4. Copiar el resto del proyecto
Ahora copiamos el resto de los archivos del proyecto:
COPY . .Esto incluye el código, plantillas, módulos, etc.
5. Exponer el puerto y ejecutar el proyecto
Definimos el puerto (en mi caso, 5050) y cómo se ejecutará la aplicación:
EXPOSE 5050
CMD ["python", "app.py"]Construir y Ejecutar la Imagen
Con el Dockerfile listo, el siguiente paso es construir la imagen.
Tenemos la estructura para crear la imagen, falta construir la imagen personalizado de nuestra aplicación, para ello:
$ docker build -t app-flask-chat-01 .- -t, Se utiliza la bandera -t (tag), la imagen resultante recibe un nombre y una etiqueta
- el punto al final (.) significa copiar TODO el proyecto desde el directorio actual que es el que tiene:
__pycache__ chat_routes.py llm_service.py templates
app.py Dockerfile requirements.txt test.py
Este comando crea la imagen, leyendo las instrucciones del Dockerfile.
Puedes verificarla en Docker Desktop o con:
$ docker imagesEjecutar el Contenedor
Ahí verás tu imagen recién generada.
Y para crear el contenedor de nuestra imagen personalizada:
$ docker run -d -p 5050:5050 --name flask-app-contenedor app-flask-chat-01En cualquier comento, puedes ver el log del contenedor:
$ docker logs flask-app-contenedor Ideal por si el proyecto tiene errores, y deberías de ver algo como esto:
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5050
* Running on http://172.17.0.2:5050
Press CTRL+C to quit
* Restarting with stat
* Debugger is active!
* Debugger PIN: 148-371-654Con Gunicorn
Si queremos desplegar nuestra aplicación en producción, esto se convierte en un problema.
El hecho de que Flask indique que es un servidor de desarrollo significa que no está optimizado para entornos productivos, por lo que debemos utilizar un servidor apropiado para este tipo de despliegues.
En el caso de las aplicaciones desarrolladas con Flask, necesitamos emplear un servidor WSGI (Web Server Gateway Interface) orientado a producción.
Y justamente, uno de los más usados para este propósito es Uvicorn.
Sustituyendo el servidor de desarrollo por Uvicorn
Hasta ahora hemos estado utilizando el servidor de desarrollo, pero queremos hacerlo bien y simular un entorno de producción.
Para ello, comenzamos instalando el paquete de Uvicorn en nuestro proyecto Flask.
Agregamos requirements.txt:
$ pip install gunicornY
$ pip freeze > requirements.txtEl Dockerfile:
CMD ["gunicorn", "--workers", "4", "--bind", "0.0.0.0:5050", "app:app"]
gunicorn -b 0.0.0.0:$PORT run:appExplicando los parámetros:
- --workers 4: indica el número de workers (procesos) que manejarán las peticiones de los usuarios.
Puedes ajustar este valor según los recursos del servidor. - --host 0.0.0.0: define la dirección donde se ejecutará la aplicación dentro del contenedor (el equivalente a localhost).
- --port 5050: especifica el puerto del proyecto.
El resto del archivo Dockerfile permanece igual.
Luego reconstruyes la imagen Docker y levantamos el servidor, tal cual hicimos antes:
$ docker build -t gapp-flask-chat-01 .
$ docker run -d -p 5050:5050 --name gflask-app-contenedor gapp-flask-chat-01App en Django
Pensando en la estructura anterior, veamos como podemos crear un Dockerfile, para crear una imagen personalizada de un proyecto en Flask:
https://github.com/libredesarrollo/coruse-book-django-store
Creamos el Dockerfile:
# Imagen base
FROM python:3.12-slim
# Evitar que Python guarde pyc y buffer stdout
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Carpeta de trabajo
WORKDIR /app
# Copiar dependencias primero
COPY requirements.txt .
# Instalar dependencias
RUN pip install --no-cache-dir -r requirements.txt
# Copiar todo el código
COPY . .
# Exponer puerto de Django
EXPOSE 8000
# Comando de inicio (Gunicorn para producción)
CMD ["gunicorn", "app.wsgi:application", "--bind", "0.0.0.0:8000"]En donde app, es el nombre del proyecto en Django, en caso del proyecto anterior quedarías así:
CMD ["gunicorn", "mystore.wsgi:application", "--bind", "0.0.0.0:8000"]Es donde se ubican los archivos de:
mystore/wsgi.py
Y
mystore/asgi.py
De tu proyecto.
Definimos un par de variables de entorno adicionales:
ENV PYTHONDONTWRITEBYTECODE=1
Indica a Python que no genere archivos .pyc (bytecode compilado).
Normalmente, Python crea archivos .pyc junto a tus .py para acelerar futuras ejecuciones.
En Docker eso no tiene sentido, porque cada vez que reconstruyes la imagen se vuelve a generar todo.
ENV PYTHONUNBUFFERED=1
Hace que Python escriba directamente a la salida estándar (stdout), sin guardar en buffer.
Sin esto, los logs pueden “retrasarse” o no verse en tiempo real dentro de docker logs.Con esto, los print() y los logs de Django o Flask aparecen inmediatamente en el terminal o en docker logs -f.
Estas mismas variables de entorno las puedes emplear también en tus otros proyectos en Python, inclusive en el de Flask que vimos anteriormente para optimizar las imágenes.
Finalmente, si quieres emplear el servidor local:
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]Y al igual que antes, generamos las imagen y el contenedor:
$ docker build -t app-django-01 .
$ docker run -d -p 8000:8000 --name django-app-contenedor app-django-01Conectando Docker con la Máquina Local: Explicación Práctica: host.docker.internal
Vamos a conocer un mecanismo que tenemos en Docker que nos permite, en pocas palabras, conectarnos desde un contenedor hacia nuestra máquina local. Es decir, desde un entorno aislado (el contenedor) podemos acceder a servicios que se ejecutan directamente en nuestro host.
El ejercicio es simple, tengo una app en Django con los CORS configurados ejecutándose en mi localhost (nada de Docker) y quiero conectar una app en Flask ejecutándose en un contenedor; para poder conectarse a nuestro host (nuestra PC) desde un contenedor en Mac y Windows tenemos el siguiente DNS:
Intentando con host.docker.internal
Existe un mecanismo especial: host.docker.internal, un DNS interno que permite a los contenedores comunicarse con el host.
Así que regeneramos la imagen agregando la siguiente línea al momento de generar la imagen y el contenedor:
--add-host=host.docker.internal:host-gateway
docker build -t app-flask-chat-01 .
docker run -d -p 5050:5050 --add-host=host.docker.internal:host-gateway app-flask-chat-01Antes de esto, desde la app en Flask, nos conectamos a la app Django mediante:
# response = requests.get('http://127.0.0.1:8000/store/product')
response = requests.get('http://host.docker.internal:8000/store/product')Con esto, ahora podremos conectarnos de un contenedor a nuestro host de una manera sencilla
Esto habilita la comunicación con el host desde dentro del contenedor.
Tras ejecutar nuevamente, vemos que el error cambia: ahora obtenemos un 403 (Forbidden) en lugar del 500 anterior.
Volumenes
La siguiente evolución lógica en este curso es conocer los volúmenes. Ya no solo trabajamos con imágenes y contenedores, sino también con una nueva herramienta: los volúmenes.
¿Qué son los volúmenes?
Un volumen es una forma de persistir datos fuera del contenedor. Hasta ahora, cuando eliminábamos un contenedor, se perdía toda la información que contenía. Con los volúmenes, esos datos se mantienen independientemente del ciclo de vida del contenedor.
- Básicamente, funciona como un pendrive o disco duro externo: los datos se almacenan en un espacio independiente, fuera del contenedor.
- Esto nos permite desarrollar sin tener que generar nuevas imágenes constantemente para mantener información.
Donde partimos
De momento, hemos visto algunos conceptos básicos sobre cómo trabajar con Docker. Lo principal ha sido aprender sobre imágenes, contenedores y cómo podemos manipularlos: el típico CRUD de crear, eliminar, listarlos, etcétera.
También vimos cómo tomar una imagen para ejecutarla en un contenedor, configurarla mediante los puertos, y otras opciones. Básicamente, eso es lo que hemos hecho hasta este punto.
Aparte de eso, revisamos otra sección, ya que con solo esos conocimientos no es suficiente. Hasta ahora estábamos “jugando”: creamos una imagen, levantamos un contenedor, pero realmente no estábamos utilizando nada de manera práctica. Por ejemplo, levantamos Nginx, pero no había nada ejecutándose allí.
Problemas al trabajar con Docker en desarrollo
Entonces surge la pregunta: ¿cómo podemos, como programadores, utilizar Docker para nuestras propias soluciones?
Ahí es donde entra este curso, que busca enseñarte a levantar tus proyectos en Docker de manera práctica. Vimos un preámbulo en el que, mediante el Dockerfile, podemos tener nuestro propio proyecto. Revisamos ejemplos como una aplicación en Flask y otra en Django, agregando ciertas reglas para levantar la aplicación en Docker.
Hasta aquí todo perfecto, pero si has experimentado un poco con Docker, habrás notado algunos problemas:
- Docker puede usarse tanto en producción como en desarrollo.
- En producción, no pasa tanto: simplemente levantamos un contenedor sobre un servidor ya configurado (por ejemplo, Unicorn).
- En desarrollo, es diferente: cada cambio que hagamos en la aplicación requiere generar nuevamente la imagen (docker build) y levantar el contenedor (docker run).
Esto hace que el desarrollo sea poco funcional: cada cambio implica un proceso laborioso, eliminar contenedores anteriores, recrearlos, verificar errores, y volver a intentar.
Creación y uso de volúmenes
Vamos a probarlo paso a paso:
Abrimos la terminal y verificamos que Docker está ejecutándose.
Revisamos contenedores, imágenes y volúmenes. Todo forma parte del ecosistema de Docker.
Creamos un volumen usando:
$ docker volume create my_volumeAhora tenemos un volumen vacío, como un pendrive recién creado. Podemos listar los volúmenes con:
$ docker volume lsMontando el volumen en un contenedor
Para que tenga sentido, un volumen debe usarse con un contenedor. Por ejemplo:
$ docker run -it --name c1 -v my_volume:/data ubuntu- -v my_volume:/data indica que el volumen my_volume se montará en la carpeta /data dentro del contenedor.
Esto crea un espacio persistente donde se pueden guardar archivos, datos de la aplicación, logs, etc.
Dentro del contenedor:
$ cd /data
$ ls
$ echo "Hola desde contenedor" > archivo.txt
$ cat archivo.txtSi eliminamos el contenedor y levantamos uno nuevo:
$ docker run -it -v mi_volumen:/data ubuntu bashVeremos que la carpeta /data sigue ahí con los mismos archivos, porque los datos están persistiendo en el volumen, no en el contenedor.
Docker Compose: ¿Qué demonios es esto y qué pasó con los volúmenes?
¿Qué era lo que estábamos hablando anteriormente? Recuerda que el objetivo de este bloque, de esta sección, es poder utilizar Docker, pero no como una herramienta de deployment en producción, sino para trabajar perfectamente con nuestras aplicaciones durante el desarrollo.
La idea es que, por ejemplo, cuando tengamos cambios en el código, estos se puedan reflejar automáticamente en el contenedor y verlos por pantalla. Con lo que ya hemos visto de imágenes, contenedores y demás, no es suficiente; eso son solo las herramientas básicas, pero necesitamos más mecanismos.
Recordatorio: los volúmenes
Anteriormente vimos una pieza clave: los volúmenes. En resumidas cuentas —y lo viste en el video anterior— los volúmenes permiten persistir datos, lo cual es fundamental para lo que estamos mencionando. Pero necesitamos aún otra pieza clave: Docker Compose, que internamente ampliará el uso de los volúmenes para poder inyectar los cambios que estamos comentando.
¿Qué es Docker Compose?
Docker Compose es una herramienta que viene instalada junto con Docker (igual que pasa con pip cuando instalas Python o npm cuando instalas Node).
Básicamente, Compose permite emplear múltiples contenedores de Docker dentro de una sola aplicación.
Por ejemplo, aquí tenemos una aplicación Flask —la que vamos a construir ahora— donde utilizamos un contenedor para Flask (es decir, una imagen de Python) y también necesitamos Redis. Por lo tanto, son dos contenedores que deben comunicarse entre sí.
¿Y cómo los comunicamos?
Para eso está Compose: permite hacer esto de forma muy sencilla mediante un archivo de configuración.
Compose nos deja agregar todas las dependencias que necesite nuestro proyecto: Redis, MySQL, PostgreSQL, etc. Todo lo que necesites como contenedor.
Resumen de la definición
Docker Compose es una herramienta que permite definir y ejecutar aplicaciones con múltiples contenedores.
Ejemplo: un contenedor para Flask y otro para Redis.
Uso básico de Docker Compose
Compose tiene sus comandos típicos, lo que sería un pequeño “CRUD”: comandos para crear, parar, ver logs y listar.
En la documentación oficial puedes ver los comandos principales:
- compose up → levantar la aplicación
- compose down → detener y desmontar
- logs → ver registros
- ps → ver procesos/servicios activos
Todo lo típico.
En términos simples: Compose es un mecanismo para que desde un solo proyecto podamos utilizar múltiples contenedores, que al final son las dependencias de nuestra aplicación.
El proyecto de ejemplo con Flask y Redis
Este es el proyecto que vamos a montar como ejercicio. Es un ejemplo muy sencillo: una aplicación Flask que se conecta a Redis.
En el repositorio encontrarás:
- Dependencias
- Dockerfile
- Archivo docker-compose.yml
- Código fuente
- Configuraciones adicionales
El proyecto consiste en un contador almacenado en Redis, de manera que cada vez que recargamos la página, Redis incrementa un valor y Flask lo muestra. Redis se utiliza aquí como caché, aunque también sirve para almacenar datos temporalmente, manejar sesiones, colas, etc.
El retorno de Flask simplemente muestra por pantalla el valor incrementado.
Dockerfile y consideraciones
En el Dockerfile tenemos lo mismo de siempre:
- Imagen base de Python (la versión "alpine", más ligera).
- Directorio de trabajo.
- Instalación de dependencias (incluyendo las de Redis).
- Copia del proyecto completo al contenedor.
- Comando de ejecución.
Algunas variantes del proyecto usan flask run, que es lo recomendado para desarrollo, pero por ahora usaremos la forma más básica.
El archivo docker-compose.yml
Aquí viene la parte importante. Para usar Compose necesitamos este archivo específico. Puede llamarse docker-compose.yml o dockercompose.yml (con o sin guion bajo).
Servicios
En Compose, cada bloque de configuración representa un servicio, que básicamente es un contenedor.
Ejemplo de la estructura básica:
- web: servicio principal (Flask).
- redis: servicio para Redis.
En web se define:
- build: . → que construya la imagen a partir del Dockerfile.
- Puertos expuestos.
- Dependencias.
En redis simplemente definimos la imagen que vamos a usar (en este caso, la versión alpine de Redis).
Agregar otros servicios
Si quisiéramos usar MySQL, simplemente agregamos:
mysql:
image: mysql
...Compose permite agregar tantos servicios como necesite nuestro proyecto.
Levantando la aplicación
Si no tenemos contenedores, imágenes o volúmenes previos, Compose los va a generar.
El comando principal:
$ docker compose upEste comando:
- Lee el archivo docker-compose.yml.
- Construye las imágenes necesarias (si no existen).
- Crea los contenedores.
- Los levanta en el orden correcto.
El archivo Compose se convierte en la pieza clave del proyecto.
La aplicación Flask se levanta correctamente y ya podemos acceder a ella. Cada recarga incrementa el contador almacenado en Redis.
Problema pendiente: sincronización de cambios
Por ahora hacemos cambios en el proyecto y no se sincronizan con el contenedor.
Esto lo resolvemos en la siguiente clase con la parte de sincronización (volúmenes y docker watch).
Consideraciones importantes
- Primero configura el Dockerfile.
Si algo falla allí, Compose tampoco funcionará. - La base es siempre la aplicación.
Si la app no levanta, el contenedor construido desde el Dockerfile tampoco lo hará, y Compose mucho menos. - Compose es una capa superior.
Si algo falla abajo (app → Dockerfile → Compose), debes resolver el problema desde la base hacia arriba.
Acepto recibir anuncios de interes sobre este Blog.
Guía básica para iniciar con Docker, empezar a crear tus primeros contenedores, incluso si nunca has usado Docker antes. Verás cómo funciona internamente y empezar a usar Docker en tus proyectos.
Algunas recomendaciones:
Benjamin Huizar Barajas
Laravel Legacy - Ya había tomado este curso pero era cuando estaba la versión 7 u 8. Ahora con la ac...
Andrés Rolán Torres
Laravel Legacy - Cumple de sobras con su propósito. Se nota el grandísimo esfuerzo puesto en este cu...
Cristian Semeria Cortes
Laravel Legacy - El curso la verdad esta muy bueno, por error compre este cuando ya estaba la versi...
Bryan Montes
Laravel Legacy - Hasta el momento el profesor es muy claro en cuanto al proceso de enseñanza y se pu...
José Nephtali Frías Cortés
Fllask 3 - Hasta el momento, están muy claras las expectativas del curso
| 👤 Andrés Cruz
Por aquí tienes el listado completo de clases que vamos a cubrir en el libro y curso:
Primeros pasos
-
1 Conceptos Claves en Docker: Similitudes de Imágenes y contenedores con PHP, Node y Python - 01
Damos unas comparaciones para entre los conceptos claves de Docker como lo es los contenedores e imágenes con tecnologías que empleamos siempre como lo son PHP, Node y Python.
-
2 Conceptos Claves en Docker: Imágenes, Contenedores, Cliente y Demonio - 02
Introducimos LOS CONCEPTOS CLAVES de Imágenes, Contenedores, Cliente y Demonio y por supuesto, el de Docker.
-
3 Instalar Docker: UI y CLI
Hablamos sobre como instalar Docker, y que es lo que instalamos realmente...
-
4 El comando con el cual podrás entender el funcionamiento - docker run -d -p 8080:80 nginx - 04
Ejecutamos el siguiente comando: docker run -d -p 8080:80 nginx Con el cual se descarga la imagen de nginix, se crea el contenedor y se expone en el puerto 8080.
-
5 docker images - Listado de las imágenes - 05
Ejecutamos el siguiente comando: docker images
-
6 docker run - Ejecutar una imagen y generar un contenedor - 06
Ejecutamos el siguiente comando: docker run Con el cual ejecuta una imagen y crea un contenedor, hablemos sobre aspectos de configuración mediante parámetros y ejemplos de uso.
-
7 docker ps - Ver Todos los Contenedores Creados
Ejecutamos el siguiente comando: docker ps -a Con el cual veremos TODOS los contenedores y: docker ps Muestra TODOS los contenedores ejecutandose .
-
8 docker stop - Detener Contenedores en Ejecución
Ejecutamos el siguiente comando: docker stop ID/NAME Detenemos los contenedores que se encuentren ejecutándose.
-
9 docker rm - Eliminar Contenedores NO Ejecutandose - 09
Ejecutamos el siguiente comando: docker rm ID/NAME Para eliminar un contenedor
-
10 docker logs - Ver Traza de un Contenedor - 10
Ejecutamos el siguiente comando: docker logs ID/NAME Veremos el log o la traza de un contenedor
-
11 docker rmi - Elimina Una Imagen
Ejecutamos el siguiente comando: docker rmi ID/NAME Eliminamos una imagen
-
12 docker run/exec -it bash - Activar la Consola Interactiva sobre el Contenedor
Ejecutamos el siguiente comando: docker exec -it bash - Entrar dentro de un contenedor ACTIVO en modo interactivo (habilita el bash para lanzar comandos) docker run -it Container ID (Ej ubuntu) Crea el contenedor y lo deja en modo interactivo (habilita el bash para lanzar comandos)
-
13 docker stats - Monitorea tus contenedores en tiempo real
Vemos cómo ver el consumo de CPU y memoria en Docker (con docker stats)
Imágenes
-
1 Construir Imágenes en Docker - Conceptos Claves
Hablamos sobre como generar imágenes en Docker, en donde las claves es el archivo Dockerfile sobre nuestros proyectos y el comando de Dockerfile
-
2 Archivo Dockerfile, FUNDAMENTAL para construir nuestras Imágenes en Docker - Conceptos Claves
Los Dockerfiles son la pieza clave para poder crear imágenes personalizadas, te explico sus opciones claves.
-
3 DOCKERIZAR tu APP en FLASK: Crea tu Imagen Docker Fácil y Rápido en 2 Pasos
Te mostramos paso a paso cómo crear una imagen Docker limpia y eficiente para tu aplicación web desarrollada en Flask y como generar el contenedor.
-
4 DOCKERIZAR tu APP en FLASK + Servidor en Gunicorn
Te mostramos paso a paso cómo crear una imagen Docker de tu proyecto en Flask junto con el servidor de Gunicorn en Docker.
-
5 DOCKERIZAR tu APP en Django + Servidor en Gunicorn
Te mostramos paso a paso cómo crear una imagen Docker de tu proyecto en Django junto con el servidor de Gunicorn en Docker.
-
6 Conecta tu contenedor Docker con el localhost del host (¡usando host.docker.internal!)
"Docker no se conecta a tu localhost… hasta que usas esto"
Volumen
-
1 docker volume - TODO lo que necesitas saber - Persistir Datos
Aprendemos a emplear los volumes en Docker para poder persistir datos, en el ejercicio, usamos un contenedor de Ubuntu para crear una carpeta con los datos persistidos.
-
2 docker compose - Define y Ejecuta aplicaciones multicontenedor
Aprende a usar multicontenedores en tus proyectos con Docker, veremos como usar una app en Flask junto con el proceso de Redis y ejecutarlo en Docker.