Ne comprenant pas ce qui se passe lorsque j'essaie d'exécuter deux commandes au moment 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é. J'ai donc dû le faire comme ceci:
CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]
Je ne comprends pas. Pourquoi donc? Pourquoi la première ligne n'est pas la bonne voie? Quelqu'un peut-il m'expliquer ces trucs "Format CMD Shell vs format JSON, etc". En termes simples.
Juste pour noter - la même chose était avec command:
directive dans docker-compose.yml
, comme prévu.
Je crois que la différence pourrait avoir à voir avec, la deuxième commande fait le traitement Shell, tandis que la première ne le fait pas. Selon la version officielle documentation , il existe les formulaires exec
et Shell
, votre première commande est un formulaire exec et ne développe pas par exemple les variables d'environnement, tandis que la seconde on le fait. Il est donc possible qu'en utilisant le formulaire exec, la commande échoue en raison de sa dépendance au traitement Shell. Vous pouvez vérifier cela en exécutant docker logs CONTAINERID
Votre deuxième commande, le formulaire Shell, équivaut à -
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 commande Shell. Cela signifie que le traitement Shell normal ne se produit pas. Par 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 un Shell directement, par exemple:CMD [ "sh", "-c", "echo", "$HOME" ]
.
Ne vous compliquez pas la tâche. Créez simplement un fichier bash "start.sh":
#!/bin/bash
/usr/bin/command2 param1
/usr/bin/commnad1
dans votre Dockerfile:
ADD start.sh /
RUN chmod +x /start.sh
CMD ["/start.sh"]
La syntaxe json de CMD
(et RUN
et ENTRYPOINT
) transmet les arguments au noyau directement comme un appel système exec. Il n'y a pas de séparation de la commande des arguments par des espaces, échappement des guillemets, IO, substitution de variable, tuyauterie entre les commandes, exécution de plusieurs commandes, etc., dans le syscall de l'exec. Le syscall uniquement prend l'exécutable à exécuter et la liste des arguments à passer à cet exécutable, et il l'exécute.
Des personnages comme $
pour développer les 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 des fonctionnalités du shell et ont besoin de quelque chose comme /bin/sh
ou /bin/bash
pour 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 d'erreur si votre première commande échoue, surtout si elle s'exécute en arrière-plan. Vous laissez également un Shell fonctionner en tant que pid 1 à l'intérieur du conteneur, ce qui interrompra la gestion du signal, ce qui entraînera 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 la commande Shell exec
:
CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm
Cependant, la gestion des processus échouant silencieusement en arrière-plan nécessite que vous passiez à une sorte de gestionnaire multi-processus comme supervisord, ou de préférence divisez votre application en plusieurs conteneurs et déployez-les avec quelque chose comme docker-compose.
Je suppose que la première commande échoue car sous forme DOCKER CMD, seul le premier paramètre est exécuté, le reste est introduit dans cette commande.
Le second formulaire fonctionne car toutes les commandes séparées par ";" sont introduits dans la commande sh, qui les exécute.
Je ne pense pas que vous devriez mettre une virgule après "start"
à la place 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