Entender los contenedores
Módulo 9: Docker y docker compose · Tiempo de lectura: 10 minutos
Objetivo de aprendizaje: Después de esta lección podrá explicar qué es un contenedor, en qué se diferencia de una máquina virtual, dónde quedan los datos de un contenedor y cuándo tiene sentido usar Docker en su servidor.
Conceptos clave: imagen, contenedor, capa, registro (Docker Hub), tag, digest, namespaces, cgroups, kernel compartido, sistema de archivos volátil, volumen, bind mount, publicar un puerto, imagen oficial
¿Por qué contenedores?
Imagine que quiere ejecutar en su VPS una página de estado que muestre si su sitio web funciona. El programa está escrito en Node.js, necesita una versión concreta de Node.js y además unas doscientas bibliotecas. Sin contenedores, instala todo eso en su servidor, junto a su servidor web y su base de datos. Un año después quiere un segundo programa que necesita otra versión de Node.js. Y ahí empiezan los quebraderos de cabeza.
Un contenedor resuelve ese problema. El autor del programa lo entrega junto con todo lo que necesita, en un único paquete: una imagen. En su servidor, usted inicia esa imagen como contenedor. El programa ve sus propios archivos, su propio Node.js y sus propias bibliotecas, y no choca con el resto de su servidor. ¿Ya no lo necesita? Elimina el contenedor y la imagen, y no queda nada en /usr ni en /etc.
Docker es la herramienta más conocida para descargar imágenes y ejecutar contenedores. Existen alternativas (Podman, el propio containerd), pero los conceptos son los mismos en todas.
Imagen, contenedor y registro
Tres palabras que encontrará una y otra vez:
- Imagen: una plantilla de solo lectura con un sistema de archivos (programa, bibliotecas, configuración) y la orden que debe iniciarse. Una imagen se compone de capas: una capa base (por ejemplo, un Debian mínimo), encima una capa con Node.js y encima el programa. Dos imágenes con la misma capa base comparten esa capa en su disco.
- Contenedor: una instancia en ejecución (o detenida) de una imagen. Sobre las capas de solo lectura, el contenedor recibe su propia capa de escritura, muy fina. A partir de una sola imagen puede iniciar diez contenedores.
- Registro: el lugar donde se guardan las imágenes, como Docker Hub (
docker.io) o el registro de GitHub (ghcr.io). Docker descarga una imagen condocker pull.
El nombre de una imagen tiene este aspecto:
louislam/uptime-kuma:2
caddy:2
vaultwarden/server:latestLa parte que va después de los dos puntos es el tag (etiqueta): un nombre para una versión. Un tag puede cambiar: caddy:2 apunta hoy a una compilación distinta de la que apuntará dentro de tres meses, en cuanto salga una nueva 2.x. Si quiere fijar con precisión qué imagen ejecuta, utilice el digest: una huella digital del contenido, como caddy@sha256:.... Esta no cambia nunca. El tag latest es simplemente un nombre que elige el autor; no significa automáticamente «la versión estable más reciente» y por eso es una mala elección si quiere saber qué está ejecutando.
No es una máquina virtual
Un contenedor se parece a una pequeña máquina virtual, pero no lo es. Esa diferencia es importante para la seguridad.
| Máquina virtual (como su VPS) | Contenedor | |
|---|---|---|
| Kernel | Kernel propio | Comparte el kernel del host |
| Arranque | De segundos a minutos, un sistema operativo completo | Normalmente en un segundo, solo el programa |
| Aislamiento | Mediante el hipervisor, a nivel de hardware | Mediante el kernel: namespaces y cgroups |
| Tamaño | Gigabytes | A menudo de decenas a cientos de megabytes |
Un contenedor es en realidad un proceso normal en su servidor, que el kernel coloca en un entorno aislado:
- los namespaces hacen que el proceso tenga su propia visión de los archivos, los procesos, la red y los usuarios. Dentro del contenedor, el programa parece ser el proceso número 1 y no ve el resto de su servidor;
- los cgroups limitan cuánto procesador y memoria puede usar.
Como todos los contenedores comparten el mismo kernel, el aislamiento es menos estricto que entre dos VPS. Una vulnerabilidad en el kernel o un contenedor con demasiados privilegios puede afectar al host. De ahí las reglas de este módulo: ejecute solo imágenes de confianza, no conceda a los contenedores más privilegios de los necesarios y nunca monte /var/run/docker.sock ni / en un contenedor (lecciones 9.3 y 10.2).
¿Dónde quedan sus datos?
Esta es la trampa clásica para principiantes. La capa de escritura de un contenedor es volátil: si elimina el contenedor (por ejemplo, al actualizar, lección 9.4), todo lo que el programa escribió en ella desaparece. Por eso, los datos que deben conservarse tienen que estar fuera del contenedor:
- Volumen: un espacio de almacenamiento que gestiona el propio Docker (en
/var/lib/docker/volumes/). Usted le da un nombre, por ejemplouptime-kuma, y lo vincula a una carpeta del contenedor:-v uptime-kuma:/app/data. - Bind mount: una carpeta normal de su servidor que se monta en el contenedor:
-v /srv/vaultwarden:/data. Resulta práctico porque ve los archivos directamente y los incluye fácilmente en su copia de seguridad (módulo 8).
Un contenedor con buenos volúmenes puede eliminarse y volver a crearse sin perder nada. Así es exactamente como funciona una actualización: descargar la nueva imagen, eliminar el contenedor antiguo y crear un contenedor nuevo sobre los mismos volúmenes. Por eso, incluya los volúmenes en su plan de copias de seguridad (lección 8.1).
Publicar puertos
Un contenedor tiene su propia red. Un programa web que escucha dentro del contenedor en el puerto 3001 no es accesible desde fuera del servidor hasta que usted publica ese puerto: -p 3001:3001 (puerto del host:puerto del contenedor). Atención: sin dirección, Docker publica el puerto en todas las direcciones de su servidor, es decir, en 0.0.0.0 y [::]. Eso significa que es accesible desde todo internet, y Docker lo gestiona sin pasar por ufw (lección 9.3). La costumbre segura es publicar en loopback, -p 127.0.0.1:3001:3001, y poner delante un proxy inverso con https (lección 9.4).
¿Quién crea la imagen?
Una imagen es software de otra persona que puede ejecutarse como root en su servidor. Por eso, compruebe quién es el autor:
- Docker Official Images (como
caddy,nginx,postgres) las mantiene Docker junto con los autores; - imágenes del propio autor (como
louislam/uptime-kumayvaultwarden/server), reconocibles por el nombre que indica la web del proyecto; - imágenes de desconocidos con nombres parecidos: no las utilice.
Utilice siempre el nombre que figura en la web oficial del proyecto, no el primero que aparezca en una búsqueda.
¿Cuándo sí y cuándo no?
Docker resulta útil para programas que el autor distribuye como imagen, para servicios que quiere poder eliminar o trasladar rápidamente y para ejecutar varios programas con requisitos distintos uno al lado del otro. Para la base de su servidor (SSH, firewall, actualizaciones) no se usan contenedores. Y un único sitio web con nginx y PHP de los repositorios de paquetes (lección 7.2) funciona perfectamente sin Docker. Un contenedor añade una capa que debe entender y mantener actualizada; utilícelo cuando aporte algo.
Resumen
- Una imagen es una plantilla de solo lectura formada por capas; un contenedor es una instancia en ejecución con su propia capa de escritura.
- Los contenedores comparten el kernel del host y están aislados mediante namespaces y cgroups: más ligeros que una VM, pero con un aislamiento menos estricto.
- La capa de escritura es volátil: los datos permanentes deben estar en un volumen o un bind mount, y estos deben estar en su copia de seguridad.
- Un tag puede cambiar, un digest no;
latestdice poco. - Publique los puertos en 127.0.0.1 y utilice solo imágenes del autor o imágenes oficiales.
Cuestionario
Ejercicio
Ejercicio O9.1: ¿Contenedor o no? Elija dos programas que quiera ejecutar en su servidor (o utilice como ejemplo Uptime Kuma y un sitio de WordPress). Para cada programa, averigüe si el autor ofrece una imagen oficial y con qué nombre, qué tag elegiría, qué carpeta contiene los datos permanentes y en qué puerto escucha. Después explique si lo ejecutaría en un contenedor o desde los repositorios de paquetes, y por qué.
Ejercicio O9.1: ¿Contenedor o no?
Este ejercicio lo hace usted mismo; nadie lo revisa. Marque lo que haya hecho y señale el ejercicio como realizado.
Uptime Kuma: louislam/uptime-kuma con una etiqueta de versión, datos en /app/data, puerto 3001, publicado en 127.0.0.1 detrás de un proxy inverso. Elija una imagen del propio desarrollador o una Official Image, con una etiqueta de versión y una carpeta de datos con nombre.
Sus marcas y notas se quedan solo en este navegador; no las enviamos a ningún sitio. Si ha iniciado sesión, en Mis cursos solo guardamos que ha realizado el ejercicio.
Para saber más
- Documentación de Docker, What is a container?: https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/
- Documentación de Docker, Volumes: https://docs.docker.com/engine/storage/volumes/
- Documentación de Docker, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Docker Official Images: https://docs.docker.com/docker-hub/repos/manage/trusted-content/official-images/
