Los contenedores no son valiosos por sí mismos. Aportan valor cuando convierten un entorno difícil de repetir en un artefacto y una configuración que pueden construirse, distribuirse y ejecutarse de forma consistente.
La pregunta correcta no es “¿Docker es una buena práctica?”, sino:
¿Qué variación, dependencia o dificultad operativa elimina en este sistema, y qué nuevas responsabilidades introduce?
Docker suele mejorar la entrega cuando varios ambientes deben ejecutar el mismo software, existen dependencias incompatibles o se necesita crear y destruir entornos con frecuencia. También puede ser una capa innecesaria cuando el problema ya está resuelto por una plataforma administrada o el sistema es demasiado simple para justificarla.
Una aplicación no está formada únicamente por su código fuente. Su comportamiento también depende de:
versión del runtime;
paquetes del sistema operativo;
librerías nativas;
variables de entorno;
estructura de directorios;
certificados;
puertos;
usuarios y permisos;
servicios externos;
comandos utilizados para instalar y arrancar.
Cuando esos elementos se configuran manualmente, el conocimiento queda repartido entre documentación, scripts, memoria del equipo y estado histórico de cada máquina.
Imagina una API Node.js que necesita Node 22, una versión concreta de libc, PostgreSQL y Redis. Sin una estrategia reproducible, cada desarrollador debe instalar y mantener todo eso. CI necesita otra preparación. Producción necesita una tercera. Aunque las instrucciones sean iguales, los resultados pueden diferir por actualizaciones, archivos residuales o configuración previa.
Docker permite describir una parte de ese entorno como código:
Texto
source + lockfiles + Dockerfile
→ image versionada
→ misma unidad de ejecución en desarrollo, CI y producción
Esto no significa que todos los ambientes sean idénticos. El kernel, recursos, secretos, red y servicios externos pueden cambiar. La ventaja es que el artefacto principal deja de reconstruirse manualmente en cada destino.
Una imagen fija un filesystem y metadata de ejecución. Si el mismo digest se ejecuta en dos hosts compatibles, ambos parten del mismo artefacto.
La reproducibilidad no es absoluta. Una aplicación todavía puede variar por environment, arquitectura, servicios externos, tiempo, red o recursos. Docker reduce una categoría de variación: la preparación interna del runtime.
CI puede levantar una aplicación y sus dependencias, ejecutar pruebas y destruir todo después.
Bash
docker compose up -d--waitnpm run test:e2e
docker compose down -v
Esto reduce dependencia de servidores de prueba compartidos y estados acumulados. Sin embargo, las pruebas solo son útiles si las imágenes y configuración representan realmente el entorno objetivo.
Un desarrollador nuevo puede iniciar varios servicios con menos instalación global. Esto reduce tiempo inicial, pero no elimina la necesidad de comprender el sistema. Un equipo que solo sabe ejecutar docker compose up seguirá teniendo problemas cuando red, permisos o datos fallen.
Debes elegir base images, actualizar dependencias, corregir vulnerabilidades, gestionar cache y garantizar compatibilidad.
Una imagen que funcionaba hace meses puede contener paquetes obsoletos aunque el código no haya cambiado. Mantener imágenes implica reconstrucciones periódicas y pruebas.
Las imágenes necesitan almacenamiento, autenticación, retención, escaneo y trazabilidad. Debes decidir quién puede publicar, qué artefactos son confiables y qué ocurre si el registry no está disponible.
El contenedor es reemplazable, pero los datos no siempre lo son. Databases, uploads y colas requieren volumes o servicios externos, backups, restore y capacidad.
Ahora existen al menos dos perspectivas: red del host y red del contenedor. localhost cambia de significado, aparecen DNS interno, publicaciones de puertos y firewalls.
Debes proteger daemon, socket, images, secrets, mounts, capabilities, usuarios y kernel. Ejecutar una aplicación insegura dentro de Docker no la vuelve segura.
Windows, macOS y Linux pueden trabajar sobre imágenes Linux mediante Docker Desktop o Engine. Persisten diferencias de filesystem y rendimiento, pero se reduce la instalación específica del stack.
Una aplicación se despliega en VMs o servidores propios. La imagen sirve como unidad de entrega en lugar de copiar código y ejecutar instalación remota.
La plataforma controla runtime, escalado y despliegue. Empaquetar una imagen personalizada solo tiene sentido si se necesita una dependencia o control que el runtime estándar no ofrece.
Un script con una dependencia y uso individual puede ser más sencillo con un entorno del lenguaje. Docker añade daemon, imagen, mounts y comandos sin eliminar un problema real.