Buenas prácticas de Docker para crear y ejecutar contenedores
Ago 12, 2026
/
Faradilla A.
/
13 min Leer
Las buenas prácticas de Docker son pautas para crear, ejecutar y mantener contenedores de forma segura y eficiente.
Docker empaqueta las aplicaciones y sus dependencias en contenedores portátiles que funcionan de forma uniforme en distintos entornos.
Esta uniformidad simplifica el desarrollo y el despliegue, pero para que la contenedorización sea fiable no basta con empaquetar una aplicación en una imagen.
Las buenas prácticas se centran en los aspectos que más influyen en entornos reales, como la optimización de imágenes, la eficiencia de las compilaciones, la seguridad de los contenedores, la gestión de secretos, la observabilidad y la preparación para la orquestación.
En conjunto, estas técnicas permiten crear contenedores más fáciles de desplegar, escalar, proteger y mantener durante todo su ciclo de vida.
1. Usa imágenes base oficiales y minimalistas
Las imágenes oficiales proceden de mantenedores de confianza y ofrecen una base más segura para tus contenedores, mientras que las imágenes minimalistas reducen el número de paquetes, herramientas y bibliotecas incluidos en la imagen final.
Las imágenes base minimalistas, como Alpine, permiten crear contenedores más ligeros porque solo incluyen lo imprescindible para ejecutar una aplicación.
Consejo profesional
Al elegir una imagen base, opta por imágenes distroless, como las de Google, para cargas de trabajo de producción en las que necesites reducir al máximo la superficie de ataque. Usa imágenes basadas en Alpine cuando necesites un shell o un gestor de paquetes para depurar durante el desarrollo.
Las imágenes de uso general más grandes incluyen más utilidades del sistema y dependencias, lo que supone tener más componentes que actualizar, analizar y proteger. Cada paquete adicional añade código que hay que mantener. Eliminar lo que no necesitas reduce las vulnerabilidades y agiliza la creación, descarga e inicio de las imágenes.
2. Fija las versiones de las imágenes base para conseguir compilaciones reproducibles
Fija versiones concretas de las imágenes base para conseguir compilaciones reproducibles y evitar cambios inesperados. Usar etiquetas genéricas, como latest, genera incertidumbre porque la imagen subyacente puede cambiar en cualquier momento.
Un Dockerfile que hoy funciona puede generar una imagen diferente mañana, aunque el código de la aplicación no haya cambiado.
Fijar las versiones hace que los despliegues sean más predecibles, ya que garantiza que las compilaciones utilicen siempre la misma versión de la imagen base.
Una etiqueta como node:22.11-alpine o python:3.12-slim ayuda a evitar cambios inesperados en las dependencias, actualizaciones imprevistas de paquetes y problemas de compatibilidad difíciles de diagnosticar después del despliegue.
Los equipos que necesiten mayores garantías pueden fijar los digests de las imágenes además de las etiquetas de versión. Los digests identifican una imagen concreta y garantizan que Docker descargue siempre exactamente la misma imagen.
Esto requiere más mantenimiento, ya que los digests fijados no se actualizan automáticamente. Los parches de seguridad y las nuevas versiones deben revisarse manualmente y actualizarse en el Dockerfile.
3. Escribe archivos Dockerfile eficientes
Cuando escribas archivos Dockerfile, ten en cuenta el tamaño de la imagen, la velocidad de compilación y la seguridad. La estructura del Dockerfile determina cuántas capas crea Docker, cuántos datos se incluyen en la imagen final y con qué eficiencia las futuras compilaciones podrán reutilizar el trabajo almacenado en caché.
Los Dockerfile eficientes evitan dependencias innecesarias y eliminan los archivos temporales después de instalar los paquetes.
Las herramientas de compilación, las cachés de paquetes, los registros y los archivos descargados no deberían permanecer en la imagen de ejecución, salvo que la aplicación los necesite. Los archivos innecesarios aumentan el tamaño de la imagen y añaden componentes que hay que analizar, parchear y mantener.
La gestión de las capas también es importante. Agrupa los comandos relacionados en una única instrucción RUN para reducir las capas innecesarias. Una imagen más pequeña solo resulta útil si quienes trabajen con el Dockerfile pueden entender cómo se crea la imagen y actualizar las instrucciones de forma segura.
Los archivos Dockerfile predecibles son más fáciles de mantener a largo plazo. Un orden claro de las instrucciones, las dependencias explícitas y los comandos fáciles de entender reducen los imprevistos durante la compilación y facilitan el diagnóstico de los fallos durante los despliegues.
4. Usa compilaciones en varias etapas para reducir el tamaño de la imagen
Usa compilaciones en varias etapas para separar las herramientas de compilación de las dependencias de ejecución. Las herramientas de compilación, los compiladores, los gestores de paquetes y los archivos fuente solo son necesarios durante el desarrollo de la aplicación.
El contenedor final solo necesita la aplicación compilada y los archivos necesarios para ejecutarla.
Las compilaciones en varias etapas reducen el tamaño de la imagen al excluir componentes innecesarios durante la ejecución. Las imágenes más pequeñas se transfieren y se inician más rápido, además de ocupar menos espacio de almacenamiento.
Eliminar las herramientas de compilación y las dependencias de desarrollo también reduce la superficie de ataque, ya que hay menos componentes disponibles dentro del contenedor en ejecución.
Las compilaciones en varias etapas son más eficaces para aplicaciones compiladas y proyectos con muchas dependencias de compilación.
Este enfoque suele ser especialmente útil con lenguajes y marcos como Go, Java, .NET y Node.js, así como con proyectos de React, porque el entorno de compilación es bastante más grande que el entorno de ejecución.
Consejo profesional
Un Dockerfile básico de varias etapas utiliza una instrucción FROM distinta para cada etapa. Asigna un nombre a la etapa de compilación, por ejemplo, FROM node:20-alpine AS builder, ejecuta los pasos de compilación y, después, inicia otra etapa con una imagen base minimalista y copia únicamente el resultado compilado con COPY --from=builder.
Separar las etapas permite mantener las imágenes de producción ligeras sin complicar el flujo de trabajo de desarrollo.
5. Optimiza el uso de la caché de compilación de Docker
Optimiza el uso de la caché de compilación de Docker para reducir los tiempos de compilación y evitar trabajo innecesario durante las recompilaciones. Docker almacena cada instrucción como una capa reutilizable, lo que permite reutilizar las partes del proceso de compilación que no han cambiado en lugar de volver a compilarlas desde cero.

