Convertir un contenedor en un pequeño ejecutable reutilizable es una de las estrategias más prácticas de Docker. En lugar de instalar binarios nativamente en tu máquina, puedes construir una imagen que funcione como herramienta de línea de comandos, acepte parámetros y se comporte de forma predecible en cualquier sistema que soporte Docker. La clave está en entender la diferencia entre entry point y CMD, y en combinarlos correctamente.
¿Cómo funciona un contenedor que ejecuta una tarea específica?
El punto de partida es un Dockerfile sencillo basado en Ubuntu que ejecuta el comando ping [00:26]. Este binario envía paquetes a un destino y espera respuesta. En el ejemplo, se configura así:
dockerfile
FROM ubuntu
CMD ["ping", "-c", "3", "localhost"]
- La flag
-c significa count: indica cuántas veces se realizará el ping.
- Al correr dentro del contenedor, localhost no es tu máquina, sino el propio contenedor [00:44].
- El proceso que corre dentro del contenedor no sabe que está en un contenedor; piensa que el contenedor es la máquina misma.
Para construir y ejecutar, basta con docker build -t ping . y luego docker run --name pinger ping [01:02].
¿Por qué no basta con CMD para parametrizar un contenedor?
El problema aparece cuando queremos que el contenedor acepte destinos diferentes. Si intentamos pasar un parámetro como hostname al final de docker run, Docker reemplaza el CMD completo [02:05]. No agrega el parámetro al comando existente, sino que lo sustituye por entero.
Por ejemplo, al ejecutar docker run --name pinger ping hostname, el contenedor no hace ping a nada. Corre el comando hostname, que devuelve el ID del contenedor, porque por defecto el hostname de un contenedor es su propio ID [01:52].
Esto significa que un contenedor con solo CMD no sirve como binario reutilizable: siempre ejecuta exactamente lo mismo, o se reemplaza todo.
¿Qué es el entry point y cómo resuelve este problema?
La instrucción entry point define el comando base que siempre se ejecutará en el contenedor [02:44]. Lo que se defina en CMD se convierte en parámetro del entry point. Si el usuario pasa argumentos en docker run, estos reemplazan solo el CMD, no el entry point.
El Dockerfile modificado queda así:
dockerfile
FROM ubuntu
ENTRYPOINT ["ping", "-c", "3"]
CMD ["localhost"]
- Entry point (
ping -c 3): se ejecuta siempre.
- CMD (
localhost): valor por defecto que se puede pisar desde la línea de comandos.
¿Cómo se usa en la práctica?
Sin parámetros, el contenedor hace ping a localhost como antes [03:32]:
bash
docker run --name pinger ping
Pero si le pasamos un destino diferente [03:44]:
bash
docker run --name pinger ping google.com
El contenedor pinguea a google.com en lugar de localhost. Al inspeccionar con docker ps -l, el comando visible es la combinación de entry point y CMD: /bin/ping -c 3 google.com [04:10]. No se rebildea la imagen; simplemente se parametriza.
¿Qué precauciones hay que tener con el formato exec y shell?
Un detalle crítico es usar siempre el formato exec (con corchetes y comillas) tanto en entry point como en CMD [04:44]. Docker soporta dos formatos:
- Formato exec:
["ping", "-c", "3"] — ejecuta el binario directamente.
- Formato shell:
ping -c 3 — envuelve el comando en /bin/sh -c, lo que trae complicaciones con señales y comportamiento inesperado.
Las reglas fundamentales son:
- Ambas instrucciones deben usar el mismo formato.
- Nunca mezclar formato shell en entry point con formato exec en CMD, ni viceversa.
- Si se combinan incorrectamente, el contenedor no funcionará como se espera.
Esta técnica permite construir contenedores binarios autocontenidos que corren tareas específicas de forma paramétrica, sin instalar nada nativamente. Es una forma limpia de distribuir herramientas que funcionan en cualquier entorno con Docker.
¿Has creado tus propios contenedores como binarios reutilizables? Comparte tu experiencia y qué herramientas has empaquetado de esta forma.