web-dev-qa-db-fra.com

Utilisez la commande docker run pour transmettre des arguments à CMD dans Dockerfile

Je suis nouveau chez Docker et j'ai du mal à installer le conteneur Docker comme je le souhaite. J'ai une application nodejs qui peut prendre deux paramètres lors du démarrage. Par exemple, je peux utiliser

node server.js 0 dev

ou

node server.js 1 prod

pour basculer entre le mode de production et le mode dev et déterminer si le cluster doit être activé. Maintenant, je veux créer une image de menu fixe avec des arguments pour faire la même chose, la seule chose que je puisse faire jusqu’à présent est d’ajuster le fichier Dockerfile pour avoir une ligne.

CMD [ "node", "server.js", "0", "dev"]

et

docker build -t me/app . pour construire le docker.

Ensuite docker run -p 9000:9000 -d me/app pour exécuter le menu fixe.

Mais si je veux passer en mode prod, je dois changer le CMD Dockerfile pour qu’il soit

CMD [ "node", "server.js", "1", "prod"],

et j'ai besoin de tuer l'ancien qui écoute sur le port 9000 et de reconstruire l'image. J'aimerais avoir quelque chose comme

docker run -p 9000:9000 environment=dev cluster=0 -d me/app

pour créer une image et exécuter la commande nodejs avec les arguments "environment" et "cluster", il est donc inutile de modifier le fichier Docker et de reconstruire le menu fixe. Comment puis-je accomplir cela?

29
Jaaaaaaay

Assurez-vous que votre fichier Docker déclare une variable d’environnement avec ENV :

ENV environment default_env_value
ENV cluster default_cluster_value

Le ENV <key> <value> forme peut être remplacé en ligne .

Ensuite, vous pouvez passer une variable d’environnement avec docker run

docker run -p 9000:9000 -e environment=dev -e cluster=0 -d me/app

Ou vous pouvez définissez-les dans votre fichier de composition :

node:
  environment:
    - environment=dev
    - cluster=0

Votre fichier Dockerfile CMD peut utiliser cette variable d'environnement, mais, comme indiqué dans le numéro 5509 , vous devez le faire dans un fichier sh -c forme:

CMD ["sh", "-c", "node server.js ${cluster} ${environment}"]

L’explication est que le shell est responsable du développement des variables d’environnement et non de Docker. Lorsque vous utilisez la syntaxe JSON , vous demandez explicitement que votre commande ignore le shell et soit exécutée directement.

Même idée avec Builder RUN (s'applique également à CMD):

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, RUN [ "echo", "$HOME" ] ne fera pas de substitution de variable sur $HOME. Si vous souhaitez un traitement Shell, utilisez le formulaire Shell ou exécutez-le directement, par exemple: RUN [ "sh", "-c", "echo $HOME" ].

Lors de l'utilisation du formulaire exec et de l'exécution directe d'un shell, comme c'est le cas pour le formulaire shell, c'est le shell qui développe les variables d'environnement, pas le menu fixe.

45
VonC

Une autre option consiste à utiliser ENTRYPOINT pour spécifier que node est l'exécutable à exécuter et CMD pour fournir les arguments. . Les documents ont un exemple dans exemple EXEC de la forme ENTRYPOINT .

En utilisant cette approche, votre Dockerfile ressemblera à quelque chose comme:

FROM ...

ENTRYPOINT [ "node",  "server.js" ]
CMD [ "0", "dev" ]

L'exécuter dans dev utiliserait la même commande

docker run -p 9000:9000 -d me/app

et l'exécuter dans prod vous passeriez les paramètres à la commande d'exécution

docker run -p 9000:9000 -d me/app 1 prod

Vous voudrez peut-être omettre entièrement CMD et toujours y passer 0 dev ou 1 prod comme arguments de la commande run. Ainsi, vous ne démarrez pas accidentellement un conteneur prod dans dev ou un conteneur dev dans prod.

29
R0MANARMY

Pour ce faire, les conteneurs Docker utilisent généralement des variables d’environnement:

docker run -p 9000:9000 -e NODE_ENV=dev -e CLUSTER=0 -d me/app
4
Paul