Ordena las instrucciones del Dockerfile desde las que tienen menos probabilidades de cambiar hasta las que tienen más.
Las instrucciones estables deberían tener prioridad. La instalación de paquetes del sistema, los manifiestos de dependencias y la configuración básica cambian con menos frecuencia que el código fuente de las aplicaciones.
Copia los archivos de dependencias antes de copiar toda la aplicación para que Docker pueda reutilizar las capas de instalación de las dependencias cuando solo cambie el código de la aplicación.
Define con cuidado los pasos de instalación de paquetes. Combina apt-get update y apt-get install en una sola instrucción para mantener sincronizados los índices y los paquetes instalados.
Elimina las cachés de los paquetes tras la instalación para evitar que se guarden archivos innecesarios en la imagen. Las imágenes más pequeñas se transfieren más rápido, ocupan menos espacio de almacenamiento y requieren menos datos que analizar y mantener.
Ordena los argumentos de varias líneas siempre que sea posible. Las listas de paquetes ordenadas reducen las entradas duplicadas, facilitan las revisiones y ayudan a detectar rápidamente los cambios cuando se añaden o eliminan dependencias.
6. Excluye los archivos que no necesites con .dockerignore
Usa un archivo .dockerignore para excluir los archivos y directorios que no sean necesarios para la compilación.
Docker envía todo el contexto de compilación al daemon de Docker antes de crear una imagen. Los archivos innecesarios aumentan tanto la cantidad de datos que Docker debe procesar como el riesgo de incluir información confidencial por error.

