I am trying to work with nginx in my express app and I’m following the tutorial here
https://cloud.google.com/community/tutorials/deploy-react-nginx-cloud-run
then at the end I saw this command
CMD sh -c "envsubst '$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
Please what does the above command do?
Most specifically what does "envsubst '$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
do?
Also, how do I run another command after that command above, because it seems I can’t have multiple CMD
statements. I need to run the below after that last command
CMD["node","server.js"]
3
Answers
sh -c
just means you are giving your shell (sh) a commande to execute as parameter.In your case, it would be ‘like’ typing in a terminal on the docker instance
envsubst '$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'
`
This line set the nginx config of your container.
to run node from your docker instance, use
I recommand this quick read on Docker run and cmd command : https://www.geeksforgeeks.org/difference-between-run-vs-cmd-vs-entrypoint-docker-commands/
The purpose of
sh -c
here is already precisely to run multiple commands in one statement. The string after-c
can contain an arbitrary number of commands, separated by command separators. Just add more, as many as you like.CMD sh -c "envsubst '$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;' && node server.js"
At some point, as the command line grows more complex, it makes more senso to put the commands in a file,
COPY
it into the container, and then simply put that file as yourCMD
. You can also create it within yourDockerfile
;As for what these commands do,
generates
/etc/nginx/conf.d/default.conf
from the template file/etc/nginx/conf.d/configfile.temp
by running theenvsubst
command; see its manual page for details. (The backslash before the dollar sign in$PORT
isn’t really part of the command; it’s required because the enclosing string is interpreted by Docker, which has its own variable substitution mechanism, which would replace the value at build time if the dollar sign wasn’t escaped; we don’t want that here.)is a command separator which says to only proceed if the previous command succeeded. In other words,
a && b
runsa
, andb
ifa
didn’t fail. (Success or failure is determined by examining the exit code froma
, which is also momentarily available in the shell variable$?
until you run another external command.)runs
nginx
with the string as the argument to the-g
option. Again, refer to the man page for details.Specific to this setup, three answers:
There’s never a reason to use
CMD sh -c '...'
. @tripleee’s answer describes when you needsh -c
in general. The DockerfileCMD
directive has two forms, though, and if you use its shell form (the command is not a JSON array) then Docker automatically inserts thesh -c
wrapper for you. That is, you can simplify this towith one fewer level of quoting.
The
nginx
image already knows how to do this. As of Nginx 1.19, the Docker Hubnginx
image already knows how to run thisenvsubst
command (search that page for "Using environment variables in nginx configuration"), and the base image already has aCMD
that launches Nginx. So if you put the templated configuration file in the correct location, you don’t need this long-windedCMD
at all.Copying and tweaking the complete Dockerfile from the page you link to:
This setup builds a static React application. It uses a multi-stage build to first compile the application to static files, then copy those into the Nginx image.
If you need to use Nginx to proxy a server-side application, you need to run this in a separate container. You ask about this in a separate question.