Search code examples
node.jsdockerunixshgoogle-cloud-run

What does "sh -c" do?


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"]


Solution

  • 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 your CMD. You can also create it within your Dockerfile;

    RUN printf '%s\n' >cmd.sh \
        "envsubst '\$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf &&" \
        "nginx -g 'daemon off;' &&" \
        "node server.js"
    # ...
    CMD ["sh", "cmd.sh"]
    

    As for what these commands do,

    envsubst '\$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf
    

    generates /etc/nginx/conf.d/default.conf from the template file /etc/nginx/conf.d/configfile.temp by running the envsubst 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 runs a, and b if a didn't fail. (Success or failure is determined by examining the exit code from a, which is also momentarily available in the shell variable $? until you run another external command.)

    nginx -g 'daemon off;'
    

    runs nginx with the string as the argument to the -g option. Again, refer to the man page for details.