Je ne parviens pas à créer et à utiliser des variables dans un fichier Dockerfile. Je crée une image Docker via un fichier Dockerfile à l'aide de cette commande:
$ docker build --build-arg s=scripts/a.sh -t a .
(Donc, parce que j'utilise --build-arg, $ s sera un argument disponible dans le fichier Dockerfile, et cette partie fonctionne)
Le Dockerfile est comme ça:
ARG s
RUN echo $s
RUN useradd -ms /bin/bash newuser
USER newuser
WORKDIR /home/newuser
ENV fn=$(filename $s) # fails on this line
COPY $s .
ENTRYPOINT ["/bin/bash", "/home/newuser/$fn"]
Le problème que j'ai est que la construction de Docker échoue sur la ligne indiquée ci-dessus.
Error response from daemon: Syntax error - can't find = in "$s)". Must be of the form: name=value
Si je change cette ligne en ceci:
RUN fn=$(filename $s)
Je reçois cette erreur:
Error: Command failed: docker build --build-arg s=scripts/a.sh -t a .
The command '/bin/sh -c fn=$(filename $s)' returned a non-zero code: 127
Quelqu'un sait comment s'y prendre
Utilisez une interpolation de chaîne avec cette variable pour pouvoir référencer la variable dans les arguments ENTRYPOINT comme suit:
ENTRYPOINT ["/ bin/bash", "/ home/newuser/$ var"]
Même si je fais ça:
ARG s
ARG sname
RUN echo $s # works as expected
RUN echo $sname # works as expected
RUN useradd -ms /bin/bash newuser
USER newuser
WORKDIR /home/newuser
COPY $s . # works as expected (I believe)
ENTRYPOINT /bin/bash /home/newuser/$sname # does not work as expected
même si j'utilise la version "non-JSON" de ENTRYPOINT, il ne semble toujours pas capter la valeur de la variable $sname
.
Je voudrais éviter d'utiliser variable dans ENTRYPOINT
du tout. C'est délicat et nécessite une compréhension profonde de ce qui se passe. Et il est facile de le casser par accident. Il suffit de penser à l’un des éléments suivants.
Créez un lien avec le nom connu de votre script de démarrage.
RUN ln -s /home/newuser/$sname /home/newuser/docker_entrypoint.sh
ENTRYPOINT ["/home/newuser/docker_entrypoint.sh"]
ou écrivez un script de point d’entrée autonome qui exécute ce dont vous avez besoin.
Mais si vous voulez savoir comment et pourquoi les solutions de vos questions fonctionnent, continuez à lire.
D'abord quelques définitions.
ENV
- la variable environment est-elle disponible lors de la compilation (docker build
) et de l'exécution (docker run
) ARG
- la variable environment est-elle disponible uniquement pendant la phase de constructionSi vous consultez https://docs.docker.com/engine/reference/builder/#environment-replacement vous voyez la liste des instructions de dockerfile qui prennent directement en charge ces variables d’environnement. C'est pourquoi COPY
"prend la variable" comme vous l'avez dit.
Veuillez noter qu'il n'y a pas de RUN
ni ENTRYPOINT
. Comment ça marche?
Vous devez creuser dans la documentation. Première RUN
( https://docs.docker.com/engine/reference/builder/#run ). Il y a 2 formes. Le premier exécute la commande via le shell et ce dernier a accès aux variables d'environnement de compilation.
# this works because it is called as /bin/sh -c 'echo $sname'
# the /bin/sh replace $sname for you
RUN echo $sname
# this does NOT work. There is no Shell process to do $sname replacement
# for you
RUN ["echo", "$sname"]
La même chose s'applique aux variables ENTRYPOINT
et CMD
, sauf que seules les variables d'exécution sont disponibles au démarrage du conteneur.
# first you need to make some runtime variable from builtime one
ENV sname $sname
# Then you can use it during container runtime
# docker runs `/bin/sh -c '/bin/bash /home/newuser/$sname'` for you
# and this `/bin/sh` proces interprets `$sname`
ENTRYPOINT /bin/bash /home/newuser/$sname
# but this does NOT work. There is no process to interpolate `$sname`
# docker runs what you describe.
ENTRYPOINT ["/bin/bash", "/home/newuser/$sname"]
edit 2017-04-03: mise à jour des liens vers les documentations du docker et légère reformulation pour éviter toute confusion que je ressens à partir d'autres réponses et commentaires.
J'ai demandé à @Villem de répondre, et sa réponse est beaucoup plus définitive, mais ce qui suit fonctionnera (ce n'est tout simplement pas une solution stable). Sa réponse est essentiellement de dire que cette réponse n’est pas un bon moyen de le faire:
ARG s # passed in via --build-arg s=foo
ARG sname # passed in via --build-arg sname=bar
RUN echo $s
RUN echo $sname
ENV sname $sname # this is the key part
RUN useradd -ms /bin/bash newuser
USER newuser
WORKDIR /home/newuser
COPY $s .
ENTRYPOINT /bin/bash /home/newuser/$sname # works, but is not stable!
ne me demandez pas pourquoi la commande COPY récupère la variable déclarée via ARG, mais que la commande ENTRYPOINT ne pas semble capturer la variable déclarée via ARG, mais uniquement la variable déclarée via ENV. Au moins, cela semble être le cas.
Je voulais à la fois la substitution de variable et les arguments qui passent.
Disons que notre Dockerfile a:
ENV VARIABLE=replaced
Et nous voulons exécuter ceci:
docker run <image> arg1 arg2
J'ai évidemment voulu cette sortie:
replaced arg1 arg2
J'ai finalement trouvé celui-ci:
ENTRYPOINT [ "sh", "-c", "echo $VARIABLE $0 $@" ]
Ca marche !!! Mais je me sens tellement sale!
Évidemment, dans la vie réelle, je voulais faire quelque chose de plus utile:
docker run <image> --app.options.additional.second=true --app.options.additional.third=false
ENTRYPOINT [ "sh", "-c", "Java -Xmx$XMX $0 $@", \
"-jar", \
"/my.jar", \
"--app.options.first=true" ]
Pourquoi une réponse si compliquée?
Fiou ...
J'ai ajouté un commentaire à ce problème afin que les développeurs Docker puissent voir ce que nous sommes obligés de faire et qu'ils changent peut-être d'avis pour que ENTRYPOINT [] remplace les variables d'environnement: https://github.com/moby/moby/issues/4783 # issuecomment-442466609