MaxC MaxC - 1 month ago 71
Node.js Question

How to start docker container after succesfull wait-for-it script

I'm using a wait-for-it script to check if the database is up before I'm launching my other app.

#!/bin/bash

set -e

host="$1"
shift
cmd="$@"

until psql -h "$host" -U "postgres" -c '\l'; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done

>&2 echo "Postgres is up - executing command"
exec $cmd


I found this script here.
Now my app-container stops running with
MySQL is up - executing command
.
So the script was successful (db is running) but it's not clear for me how to execute the real CMD (after the script) which is in my dockerfile of my app.

This is the end of my dockerfile:

COPY docker-entrypoint.sh /entrypoint.sh
COPY ./wait-for-it.sh wait-for-it.sh
ENTRYPOINT ["/entrypoint.sh"]

EXPOSE 2368
CMD ["npm", "start"]

Answer

Let's clear up a couple of things first. When you use both ENTRYPOINT and CMD in a Dockerfile, the CMD value is passed to the ENTRYPOINT as a parameter. So what you currently have in the file translates to

/entrypoint.sh npm start

This is executed when you start the container. Without knowing what's happening in entrypoint.sh, it's hard to tell what impact this has.

Docker

You could make the following changes, please give this a try:

  • Remove the ENTRYPOINT from the Dockerfile.
  • Change CMD to the following:

    CMD /wait-for-it.sh localhost && /entrypoint.sh npm start
    

When doing that, please adjust the following:

  • The path for wait-for-it.sh - please adjust to wherever you're copying the script file in the Dockerfile. I suggest you copy it to the same folder as entrypoint.sh.
  • The localhost argument for the wait-for-it.sh script file, please replace with your database host.

What the above does, is run the wait-for-it.sh script and then, once the database is up, it runs the previous command that you had in ENTRYPOINT and CMD. It should be comparable to what you currently have.

As an alternative, you could also call the wait-for-it.sh script from your entrypoint.sh script and only run the additional steps (npm start once the wait script has succeeded). Up to you...

Docker-Compose

If you are using Docker-Compose for starting up your containers, you can overwrite the command that is executed when the container starts using the command attribute in your docker-compose.yaml file, e.g.

command: >
  bash -c "

  /wait-for-it.sh localhost 
  && /entrypoint.sh npm start
  "

Please note the use of

  • bash -c for starting multiple commands using your shell of choice (Bash in this case)
  • the quotes, you'll need them for having multiple lines.

Using this method, you can basically chain multiple commands to run after each other, combining them using the && operator.

Wait-for-it Script

BTW: I use this wait-for-it script for a similar purpose with good results in the same manner as described above. It's slightly more robust than you version of the wait script, and supports pretty much any host/port combination. I use it to wait for MySQL - your question is not clear whether it's about MySQL or PostgreSQL.

Comments