Excluye los archivos confidenciales, como los archivos .env, las claves SSH, las credenciales, los archivos de configuración locales y otros secretos.
Si incluyes esos archivos por error en el contexto de compilación, aumentas el riesgo de que se filtre información confidencial a través de imágenes de contenedores, registros de imágenes o sistemas de compilación.
Excluye también el contenido innecesario. Los metadatos del control de versiones, los registros locales, los archivos temporales, los artefactos de prueba, las cachés de dependencias y los directorios de desarrollo aumentan la cantidad de datos que Docker tiene que procesar durante las compilaciones.
Un contexto de compilación más pequeño agiliza la creación de imágenes, evita que ocupen espacio innecesario y limita su contenido a los archivos necesarios para ejecutar la aplicación.
7. Ejecuta los contenedores como usuario no root
Los procesos que se ejecutan como root tienen privilegios elevados dentro del contenedor, lo que aumenta el impacto potencial de un ataque.
Una vulnerabilidad que permite a un atacante ejecutar comandos dentro de un contenedor se vuelve más peligrosa cuando la aplicación se ejecuta con permisos sin restricciones.
Crea un usuario específico para la aplicación y cambia a él mediante la instrucción USER del Dockerfile. Ejecutar la aplicación con una cuenta que no sea root limita los recursos a los que el proceso puede acceder y los cambios que puede realizar, lo que reduce el impacto si se aprovecha una vulnerabilidad de la aplicación.
Aplica también el principio de mínimo privilegio a los archivos y directorios. Concede a los contenedores acceso únicamente a los archivos y recursos necesarios para su funcionamiento normal y configura los permisos del sistema de archivos en consecuencia.
Limitar los privilegios tanto a nivel de usuario como del sistema de archivos reduce la superficie de ataque y ayuda a contener los incidentes de seguridad cuando se producen.
8. Gestiona los secretos de forma segura durante la ejecución
Las claves de API, las contraseñas de bases de datos, los tokens de acceso y los certificados incluidos directamente en el código permanecen integrados en la imagen y pueden quedar expuestos a través de repositorios de código fuente, registros de contenedores, análisis de imágenes o artefactos de compilación compartidos.
Eliminar los datos confidenciales de las imágenes de contenedores evita que las credenciales se distribuyan junto con el código de la aplicación.
¡Advertencia! No pases secretos como argumentos de compilación de Docker mediante --build-arg. Los valores que se pasan de esta forma se almacenan en el historial de capas de la imagen y se pueden recuperar con docker history, aunque no aparezcan en la imagen final ni en el Dockerfile.
Guarda los valores confidenciales con herramientas diseñadas para gestionar secretos, como HashiCorp Vault, AWS Secrets Manager y Azure Key Vault.
Docker secrets ofrece una opción más segura al montar los secretos directamente en los contenedores en ejecución, sin exponerlos en variables de entorno, capas de imagen ni listados de procesos.
Las variables de entorno se usan mucho para la configuración durante la ejecución, pero deben considerarse una opción de reserva. Se pueden consultar con el comando docker inspect y pueden aparecer en los registros si una aplicación muestra su entorno.
Sigue las buenas prácticas para las variables de entorno: guarda los valores confidenciales fuera del código de la aplicación, restringe el acceso a las credenciales y evita que los secretos se escriban en los registros.
En los despliegues a gran escala se suelen utilizar plataformas externas de gestión de secretos para centralizar el almacenamiento de credenciales, el control de acceso, la auditoría y la rotación.
Para evitar que se revelen datos confidenciales, no basta con elegir el método de almacenamiento adecuado. Limita el acceso a los valores confidenciales, evita registrar las credenciales, revisa las imágenes por si se han incluido datos confidenciales por error y renueva las credenciales con regularidad.
9. Limita las capacidades y los recursos de los contenedores
Los contenedores solo deben tener los permisos necesarios para cumplir su función, así que limita sus capacidades y recursos siguiendo el principio de mínimo privilegio.
Los privilegios innecesarios aumentan el impacto de una intrusión, ya que permiten a los atacantes acceder a más recursos y funcionalidades del sistema de los que la aplicación realmente necesita.
Evita ejecutar contenedores como root siempre que sea posible y limita el acceso a las partes sensibles del host.
Los espacios de nombres de usuario asignan los usuarios de los contenedores a cuentas con menos privilegios en el host, lo que reduce el riesgo de escape del contenedor y de escalada de privilegios.
Los sistemas de archivos de solo lectura ofrecen otra capa de protección, ya que impiden que las aplicaciones y los atacantes modifiquen los archivos que deben permanecer inalterados durante el funcionamiento normal.
Elimina las capacidades que la aplicación no necesite. Muchos contenedores no necesitan privilegios elevados de red, de administración del sistema ni relacionados con el kernel, aunque esas capacidades pueden estar disponibles por defecto.
Limitar las capacidades reduce el número de acciones que puede realizar un contenedor comprometido y ayuda a minimizar la superficie de ataque global.
Establece límites explícitos de recursos para evitar que los contenedores consuman más de la parte que les corresponde de CPU y memoria. Sin límites, un solo contenedor puede agotar los recursos del host y afectar a otras cargas de trabajo que se estén ejecutando en el mismo sistema.
10. Diseña contenedores sin estado y efímeros
Diseña contenedores sin estado y efímeros para poder detenerlos, eliminarlos y volver a crearlos sin perder datos importantes.
Un contenedor debería ejecutar el proceso de la aplicación, no servir como lugar de almacenamiento permanente para archivos, bases de datos, sesiones o archivos subidos por los usuarios.
Guarda los datos persistentes fuera del contenedor. Los volúmenes de Docker, las bases de datos gestionadas, el almacenamiento de objetos y los servicios externos garantizan que los datos importantes sigan estando disponibles incluso cuando se sustituyan los contenedores durante actualizaciones, fallos u operaciones de escalado.
Separar la ejecución de la aplicación del almacenamiento persistente también facilita la gestión de los backups, las migraciones y los procesos de recuperación.
Los contenedores sin estado son más fáciles de escalar y orquestar. Las plataformas de orquestación pueden reiniciar los contenedores que fallan, mover cargas de trabajo entre hosts y crear réplicas adicionales sin depender de los datos almacenados dentro de una instancia concreta de contenedor.
11. Añade comprobaciones de estado a los servicios de larga duración
Añadir comprobaciones de estado a los servicios que se ejecutan durante mucho tiempo permite que Docker y las plataformas de orquestación detecten cuándo un contenedor deja de funcionar correctamente.
Que un contenedor esté en ejecución no significa que funcione correctamente. Una aplicación puede dejar de responder a las solicitudes, perder la conexión con la base de datos o entrar en un estado de fallo mientras el proceso del contenedor continúa ejecutándose.
La instrucción HEALTHCHECK permite a Docker realizar comprobaciones periódicas e informar sobre el estado del contenedor.
Las comprobaciones de estado permiten verificar que una aplicación responda a las solicitudes HTTP, acepte conexiones o realice otras funciones básicas necesarias para su funcionamiento normal.
Consejo profesional
Ajusta los parámetros --interval, --timeout y --retries en función del tiempo de inicio de la aplicación. Por ejemplo, un servicio que tarda 30 segundos en inicializarse debería usar --start-period=30s para evitar falsos errores durante el arranque.
Las plataformas de orquestación usan la información sobre el estado de los contenedores para tomar decisiones automáticas de recuperación. Si fallan las comprobaciones de estado, pueden reiniciar los contenedores, sustituir las instancias que no funcionan correctamente o retirar los contenedores del enrutamiento del tráfico.
La detección temprana de fallos en las aplicaciones reduce el tiempo de inactividad y ayuda a mantener la disponibilidad del servicio en los entornos de producción.
12. Analiza las imágenes en busca de vulnerabilidades con regularidad
Analizar las imágenes de los contenedores con regularidad permite detectar vulnerabilidades conocidas antes de que lleguen al entorno de producción.
Los escáneres de vulnerabilidades como Trivy, Docker Scout y Snyk comparan los paquetes, las bibliotecas y las dependencias instaladas con bases de datos de seguridad, lo que ayuda a los equipos a detectar software obsoleto y problemas de seguridad conocidos en una fase temprana del proceso de desarrollo.

