¿Por qué no puedo usar Docker CMD varias veces para ejecutar varios servicios?

96

He creado una imagen base de Dockerfile llamada centos + ssh. En el Dockerfile de centos + ssh, uso CMD para ejecutar el servicio ssh.

Luego, quiero crear una imagen para ejecutar otro servicio llamado rabbitmq, el Dockerfile:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD /opt/mq/sbin/rabbitmq-server start

Para iniciar el contenedor rabbitmq, ejecute :

docker run -d -p 222:22 -p 4149:4149 rabbitmq

pero el servicio ssh no funciona, parece que el CMD de Dockerfile de rabbitmq anula el CMD de centos.

  1. ¿Cómo funciona CMD dentro de la imagen de la ventana acoplable?
  2. Si quiero ejecutar varios servicios, ¿cómo? ¿Usando supervisor?
Edwardsbean
fuente

Respuestas:

62

Aunque CMD está escrito en el Dockerfile, realmente es información de tiempo de ejecución. Al igual que EXPOSE, pero al contrario de, por ejemplo, RUN y ADD. Con esto, quiero decir que puede anularlo más tarde, en un Dockerfile extendido, o simplemente en su comando de ejecución, que es lo que está experimentando. En todo momento, solo puede haber un CMD.

Si desea ejecutar varios servicios, de hecho usaría supervisor. Puede crear un archivo de configuración de supervisor para cada servicio, AGREGARlo en un directorio y ejecutar el supervisor con supervisord -c /etc/supervisorpara apuntar a un archivo de configuración de supervisor que carga todos sus servicios y se ve como

[supervisord]
nodaemon=true

[include]
files = /etc/supervisor/conf.d/*.conf

Si desea obtener más detalles, escribí un blog sobre este tema aquí: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image- herencia/

qkrijger
fuente
Gracias, supervisor es una buena idea, pero me pregunto cómo funciona CMD dentro de la imagen de la
ventana
2
Ha hecho dos preguntas, 2. sobre la ejecución de varios servicios. Al preguntarse cómo funciona CMD, explique lo que desea saber específicamente. Ya mencioné que es información de tiempo de ejecución y que se sobrescribe con cualquier CMD nuevo.
qkrijger
118

Tiene razón, el segundo Dockerfile sobrescribirá el CMDcomando del primero. Docker siempre ejecutará un solo comando, no más. Entonces, al final de su Dockerfile, puede especificar uno comando para ejecutar. No mas.

Pero puede ejecutar ambos comandos en una línea:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD service sshd start && /opt/mq/sbin/rabbitmq-server start

Lo que también puede hacer para hacer que su Dockerfile sea un poco más limpio, puede poner sus comandos CMD en un archivo adicional:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD sh /home/centos/all_your_commands.sh

Y un archivo como este:

service sshd start &
/opt/mq/sbin/rabbitmq-server start
Thomas Uhrig
fuente
1
gracias, creo que usar supervisor es mejor. pero ¿por qué Docker solo ejecuta una CMD? ¿Qué sucede adentro?
edwardsbean
1
No sé qué está pasando adentro. Pero creo que está diseñado así. Cuando tiene una imagen y ejecuta un comando en ella (por ejemplo, con CMD), inicia un contenedor. El contenedor se ejecuta mientras se ejecuta el comando. Y tan pronto como finaliza el comando, el contenedor también se detiene. Entonces, cada contenedor representa un solo comando (en ejecución).
Thomas Uhrig
Creo que tal vez debido a lcx o el límite de algo
edwardsbean
2
@ Tyguy7 .. porque ................?
StartupGuy
1
&&La técnica funcionará solo con servicios no interactivos (que pueden comenzar en segundo plano); de lo contrario, solo se ejecutará el primero.
noraj
26

Si bien respeto la respuesta de qkrijger explicando cómo puede solucionar este problema, creo que podemos aprender mucho más sobre lo que está sucediendo aquí ...

Para responder realmente a su pregunta de " por qué " ... creo que sería útil para usted comprender cómo funciona el docker stopcomando y que todos los procesos deben cerrarse limpiamente para evitar problemas cuando intente reiniciarlos (corrupción de archivos, etc.).

Problema: ¿Qué pasa si Docker hizo SSH inicio de ella de mando y comenzó RabbitMQ de su archivo estibador? " El comando de parada de la ventana acoplable intenta detener un contenedor en ejecución primero enviando una señal SIGTERM al proceso raíz (PID 1) en el contenedor " . ¿Qué proceso está siguiendo la ventana acoplable como PID 1 que obtendrá el SIGTERM? ¿Será SSH o Rabbit?"De acuerdo con el modelo de proceso Unix, el proceso init - PID 1 - hereda todos los procesos hijo huérfanos y debe cosecharlos. La mayoría de los contenedores Docker no tienen un proceso init que lo haga correctamente y, como resultado, sus contenedores se llenan con procesos zombies a lo largo del tiempo ".

Respuesta: Docker simplemente detiene última CMD como uno que conseguirá en marcha como el proceso de raíz con el PID 1 y obtener el SIGTERM dedocker stop .

Solución sugerida: debe usar (o crear) una imagen base creada específicamente para ejecutar más de un servicio, como phusion / baseimage

Debe ser importante tener en cuenta que tini existe exactamente por esta razón, y a partir de Docker 1.13 y versiones posteriores, tini es oficialmente parte de Docker, lo que nos dice que ejecutar más de un proceso en Docker ES VÁLIDO ... así que incluso si alguien afirma Ser más hábil con respecto a Docker, e insiste en que es absurdo pensar en hacer esto, sabe que no lo es. Hay situaciones perfectamente válidas para hacerlo.

Bueno saber:

StartupGuy
fuente
3

La respuesta oficial de Docker para ejecutar múltiples servicios en un contenedor .

Explica cómo puede hacerlo con un sistema de inicio (systemd, sysvinit, upstart), un script ( CMD ./my_wrapper_script.sh) o un supervisor como supervisord.

La &&solución alternativa puede funcionar solo para los servicios que se inician en segundo plano (demonios) o que se ejecutarán rápidamente sin interacción y liberarán el mensaje. Haciendo esto con un servicio interactivo (que mantiene el mensaje) y solo se iniciará el primer servicio.

Noraj
fuente
0

Para abordar por qué CMD está diseñado para ejecutar solo un servicio por contenedor, vamos a darnos cuenta de lo que sucedería si los servidores secundarios que se ejecutan en el mismo contenedor no son triviales / auxiliares sino "principales" (por ejemplo, almacenamiento incluido con la aplicación frontend). Para empezar, desglosaría varias características importantes de contenedorización, como el escalado horizontal (auto) y la reprogramación entre nodos, que asumen que solo hay una aplicación (fuente de carga de CPU) por contenedor. Luego está el problema de las vulnerabilidades: más servidores expuestos en un contenedor significan parches más frecuentes de CVE ...

Así que admitamos que es un 'empujón' de los diseñadores de Docker (y Kubernetes / Openshift) hacia las buenas prácticas y no deberíamos reinventar las soluciones alternativas (SSH no es necesario, hemos docker exec / kubectl exec / oc rshdiseñado para reemplazarlo).

  • Más información

/devops/447/why-it-is-recommended-to-run-only-one-process-in-a-container

mirekphd
fuente