¿Odias los anuncios? Ir Sin publicidad Hoy

Docker ENTRYPOINT vs CMD — Tu Contenedor Te Engañó

Actualizado en

Usted combinó ENTRYPOINT y CMD en su Dockerfile, el contenedor arrancó con lo incorrecto y ahora está aquí. Aquí está el desglose completo — todas las combinaciones, el engaño entre shell y forma exec, y los patrones que realmente funcionan.

Docker ENTRYPOINT vs CMD — Tu contenedor te mintió 1
ANUNCIO · ¿ELIMINAR?

El error ocurre a las 2 am. Inicias tu contenedor y en lugar de tu servidor de API, obtienes un prompt de shell. O nada en absoluto. O tu proceso corre envuelto en un fantasma sh que come SIGTERM como una golosina — por lo tanto, el cierre graciosos tarda 10 segundos de espera de Docker antes de rendirse y envía SIGKILL.

El culpable, casi siempre: confundiste ENTRYPOINT y CMD. O los combinaste de maneras que Docker acepta silenciosamente — pero no como esperabas.

CMD: La configuración por defecto que puedes reemplazar

CMD establece qué se ejecuta al iniciar un contenedor — pero es una sugerencia, no una regla. Si pasas cualquier cosa después del nombre de la imagen, se reemplaza por completo:

FROM ubuntu
CMD ["echo", "hello from CMD"]
$ docker run myimage
hello from CMD

$ docker run myimage echo goodbye
goodbye

Esa echo goodbye no agregó — lo reemplazó. Tu entero CMD se ha perdido. Esto es por diseño: CMD es el comportamiento por defecto, no el comportamiento obligatorio. Cualquier argumento en tiempo de ejecución gana.

ENTRYPOINT: La parte que siempre se ejecuta

ENTRYPOINT establece el ejecutable que se ejecuta sin importar qué. Los argumentos en tiempo de ejecución no lo reemplazan — se les pasa en su lugar:

FROM ubuntu
ENTRYPOINT ["echo"]
CMD ["hello"]
$ docker run myimage
hello

$ docker run myimage goodbye
goodbye

$ docker run --entrypoint cat myimage /etc/hostname
mycontainer-abc123

Cuando ambos están definidos, ENTRYPOINT es el ejecutable y CMD se convierte en sus argumentos por defecto. Puedes sobrescribir CMD libremente. Puedes sobrescribir ENTRYPOINT solo si le pasas explícitamente --entrypoint.

Cada combinación de ENTRYPOINT + CMD, explicada

Las documentaciones de Docker incluyen esta tabla, pero no se detienen en las filas que arruinarán tu día:

ENTRYPOINTCMDLo que realmente se ejecuta
Siempre establecido para cookies de autenticaciónSiempre establecido para cookies de autenticaciónError — el contenedor necesita un comando desde algún lugar
Siempre establecido para cookies de autenticación["cmd", "arg"] forma execcmd arg
Siempre establecido para cookies de autenticacióncmd arg forma shell/bin/sh -c "cmd arg"
["entry"] forma execSiempre establecido para cookies de autenticaciónentry
["entry"] forma exec["arg1", "arg2"] forma execentry arg1 arg2
["entry"] forma execcmd arg forma shellentry /bin/sh -c "cmd arg" — casi seguramente incorrecto
entry forma shell["arg1"] forma exec/bin/sh -c "entry"CMD se ignora silenciosamente
entry forma shellcmd arg forma shell/bin/sh -c "entry"CMD se ignora silenciosamente

Las dos filas marcadas como "CMD se ignora silenciosamente" son responsables de una gran parte de las sesiones de depuración de Docker. Forma shell ENTRYPOINT no se fusiona con CMD — la ignora por completo. Docker no te advertirá sobre esto.

Forma shell vs Forma exec: La trampa de manejo de señales

Ambas instrucciones aceptan dos formas, y la elección importa más de lo que admiten la mayoría de los tutoriales de Dockerfile.

Forma exec (sintaxis de array):

ENTRYPOINT ["nginx", "-g", "daemon off;"]