Integra el análisis de imágenes en las canalizaciones de CI/CD para que las comprobaciones de seguridad se ejecuten automáticamente durante las compilaciones y los despliegues.
El análisis automático ayuda a detectar vulnerabilidades antes de que las imágenes se publiquen en los registros o se desplieguen en entornos de producción, lo que reduce el riesgo de desplegar versiones poco seguras.
Analiza tanto la imagen base como las capas de la aplicación. Una aplicación segura puede seguir heredando vulnerabilidades de una imagen base desactualizada, mientras que una imagen base totalmente actualizada no protege contra las dependencias inseguras de la aplicación.
Analizar la imagen completa ofrece una visión más precisa de la seguridad de los contenedores y ayuda a priorizar las medidas correctivas antes del despliegue.
13. Supervisa y registra la actividad de los contenedores
La supervisión y el registro de la actividad de los contenedores permiten mantener una visión clara del estado, el rendimiento y los fallos de las aplicaciones.
Los entornos basados en contenedores son dinámicos por naturaleza, ya que los contenedores se inician, se detienen, se escalan y se sustituyen con frecuencia. Sin una observabilidad fiable, identificar el origen de los problemas de rendimiento o de los fallos de las aplicaciones se vuelve mucho más difícil.
Centraliza los registros y recopila métricas de los contenedores, los hosts y los servicios auxiliares. Los registros centralizados facilitan la investigación de errores en aplicaciones distribuidas, mientras que las métricas permiten hacer un seguimiento del uso de recursos, los tiempos de respuesta, el volumen de solicitudes y otros indicadores del estado de las aplicaciones.
En conjunto, los registros y las métricas te dan el contexto que necesitas para solucionar problemas e identificar los cuellos de botella en el rendimiento.
Usa herramientas de monitorización que se integren bien con los entornos de contenedores. Prometheus y Grafana se usan mucho para recopilar y visualizar métricas, mientras que soluciones como la pila ELK (Elasticsearch, Logstash y Kibana) y Loki ayudan a centralizar y analizar los registros de los contenedores.
Recopilar registros y métricas solo sirve de algo si se avisa a las personas adecuadas cuando algo va mal. Configura alertas para las situaciones que indiquen problemas reales: uso elevado y prolongado de la CPU o la memoria, picos en la tasa de errores, comprobaciones de estado fallidas y contenedores que se reinician una y otra vez.
Envía las alertas a los canales adecuados, como una plataforma de mensajería, una herramienta de gestión de incidencias o un sistema de turnos de guardia, para que se actúe ante los problemas en lugar de descubrirlos cuando ya se han producido.
14. Limpia los recursos de Docker que no uses
Limpia con regularidad los recursos de Docker que no uses para recuperar espacio de almacenamiento y mantener organizados los servidores de contenedores.
Las imágenes que no se usan, los contenedores detenidos, los volúmenes huérfanos y las redes que no se usan se van acumulando con el tiempo, sobre todo en entornos de desarrollo y sistemas de CI/CD en los que se crean y se despliegan imágenes con frecuencia.
Elimina los recursos que ya no necesites con comandos de limpieza de Docker como docker image prune, docker container prune, docker volume prune y docker system prune.
¡Advertencia! Al ejecutar docker system prune -a, se eliminan todas las imágenes que no se estén utilizando, no solo las imágenes huérfanas. Esto incluye las imágenes que no estén asociadas en ese momento a un contenedor en ejecución y que podrían ser necesarias para futuros despliegues. Comprueba siempre qué se va a eliminar antes de ejecutar este comando en entornos compartidos o de producción.
Los scripts de limpieza automáticos y las tareas de mantenimiento programadas ayudan a evitar la acumulación de recursos en los servidores que llevan mucho tiempo en funcionamiento sin que haga falta intervenir manualmente.
El consumo de almacenamiento afecta a más aspectos que el uso del disco. Una gran cantidad de recursos sin usar complica la gestión de los entornos, aumenta el tamaño de los backups y ocupa espacio que podrían aprovechar las cargas de trabajo activas.
15. Prueba los contenedores antes del despliegue
Probar los contenedores antes del despliegue te permite asegurarte de que la imagen funciona igual que lo hará en producción.
Que la compilación se complete correctamente solo demuestra que Docker ha creado una imagen. No significa que la aplicación se inicie correctamente, se conecte a los servicios necesarios, gestione el tráfico o cumpla los requisitos de seguridad.
Incorpora pruebas de contenedores al flujo de trabajo de desarrollo. Las pruebas unitarias validan la lógica de la aplicación, las pruebas de integración verifican las conexiones entre servicios dentro de los contenedores y los análisis de seguridad comprueban si las imágenes tienen vulnerabilidades conocidas antes del lanzamiento.
Las pruebas de rendimiento también ayudan a detectar tiempos de arranque lentos, límites de recursos y problemas de ejecución que solo se producen en el entorno de contenedores.
Automatiza las pruebas de contenedores siempre que puedas. Las herramientas de CI/CD, como GitHub Actions, GitLab CI/CD, Jenkins y CircleCI, pueden crear imágenes, ejecutar pruebas, buscar vulnerabilidades y bloquear el despliegue cuando fallan las comprobaciones.
Las pruebas automatizadas reducen el riesgo de desplegar contenedores defectuosos o poco seguros en el entorno de producción.
Cómo elegir la plataforma de orquestación de contenedores adecuada
Elige una plataforma de orquestación de contenedores en función de la complejidad de tu entorno, tus requisitos de escalabilidad, tus recursos operativos y tus necesidades de integración.
La elección adecuada no depende tanto de la lista de funciones como de la infraestructura que tengas que gestionar.
Empieza por evaluar el volumen y la complejidad de la carga de trabajo. Las aplicaciones que ejecutan un número reducido de contenedores suelen necesitar menos funciones de orquestación que los grandes sistemas distribuidos con decenas o cientos de servicios.
Gestionar una plataforma más potente de lo que requiere la carga de trabajo añade complejidad operativa sin aportar beneficios significativos.
A continuación, piensa en el nivel de automatización que necesitas. Kubernetes ofrece funciones avanzadas como el escalado automático, la autorreparación, el descubrimiento de servicios y los despliegues progresivos.
Esas funciones son muy útiles en entornos de producción a gran escala, pero también aumentan la complejidad de la configuración, el mantenimiento y la gestión.
Docker Swarm y HashiCorp Nomad ofrecen alternativas más sencillas. Docker Swarm se integra estrechamente con Docker y requiere gestionar menos componentes que Kubernetes.
Nomad admite tanto cargas de trabajo en contenedores como cargas de trabajo sin contenedores y se integra bien con herramientas como Consul y Vault.
Ambas plataformas son más fáciles de gestionar cuando no se necesitan funciones avanzadas de orquestación.
Ten en cuenta el respaldo de la comunidad y la madurez del ecosistema antes de tomar una decisión definitiva. Kubernetes cuenta con el ecosistema más amplio, ofrece compatibilidad con más herramientas y dispone de la documentación más completa.
Las plataformas más pequeñas pueden ser más fáciles de gestionar, pero ofrecen menos integraciones con servicios de terceros y menos recursos de formación.
La plataforma de orquestación es solo una parte de la estrategia de despliegue. Contar con una infraestructura fiable es igual de importante para ejecutar cargas de trabajo en contenedores.
El Hosting VPS con Docker de Hostinger ofrece recursos dedicados de CPU, RAM y almacenamiento, además de un Administrador de Docker integrado, backups automáticos y herramientas de administración de servidores asistidas por IA que simplifican el despliegue y la gestión de contenedores.

All of the tutorial content on this website is subject to Hostinger's rigorous editorial standards and values.
Comentarios
0 responses