Plusieurs commandes dans la directive CMD Docker

Je ne comprends pas ce qui se passe lorsque j'essaie d'exécuter deux commandes lors de l'exécution via la directive CMD dans `Dockerfile. J'ai supposé que cela devrait fonctionner:

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

Mais ça ne marche pas. Le conteneur n'a pas démarré. Alors je devais le faire comme ça:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Je ne comprends pas. Pourquoi ça? Pourquoi la première ligne n'est pas la bonne voie? Quelqu'un peut-il m'expliquer ces trucs "Format shell CMD vs format JSON, etc". En termes simples.

Juste pour noter - la même chose était avec command: directive en docker-compose.yml, comme prévu.

Je pense que la différence pourrait être due au fait que la deuxième commande effectue un traitement shell alors que la première ne le fait pas. Selon le documentation officielle, il y a les exec et shell forme. Votre première commande est un exec forme. Le exec le formulaire ne développe pas les variables d'environnement alors que le shell la forme le fait. Il est possible qu'en utilisant le exec formulaire la commande échoue en raison de sa dépendance au traitement du shell. Vous pouvez vérifier cela en exécutant docker logs CONTAINERID

Votre deuxième commande, la forme shell, est équivalente à -

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

Extraits de la documentation -

Remarque: Contrairement au formulaire shell, le formulaire exec n'invoque pas de shell de commande. Cela signifie que le traitement normal du shell ne se produit pas. Exemple, CMD [ "echo", "$HOME" ] ne fera pas de substitution de variable sur $HOME. Si vous souhaitez un traitement shell, utilisez le formulaire shell ou exécutez directement un shell, par exemple: CMD [ "sh", "-c", "echo", "$HOME" ].

Ne te complique pas la tâche. Il suffit de créer un fichier bash & quot; start. sh":

#!/bin/bash/usr/bin/command2 param1/usr/bin/command1

dans votre Dockerfile, faites:

ADD start.sh /RUN chmod +x /start.shCMD ["/start.sh"]

La syntaxe json de CMD (et RUN et ENTRYPOINT) passez les arguments au noyau directement en tant qu'appel système exec. Il n'y a pas de séparation de la commande des arguments par des espaces, d'échappement des guillemets, de redirection d'E / S, de substitution de variable, de tuyauterie entre les commandes, d'exécution de plusieurs commandes, etc., dans l'appel système exec. L'appel système ne prend que l'exécutable à exécuter et la liste des arguments à transmettre à cet exécutable, et il l'exécute.

Des personnages comme $ pour développer des variables, ; pour séparer les commandes, (espace) pour séparer les arguments, && et || pour enchaîner les commandes, > pour la redirection de sortie, | pour diriger entre les commandes, etc., sont toutes les fonctionnalités du shell et ont besoin de quelque chose comme /bin/sh ou /bin/bash les interpréter et les mettre en œuvre.


Si vous passez à la syntaxe de chaîne de CMD, docker exécutera votre commande avec un shell:

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

Sinon, votre deuxième syntaxe fait exactement la même chose:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Notez que je ne recommande pas d'exécuter plusieurs commandes de cette façon à l'intérieur d'un conteneur car il n'y a pas de gestion des erreurs si votre première commande échoue, surtout si elle s'exécute en arrière-plan. Vous laissez également un shell en cours d'exécution en tant que pid 1 à l'intérieur du conteneur, ce qui interrompra la gestion du signal, entraînant un délai de 10 secondes et une destruction ingrate de votre conteneur par docker. La gestion du signal peut être atténuée en utilisant le shell exec commande:

CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm

Cependant, la gestion des processus qui échouent silencieusement en arrière-plan nécessite de passer à une sorte de gestionnaire multi-processus comme supervisord, ou de préférence de diviser votre application en plusieurs conteneurs et de les déployer avec quelque chose comme docker-compose.

Je suppose que la première commande échoue car dans le formulaire DOCKER CMD, seul le premier paramètre est exécuté, le reste est introduit dans cette commande.

La deuxième forme fonctionne parce que toutes les commandes séparées par "; " sont introduites dans la commande sh, qui les exécute.

Par exemple, imaginez que vous avez deux commandes Python à exécuter python init_reset.py et python app.py. Ensuite, en utilisant CMD, vous pouvez combiner les deux commandes avec la commande unique

CMD python init_reset.py ; python app.py

Dans Docker compose, cela peut être fait comme l'exemple suivant:

command: ["sh", "-c", "    apt update && apt install -y libldap-common;    cp /ca.crt /usr/local/share/ca-certificates/;    update-ca-certificates;    exec apache2-foreground  "]

Le exec changera le contexte de l'exécutable principal en apache2-forground.

Je ne pense pas que vous devriez mettre une virgule après "commencer"

au lieu d'utiliser

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

essayer

CMD ["/etc/init.d/nullmailer", "start", "/usr/sbin/php5-fpm"]

comme docker utilise "sh-c", la commande ci-dessus sera exécutée comme ci-dessous

/etc/init.d/nullmailer start/etc/init.d/nullmailer /usr/sbin/php5-fpm