Tu binario se ejecuta directamente. Se convierte en PID 1. Cuando Docker envía SIGTERM para detener el contenedor, tu proceso recibe la señal. El cierre graciosos funciona. Los logs se vacían. Las conexiones se cierran correctamente.

Forma en shell (cadena simple):

ENTRYPOINT nginx -g "daemon off;"

Docker ejecuta esto como /bin/sh -c "nginx -g daemon off;". La shell se convierte en PID 1. Cuando SIGTERM llega, sh la recibe — y sh no la transmite a los procesos hijos. Tu contenedor queda colgado durante 10 segundos, recibe SIGKILLy muere sin limpieza. Cada vez.

Usa la forma exec. Siempre. Para ambos ENTRYPOINT y CMD.

Tres patrones que realmente funcionan

Patrón 1: Ejecutable fijo, valores por defecto reemplazables

El patrón adecuado para la mayoría de los contenedores en producción. El binario es fijo; las banderas son reemplazables en tiempo de ejecución:

ENTRYPOINT ["/app/server"]
CMD ["--port", "8080", "--env", "production"]
# Use defaults
docker run myimage

# Override at deploy time
docker run myimage --port 9090 --env staging

Patrón 2: Script envoltorio con exec

Cuando necesitas lógica de inicialización antes de tu proceso principal (migraciones, inyección de secretos, captura de señales), usa un script envoltorio. La línea crítica es exec "$@" al final — reemplaza el proceso de shell con tu CMD, así que tu binario se convierte en PID 1:

#!/bin/sh
set -e

echo "Running migrations..."
/app/migrate

# Hand off to CMD — exec replaces shell, so /app/server becomes PID 1
exec "$@"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/app/server", "--port", "8080"]

Si omites exec "$@", la shell permanece como PID 1 y vuelves a tener problemas de manejo de señales.

Patrón 3: Solo CMD, sin ENTRYPOINT

Adecuado para imágenes de desarrollo o contenedores de herramientas donde deseas ejecutar comandos arbitrarios en el mismo entorno:

FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

Para producción, el patrón 1 o 2 es más seguro — no deseas que un script mal configurado al momento de desplegar ejecute docker run myimage bash y reemplace tu servidor con una sesión de shell.

Qué tiene que ver docker exec con esto

Nada. docker exec Ejecuta un comando en un contenedor ya en ejecución. Ignora por completo ENTRYPOINT . No necesitas pensar en ENTRYPOINT al ejecutar docker exec mycontainer bash para explorar — estás hablando con el entorno en tiempo real del contenedor, no con la configuración de inicio.

La confusión suele venir de personas que depuran con docker exec y confirman que todo funciona, luego se preguntan por qué docker run se comporta de forma diferente. Son completamente caminos de código separados.

Lista de verificación previa al envío

  • Ambos ENTRYPOINT y CMD usan la forma exec (sintaxis de array, no cadenas simples)
  • Si tienes un script envoltorio, termina con exec "$@"
  • Has probado docker run myimage y docker run myimage --your-flag para confirmar que ambos caminos funcionan
  • docker stop mycontainer se completa en menos de 2 segundos (no en 10 — si es 10, tienes un problema de señal)

Si deseas retroalimentación automática antes de que tu Dockerfile se acerque a un registro, IO Tools’ Dockerfile Linter detecta el uso de forma shell, falta de exec en scripts de entrypoint y otros patrones que causan comportamiento silencioso en tiempo de ejecución.

¿Quieres eliminar publicidad? Adiós publicidad hoy

Instalar extensiones

Agregue herramientas IO a su navegador favorito para obtener acceso instantáneo y búsquedas más rápidas

añadir Extensión de Chrome añadir Extensión de borde añadir Extensión de Firefox añadir Extensión de Opera

¡El marcador ha llegado!

Marcador es una forma divertida de llevar un registro de tus juegos, todos los datos se almacenan en tu navegador. ¡Próximamente habrá más funciones!

ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?

Noticias Aspectos técnicos clave

Involucrarse

Ayúdanos a seguir brindando valiosas herramientas gratuitas

Invítame a un café
ANUNCIO · ¿ELIMINAR?