25

Do I have to first have to clone the wait-for-it repo and edit the parts of the wait-for-it.sh file?

https://github.com/vishnubob/wait-for-it/blob/master/wait-for-it.sh

I'm trying to make my main file fire after 5 seconds after my customer service connects and run its server. (Or whenever customer service connects server properly).

I am aware that in the Dockerfile, we would need to add these commands to it (copying file into workdir, and run the shell script as an executable.)

...
COPY wait-for-it.sh . 
RUN chmod +x /wait-for-it.sh
...

Here's my current Docker-Compose file

version: '3'
services:
  books:
    build: './books'
    container_name: "horus-books"
    ports:
      - "30043:30043"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

  customers:
    depends_on:
      - books
    build: './customers'
    container_name: "horus-customers"
    ports:
      - "6000:6000"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

  main:
    depends_on: 
      - customers
    build: './main'
    container_name: "horus-main"
    ports:
      - "4555:4555"
    command: ["./wait-for-it.sh", "customers:6000", "--", "node", "main.js"]
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    

Main Service Dockerfile

FROM node:12.14.0
WORKDIR /usr/src/app
COPY package*.json ./
COPY . /usr/src/app
COPY wait-for-it.sh . 
RUN chmod +x /wait-for-it.sh
RUN npm install
EXPOSE 4555
CMD ["node", "main.js"]
TheRoadLessTaken
  • 531
  • 2
  • 7
  • 15
  • Do you want to wait when building the container, or when running the container? – tadman Jul 31 '20 at 20:37
  • @tadman I want to wait when the customer server is running (so when running the container). – TheRoadLessTaken Jul 31 '20 at 20:38
  • 1
    `RUN` commands are executed *once* in the build phase, they do not impact the running container. You need to alter your `CMD` or your `ENTRYPOINT`. – tadman Jul 31 '20 at 20:38

1 Answers1

22

Generally you wouldn't put it in your docker-compose.yml file at all. The script needs to be built into the image, and its standard startup sequence needs to know to run it.

There's a fairly common pattern of using an entrypoint script to do some initial setup, and then use exec "$@" to run the container's command as the main process. This lets you, for example, use the wait-for-it.sh script to wait for the backend to be up, then run whatever the main command happens to be. For example, a docker-entrypoint.sh script might look like:

#!/bin/sh

# Abort on any error (including if wait-for-it fails).
set -e

# Wait for the backend to be up, if we know where it is.
if [ -n "$CUSTOMERS_HOST" ]; then
  /usr/src/app/wait-for-it.sh "$CUSTOMERS_HOST:${CUSTOMERS_PORT:-6000}"
fi

# Run the main container command.
exec "$@"

You need to make sure this script is executable, and make it the image's ENTRYPOINT, but otherwise you can leave the Dockerfile pretty much unchanged.

FROM node:12.14.0
WORKDIR /usr/src/app
COPY package*.json ./
# Do this _before_ copying the entire application in
# to avoid repeating it on rebuild
RUN npm install
# Includes wait-for-it.sh and docker-entrypoint.sh
COPY . ./
RUN chmod +x ./wait-for-it.sh ./docker-entrypoint.sh
EXPOSE 4555
# Add this line
# It _must_ use the JSON-array syntax
ENTRYPOINT ["./docker-entrypoint.sh"]
CMD ["node", "main.js"]

In your docker-compose.yml you need to add the configuration to say where the backend is, but you do not need to override command:.

main:
  depends_on: 
    - customers
  build: './main'
  ports:
    - "4555:4555"
  environment:
    - CUSTOMERS_HOST=customers
David Maze
  • 130,717
  • 29
  • 175
  • 215
  • This is awesome, thank you David! A Few questions: So for CUSTOMERS_PORT, will I have to create it or add it into the docker-compose 'environment' dictionary and equal it to the correct port? Also, you gave an example of the wait-for-it script, but I was wondering how the ./docker-entrypoint.sh script would look like (sorry I've never used shell scripting before!) – TheRoadLessTaken Aug 01 '20 at 14:57
  • 1
    The first script is the entrypoint. The Bourne shell construct `${CUSTOMERS_PORT:-6000}` uses the value of `$CUSTOMERS_PORT` if it's set in the environment, or `6000` if it's not, so you don't need to manually set it. – David Maze Aug 01 '20 at 15:43
  • What do you mean by `# Run the main container command.`? In my case I have a `.jar` I'd like to execute after waiting for another service. It's located under `/app.jar` inside the container. – nonNumericalFloat Dec 10 '21 at 17:46
  • Nevermind, I just did `exec java -jar ./app.jar` inside `docker-entrypoint.sh` and this was totally fine! – nonNumericalFloat Dec 10 '21 at 17:59
  • In your Dockerfile you should set `CMD java -jar ./app.jar`, and that will be "the main container command" when the `exec "$@"` line runs. – David Maze Dec 10 '21 at 18:32