2.0.-Introducción a los contenedores Docker
2.0. Introducción a los contenedores Docker¶
Idea principal
Un contenedor empaqueta una aplicación y las dependencias que necesita para ejecutarse de forma aislada y reproducible. Docker proporciona las herramientas para construir, distribuir y ejecutar esos contenedores sin tener que instalar cada aplicación directamente sobre el sistema anfitrión.
Cuando una aplicación pasa del ordenador de quien la desarrolla a otro equipo, es habitual que aparezcan diferencias: otra versión del lenguaje, una biblioteca que falta, una configuración distinta o un sistema operativo incompatible. La contenerización aborda este problema separando el entorno de ejecución de la aplicación del resto del sistema. Así, el equipo puede describir qué necesita la aplicación y repetir el mismo despliegue en desarrollo, pruebas y producción.
Este punto introduce los conceptos que se utilizarán durante toda la unidad: contenedor, imagen, motor Docker, registro, aislamiento, persistencia y red. No se trata de memorizar comandos aislados, sino de entender qué ocurre cuando se crea un contenedor y qué responsabilidades siguen siendo de la persona que lo administra. La instalación y los primeros comandos se desarrollan en Instalación de Docker.
Este contenido prepara el RA1 y, en particular, el CE 1.e de la normativa del módulo. La demostración práctica de la instalación y de las pruebas se completa en el punto siguiente.
| Código | Descripción |
|---|---|
| RA1 | Implanta arquitecturas web analizando y aplicando criterios de funcionalidad. |
| CE 1.e | Se ha realizado la instalación y configuración básica de tecnologías de virtualización de servidores en la nube y en contenedores. |
Qué deberías saber al terminar
Al acabar este tema deberías poder:
- explicar qué es un contenedor y por qué no equivale a una máquina virtual;
- describir cómo intervienen el núcleo del sistema, los namespaces y los cgroups en el aislamiento;
- distinguir una imagen, un contenedor, un registro y el motor Docker;
- interpretar el ciclo básico de una aplicación empaquetada en contenedores;
- valorar cuándo Docker aporta ventajas y qué riesgos no elimina.
Mapa del tema
En este documento seguiremos una progresión de lo general a lo concreto:
- el problema de las dependencias y la idea de contenerización;
- la diferencia entre máquinas virtuales y contenedores;
- el aislamiento que ofrece el sistema operativo;
- Docker como plataforma y sus componentes;
- el ciclo de vida de una aplicación contenedorizada;
- los casos de uso, las decisiones y los límites del modelo.
1. Del despliegue tradicional a la contenerización¶
Una aplicación no está formada únicamente por su código fuente. Para ejecutarse necesita un entorno: un lenguaje o runtime, bibliotecas, herramientas del sistema, variables de configuración, puertos y, en algunos casos, servicios auxiliares como una base de datos. Si esas piezas no coinciden entre dos máquinas, la aplicación puede fallar aunque el código sea exactamente el mismo.
Por ejemplo, una aplicación web desarrollada con Node.js puede requerir una versión concreta del runtime y de sus paquetes. Instalarla directamente en el ordenador anfitrión puede afectar a otras aplicaciones, y documentar todos los pasos manualmente no garantiza que otra persona reproduzca el entorno sin errores. Un contenedor permite reunir el código, el runtime y las bibliotecas necesarias en una unidad que se crea y se elimina de forma controlada.
Contenedor
Un contenedor es un proceso aislado que utiliza el núcleo del sistema operativo anfitrión y dispone de una vista restringida de los procesos, el sistema de archivos, la red y los recursos asignados. Incluye el entorno que necesita una aplicación, pero no contiene un sistema operativo completo con un núcleo independiente.
La palabra ligero no significa que el contenedor sea una carpeta comprimida ni que carezca de aislamiento. Significa que no necesita arrancar otro núcleo y que puede compartir partes de su sistema de archivos con otros contenedores. Docker es una plataforma de código abierto que organiza este proceso para que la misma definición pueda distribuirse y ejecutarse en distintos equipos compatibles. Sus ventajas principales son:
- Portabilidad: el entorno empaquetado se comporta de forma equivalente en los equipos que proporcionan un motor compatible;
- Eficiencia: no es necesario arrancar un sistema operativo completo por cada servicio;
- Aislamiento: cada aplicación obtiene una vista y unos recursos separados de los demás servicios;
- Rapidez: crear o detener un contenedor suele requerir mucho menos tiempo que arrancar una máquina virtual;
- Consistencia: el mismo artefacto puede probarse y desplegarse en varias fases del ciclo de entrega.
Un problema que la contenerización resuelve
Supón que una aplicación necesita Python 3.12 y una biblioteca que no es compatible con Python 3.10. En lugar de modificar todo el sistema anfitrión, el equipo puede empaquetar la aplicación con Python 3.12 dentro de una imagen. El contenedor utilizará ese entorno, mientras que otras aplicaciones del anfitrión podrán mantener sus propias versiones.
2. Contenedores y máquinas virtuales¶
Una máquina virtual (MV) emula o virtualiza un ordenador completo. Un hipervisor le asigna CPU, memoria, almacenamiento y red, y en ella se instala un sistema operativo invitado con su propio núcleo. El resultado ofrece un aislamiento amplio, pero necesita más recursos y tarda más en arrancar.
Un contenedor se ejecuta como un conjunto de procesos aislados sobre el sistema operativo anfitrión. Comparte su núcleo y reutiliza capas comunes del sistema de archivos. Por eso suele iniciar más rápido y consumir menos memoria, aunque su aislamiento no es equivalente al de una máquina virtual.
| Característica | Máquina virtual | Contenedor |
|---|---|---|
| Núcleo | Cada MV tiene su propio núcleo | Comparte el núcleo del anfitrión |
| Unidad aislada | Sistema operativo completo | Proceso y dependencias de la aplicación |
| Arranque | Normalmente más lento | Normalmente rápido |
| Consumo | Mayor, porque incluye otro sistema operativo | Menor, porque reutiliza el anfitrión y las capas |
| Portabilidad | Requiere una plataforma de virtualización compatible | Requiere un motor de contenedores compatible |
| Uso habitual | Otro sistema operativo, aplicaciones heredadas o aislamiento amplio | Servicios reproducibles, pruebas y despliegues ágiles |
flowchart TB
H["Hardware del servidor"] --> HV["Hipervisor"]
HV --> VM["Máquina virtual<br/>núcleo y sistema operativo propios"]
H --> OS["Sistema operativo anfitrión"]
OS --> E["Motor de contenedores"]
E --> C1["Contenedor web<br/>proceso aislado"]
E --> C2["Contenedor de base de datos<br/>proceso aislado"]
El diagrama muestra dos estrategias posibles. En un laboratorio pueden combinarse: Docker Desktop, por ejemplo, puede utilizar una máquina virtual gestionada internamente en Windows o macOS para proporcionar un núcleo Linux. Eso no cambia el modelo que estudiaremos: dentro de ese entorno, Docker crea contenedores que comparten el núcleo disponible.
No es una máquina virtual pequeña
Un contenedor no debe describirse como una máquina virtual reducida. Si una aplicación necesita otro núcleo, otro sistema operativo o una frontera de aislamiento más amplia, una máquina virtual puede ser una elección más adecuada. La decisión depende de los requisitos y del riesgo, no de una supuesta superioridad universal.
3. Cómo consigue el sistema operativo el aislamiento¶
La contenerización se apoya en capacidades del núcleo de Linux que permiten que un proceso vea un entorno limitado y tenga recursos controlados. Docker no inventa un núcleo nuevo para cada contenedor: coordina estas capacidades y ofrece una interfaz más sencilla para utilizarlas.
3.1. Namespaces: una vista separada¶
Un namespace proporciona a un proceso una vista diferente de determinados recursos del sistema. Un contenedor puede tener su propio espacio de procesos, red, usuarios, nombres de host y puntos de montaje. Desde dentro, el proceso principal puede aparecer como PID 1, mientras que desde el anfitrión sigue siendo un proceso normal gestionado por el núcleo.
Esta separación explica por qué un contenedor puede tener una interfaz de red y un sistema de archivos propios sin poseer hardware virtual completo. También explica por qué el aislamiento depende del núcleo y de la configuración del motor: no es una garantía absoluta frente a cualquier vulnerabilidad.
3.2. Cgroups: límites y contabilidad de recursos¶
Los control groups o cgroups permiten agrupar procesos y limitar o medir su consumo de recursos. Se pueden controlar, entre otros, la memoria, la CPU, la entrada y salida de disco y determinados aspectos de la red. Así se evita que un servicio consuma todos los recursos del anfitrión sin control.
Namespaces y cgroups resuelven problemas distintos:
| Mecanismo | Pregunta que responde | Ejemplo |
|---|---|---|
| Namespace | ¿Qué puede ver el proceso? | Solo ve sus procesos y su red |
| Cgroup | ¿Cuánto puede consumir? | Como máximo 512 MiB de memoria |
| Sistema de archivos por capas | ¿Qué archivos recibe y modifica? | Usa una imagen de solo lectura y una capa de cambios |
Aislamiento no significa seguridad automática
Compartir el núcleo implica que una vulnerabilidad del núcleo, del motor o
de una configuración con demasiados privilegios puede afectar al aislamiento.
No conviene utilizar --privileged por comodidad ni ejecutar servicios como
root sin una razón. En un entorno real también hay que actualizar imágenes,
limitar recursos, separar redes y proteger las credenciales.
3.3. Contenedores de sistema y de aplicación¶
Los materiales de referencia distinguen dos familias según su finalidad:
- Los contenedores de sistema, como LXC, intentan ofrecer un entorno parecido a una máquina completa. Su ciclo de vida puede incluir acceso, actualización e instalación de varios servicios dentro del mismo entorno.
- Los contenedores de aplicación, como Docker, se centran en ejecutar una aplicación o un servicio y distribuirlo con sus dependencias. Su ciclo de vida está ligado al proceso principal: cuando termina ese proceso, el contenedor se detiene.
LXC y Docker no son sinónimos. Ambos se apoyan en el aislamiento del sistema operativo, pero Docker aporta un flujo orientado a construir imágenes, distribuirlas y ejecutar contenedores de aplicación. Esta diferencia de propósito ayuda a entender por qué en Docker se suele separar una aplicación web, una base de datos y un servicio de colas en contenedores distintos.
4. Docker como plataforma¶
Docker popularizó un flujo de trabajo centrado en tres acciones: build, ship and run. Primero se construye una imagen; después se distribuye mediante un registro; finalmente se ejecuta como uno o varios contenedores. La imagen se convierte así en un artefacto que puede versionarse y trasladarse entre entornos.
4.1. El motor Docker¶
Docker Engine sigue un modelo cliente-servidor:
- La orden
dockeractúa como cliente y recoge la intención de la persona administradora. - La API transmite la petición al demonio
dockerd. - El demonio coordina imágenes, contenedores, redes, almacenamiento y permisos.
- Componentes como
containerdyruncparticipan en la creación y ejecución del proceso aislado.
En una instalación local, la comunicación suele realizarse mediante el socket
de Docker. La interfaz de línea de comandos oculta la complejidad de la API,
pero el modelo es importante para diagnosticar problemas: si el cliente no
puede comunicarse con el demonio, ningún docker run llegará a crear el
contenedor.
| Componente | Responsabilidad | Ejemplo de uso |
|---|---|---|
| Cliente Docker | Enviar órdenes al motor | docker ps, docker run |
| Docker Engine | Coordinar el entorno de ejecución | Crear redes y contenedores |
dockerd |
Recibir peticiones y administrar recursos | Gestionar el ciclo de vida |
containerd y runc |
Preparar y ejecutar el proceso aislado | Iniciar el proceso principal |
| Almacenamiento y red | Proporcionar capas, volúmenes y conectividad | Montar datos y publicar puertos |
4.2. Registro, Compose y orquestación¶
Un registro almacena y distribuye imágenes. Docker Hub es un registro público muy conocido, pero también se pueden utilizar registros privados de una empresa o de un proveedor cloud. El registro no ejecuta la aplicación: entrega la imagen al motor, y el motor crea el contenedor en el equipo elegido.
Docker Compose permite describir en un archivo YAML una aplicación que necesita varios contenedores, sus redes, sus volúmenes y su configuración. Está orientado a trabajar con varios servicios en un mismo equipo y se estudiará en el punto 2.4.
Un orquestador coordina contenedores en un clúster. Puede encargarse de replicar servicios, distribuir carga, reiniciar instancias y realizar actualizaciones controladas. Docker Swarm y Kubernetes son ejemplos de este tipo de herramientas. Compose y un orquestador no son equivalentes: Compose simplifica una aplicación multi-contenedor, mientras que el orquestador gestiona un conjunto de máquinas y servicios distribuidos.
flowchart LR
C["Cliente docker"] --> A["API del Docker Engine"]
A --> D["Demonio dockerd"]
D --> I["Imágenes y capas"]
D --> K["Contenedores"]
D --> N["Redes y puertos"]
D --> V["Volúmenes"]
R["Registro de imágenes"] -->|pull| I
I -->|docker run| K
5. Imagen, contenedor y ciclo de vida¶
Una imagen es una plantilla inmutable formada por capas de solo lectura. Incluye el sistema de archivos mínimo, las bibliotecas, los metadatos y el comando que se ejecutará. Una imagen no es un contenedor en funcionamiento.
Un contenedor es una instancia de una imagen con una capa de escritura y una configuración concreta: nombre, variables de entorno, red, puertos, volúmenes y límites de recursos. Varias instancias pueden utilizar la misma imagen y compartir sus capas de solo lectura.
| Elemento | Qué representa | Qué ocurre al eliminarlo |
|---|---|---|
| Imagen | Plantilla versionada para crear contenedores | Se conserva hasta borrarla expresamente |
| Contenedor | Ejecución concreta de una imagen | Se pierde su capa de cambios |
| Volumen | Datos separados del ciclo del contenedor | Se conserva hasta eliminarlo explícitamente |
| Registro | Servicio que distribuye imágenes | Los contenedores locales no se detienen por borrarlo |
El ciclo básico puede resumirse así:
- Se obtiene una imagen localmente o desde un registro.
- El motor crea un contenedor y añade su configuración.
- Se inicia el proceso principal de la imagen.
- El contenedor permanece en ejecución mientras ese proceso siga activo.
- Si el proceso termina, el contenedor queda detenido; no se convierte en una máquina apagada que pueda seguir ejecutando otros servicios por sí sola.
- Se puede reiniciar, eliminar o crear una nueva instancia desde la misma imagen.
flowchart LR
I["Imagen de aplicación"] -->|crear y ejecutar| C["Contenedor"]
C --> P["Proceso principal"]
P -->|sigue activo| R["Servicio disponible"]
P -->|termina| S["Contenedor detenido"]
S -->|recrear desde la imagen| C2["Nuevo contenedor"]
Un ejemplo conceptual es docker run hello-world. Docker busca la imagen en
el equipo; si no la encuentra, la obtiene del registro; crea el contenedor;
ejecuta el programa que muestra el mensaje y, cuando ese programa finaliza,
detiene el contenedor. El ejemplo no instala un sistema Ubuntu completo ni
deja un servicio ejecutándose: demuestra que el motor puede descargar una
imagen y ejecutar correctamente su proceso principal.
El sistema de archivos del contenedor es efímero
Los cambios realizados en la capa de escritura pertenecen a ese contenedor. Si el contenedor se elimina, esos cambios desaparecen. Los datos que deban sobrevivir se guardarán en volúmenes, bind mounts o servicios de almacenamiento externos. La unidad estudia estas opciones en el punto 2.3.
6. Aplicaciones web preparadas para contenedores¶
La contenerización resulta especialmente útil cuando una aplicación se puede separar en servicios con responsabilidades claras. Una aplicación monolítica también puede ejecutarse en un contenedor, pero conviene analizar si su servidor web, su lógica de aplicación y su base de datos deberían gestionarse como componentes diferenciados.
En una arquitectura sencilla, un servidor web recibe las peticiones, un servidor de aplicación ejecuta la lógica y una base de datos conserva el estado. Cada servicio puede tener su propia imagen, configuración, red y ciclo de actualización. No significa que haya que convertir cualquier programa en microservicios: separar componentes introduce comunicación de red, observación, copias de seguridad y coordinación adicionales.
flowchart LR
U["Navegador"] -->|HTTP| W["Contenedor web"]
W -->|Red interna| A["Contenedor de aplicación"]
A -->|Red interna| B["Contenedor de base de datos"]
B --> D["Volumen de datos"]
Un diseño razonable mantiene la base de datos en una red interna y publica solo el puerto que necesita el navegador. Las direcciones IP de los contenedores pueden cambiar al recrearlos; por eso los servicios deben localizarse por nombre dentro de una red Docker o mediante la configuración declarativa de Compose. Las decisiones de red, persistencia y publicación se desarrollarán en los puntos posteriores de la unidad.
Qué aporta el modelo en un despliegue web
Para probar una nueva versión de una aplicación, se puede crear un contenedor a partir de otra etiqueta de imagen sin modificar el servidor web del anfitrión. Si la prueba no funciona, se elimina el contenedor y se vuelve a crear el anterior. La facilidad para recrear no sustituye a una copia de seguridad ni a un procedimiento de cambio, pero reduce el riesgo de dejar instalaciones manuales a medio modificar.
7. Buenas prácticas¶
Para trabajar con contenedores con criterio técnico, conviene aplicar estas decisiones desde el principio:
- Elegir la tecnología por requisitos: utiliza contenedores cuando necesites empaquetado reproducible y arranque rápido; utiliza una máquina virtual si necesitas otro núcleo, otro sistema operativo o más aislamiento.
- Separar aplicación y datos: trata el contenedor como recreable y coloca la información persistente en volúmenes o servicios externos.
- Mantener una responsabilidad principal por contenedor: facilita los registros, las actualizaciones, las comprobaciones de salud y la recuperación.
- Fijar versiones: una etiqueta como
latestpuede cambiar; registra la versión probada y, cuando sea necesario, el digest de la imagen. - Aplicar mínimo privilegio: evita
--privileged, limita recursos y usa un usuario no privilegiado cuando la imagen y la aplicación lo permitan. - Publicar solo lo necesario: un puerto interno no tiene por qué exponerse al anfitrión ni a Internet.
- Leer la documentación de cada imagen: comprueba variables de entorno, puertos, volúmenes, arquitectura y procedimiento de actualización.
- Documentar el entorno: anota versión de Docker, sistema anfitrión, imágenes empleadas, puertos y decisiones de configuración.
8. Errores frecuentes¶
| Error frecuente | Por qué ocurre | Cómo evitarlo |
|---|---|---|
| Confundir un contenedor con una máquina virtual | Ambos parecen entornos aislados desde la terminal | Explica qué comparte cada uno con el anfitrión y recuerda que el contenedor no tiene un núcleo propio |
| Pensar que un contenedor es un sistema operativo completo | Una imagen puede incluir directorios con aspecto de sistema Linux | Identifica siempre el proceso principal y el núcleo que realmente utiliza |
Interpretar Exited como un fallo automático |
Se espera que el contenedor siga abierto después de terminar su comando | Comprueba el código de salida y relaciona el estado con el proceso principal |
| Guardar datos importantes en el sistema de archivos del contenedor | Durante una prueba los archivos parecen permanecer | Usa un volumen o almacenamiento externo antes de recrear o eliminar el contenedor |
| Publicar todos los puertos | Se usa -p sin analizar quién necesita el acceso |
Publica solo la entrada necesaria y limita la interfaz de escucha cuando proceda |
Usar latest como garantía de estabilidad |
Se interpreta como una versión fija | Fija una etiqueta compatible y documenta la imagen probada |
| Creer que Docker Hub ejecuta la aplicación | Se confunde registro con motor | El registro distribuye imágenes; el Docker Engine las ejecuta en un host |
| Convertir cualquier monolito en microservicios | Se asocia contenerización con microservicios obligatorios | Evalúa el beneficio y el coste operativo antes de separar componentes |
Añadir la cuenta al grupo docker sin valorar el riesgo |
Se busca evitar sudo |
Recuerda que el acceso al socket Docker puede equivaler a privilegios elevados y aplica la política del entorno |
9. Resumen¶
En este tema has aprendido que:
- un contenedor empaqueta una aplicación y sus dependencias como procesos aislados que comparten el núcleo del anfitrión;
- una máquina virtual incluye un sistema operativo y un núcleo propios, por lo que ofrece otro equilibrio entre aislamiento, consumo y flexibilidad;
- los namespaces separan la vista de los recursos y los cgroups controlan su consumo;
- Docker coordina cliente, API, demonio, imágenes, contenedores, redes y almacenamiento;
- una imagen es una plantilla, un contenedor es una ejecución y un registro es un lugar para distribuir imágenes;
- el proceso principal determina el ciclo de vida del contenedor y los datos persistentes deben separarse de su capa efímera;
- Docker Compose y los orquestadores resuelven problemas distintos y se estudiarán con más detalle en los siguientes puntos.
Idea clave
Docker no consiste en ejecutar una máquina virtual pequeña, sino en empaquetar y ejecutar procesos reproducibles sobre un sistema anfitrión. Entender qué se aísla, qué se comparte y qué debe persistir permite elegir una arquitectura de despliegue funcional y segura.
10. Para seguir practicando¶
- Instala Docker y comprueba el ciclo básico con Instalación de Docker.
- Compara etiquetas, capas y registros en Imágenes Docker.
- Experimenta con la diferencia entre datos efímeros, volúmenes y redes en Almacenamiento y redes.
- Describe en un diagrama qué servicios tendría una aplicación web de dos o tres capas y decide qué puerto debe publicarse.
- Relaciona el modelo conceptual con la práctica de la aplicación Guestbook.
Bibliografía y fuentes¶
- José Domingo Muñoz Rodríguez, Introducción a los contenedores, CPR de Zafra, 2021 (material de referencia proporcionado para estos apuntes).
- José Domingo Muñoz Rodríguez, Introducción a Docker, CPR de Zafra, 2021 (material de referencia proporcionado para estos apuntes).
- Normativa del módulo profesional 0614.
- Docker Docs: Get started.
- Docker Docs: Docker Engine.
- Open Container Initiative.
- Curso Docker IES.
Presentación¶
- DAW-U2.1 · Docker (presentación general reutilizable sobre conceptos y componentes).