skip to Main Content

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


  1. 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

    RUN node server.js
    

    I recommand this quick read on Docker run and cmd command : https://www.geeksforgeeks.org/difference-between-run-vs-cmd-vs-entrypoint-docker-commands/

    Login or Signup to reply.
  2. 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 '%sn' >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.

    Login or Signup to reply.
  3. Specific to this setup, three answers:

    There’s never a reason to use CMD sh -c '...'. @tripleee’s answer describes when you need sh -c in general. The Dockerfile CMD directive has two forms, though, and if you use its shell form (the command is not a JSON array) then Docker automatically inserts the sh -c wrapper for you. That is, you can simplify this to

    CMD envsubst '$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'
    

    with one fewer level of quoting.

    The nginx image already knows how to do this. As of Nginx 1.19, the Docker Hub nginx image already knows how to run this envsubst command (search that page for "Using environment variables in nginx configuration"), and the base image already has a CMD that launches Nginx. So if you put the templated configuration file in the correct location, you don’t need this long-winded CMD at all.

    Copying and tweaking the complete Dockerfile from the page you link to:

    FROM node:14-alpine as react-build
    ...
    FROM nginx:alpine
    COPY nginx.conf /etc/nginx/templates/default.conf.template
    # NOTE: different path    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    COPY --from=react-build /app/build /usr/share/nginx/html
    ENV PORT 8080
    ENV HOST 0.0.0.0
    EXPOSE 8080
    # No CMD in this derived Dockerfile
    

    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.

    FROM node:14-alpine as react-build
    WORKDIR /app
    ...
    RUN yarn build
    
    FROM nginx:alpine
    COPY --from=react-build /app/build /usr/share/nginx/html
    

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search