Según la documentación de Docker : solo puede haber una instrucción CMD en un Dockerfile. Si incluye más de un CMD, solo tendrá efecto el último CMD.
Deseo ejecutar un script bash simple (que procesa la variable de entorno de la ventana acoplable) antes del comando CMD (que es init en mi caso).
¿Hay alguna manera de hacer esto?
Cree un punto de entrada personalizado que haga lo que desea, y luego ejecute su CMD al final.
NOTA : si su imagen ya define un punto de entrada personalizado, es posible que deba ampliarlo en lugar de reemplazarlo, o puede cambiar el comportamiento que necesita.
punto de entrada.sh :
#!/bin/sh ## Do whatever you need with env vars here ... # Hand off to the CMD exec "$@"archivo acoplable :
COPY entrypoint.sh /entrypoint.sh RUN chmod 755 /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] Docker ejecutará su punto de entrada, utilizando CMD como argumentos. Si su CMD es init , entonces:
/entrypoint.sh init El exec al final de la secuencia de comandos del punto de entrada se encarga de pasar a CMD cuando el punto de entrada ha terminado con lo que tenía que hacer.
El uso de ENTRYPOINT y CMD con frecuencia confunde a las personas nuevas en Docker. En los comentarios, expresaste confusión al respecto. Así es como funciona y por qué.
El PUNTO DE ENTRADA es lo inicial que se ejecuta dentro del contenedor. Toma el CMD como una lista de argumentos. Por lo tanto, en este ejemplo, lo que se ejecuta en el contenedor es esta lista de argumentos:
# ENTRYPOINT = /entrypoint.sh # CMD = init ["/entrypoint.sh", "init"] # or shown in a simpler form: /entrypoint.sh init No se requiere que una imagen tenga un PUNTO DE ENTRADA. Si no define uno, Docker tiene un valor predeterminado: /bin/sh -c .
Entonces, con su situación original, sin ENTRYPOINT, y usando un CMD de init , Docker habría ejecutado esto:
/bin/sh -c 'init' ^--------^ ^--^ | \------- CMD \--------------- ENTRYPOINT Al principio, Docker solo ofrecía CMD y /bin/sh -c estaba codificado como el PUNTO DE ENTRADA (no se podía cambiar). En algún momento del camino, las personas tuvieron casos de uso en los que tenían que hacer más cosas personalizadas, y Docker expuso ENTRYPOINT para que pudieras cambiarlo a lo que quisieras.
En el ejemplo que muestro arriba, el PUNTO DE ENTRADA se reemplaza con un script personalizado. (Aunque en última instancia todavía lo ejecuta sh , porque comienza con #!/bin/sh ).
Ese PUNTO DE ENTRADA toma el CMD como argumento. Al final del script entrypoint.sh se encuentra exec "$@" . Dado que $@ se expande a la lista de argumentos dados al script, esto se convierte en
exec "init" Y, por lo tanto, cuando finaliza el script, desaparece y se reemplaza por init como PID 1. (Eso es lo que hace exec : reemplaza el proceso actual con un comando diferente).
En los comentarios, preguntó sobre cómo agregar CMD en Dockerfile. Si tu puedes hacerlo.
archivo acoplable :
CMD ["init"] O si hay más en su comando, por ejemplo, argumentos como init -a -b , se verían así:
CMD ["init", "-a", "-b"]La respuesta de Dan fue correcta, pero la encontré bastante confusa de implementar. Para aquellos en la misma situación, aquí hay ejemplos de código de cómo implementé su explicación del uso de ENTRYPOINT en lugar de CMD.
Aquí están las últimas líneas en mi Dockerfile:
#change directory where the mergeandlaunch script is located. WORKDIR /home/connextcms ENTRYPOINT ["./mergeandlaunch", "node", "keystone.js"]Estos son los contenidos del script de shell bash mergeandlaunch:
#!/bin/bash #This script should be edited to execute any merge scripts needed to #merge plugins and theme files before starting ConnextCMS/KeystoneJS. echo Running mergeandlaunch script #Execute merge scripts. Put in path to each merge script you want to run here. cd ~/theme/rtb4/ ./merge-plugin #Launch KeystoneJS and ConnextCMS cd ~/myCMS exec "$@"Así es como se ejecuta el código:
mergeandlaunchexec .Gracias a Dan por su respuesta.
Aunque descubrí que tenía que hacer algo como esto dentro del Dockerfile:
WORKDIR / COPY startup.sh / RUN chmod 755 /startup.sh ENTRYPOINT sh /startup.sh /usr/sbin/initNOTA: Nombré el script startup.sh en lugar de entrypoint.sh
La clave aquí era que necesitaba proporcionar 'sh'; de lo contrario, seguía recibiendo errores de "no such file..." que salían de 'docker logs -f container_name'.