I am trying to create a script that would restart itself, a micro service (in my case its node-red
).
Here is my docker compose file:
docker-compose.yml
version: '2.1'
services:
wifi-connect:
build: ./wifi-connect
restart: always
network_mode: host
privileged: true
google-iot:
build: ./google-iot
volumes:
- 'app-data:/data'
restart: always
network_mode: host
depends_on:
- "wifi-connect"
ports:
- "8883:8883"
node-red:
build: ./node-red/node-red
volumes:
- 'app-data:/data'
restart: always
privileged: true
network_mode: host
depends_on:
- "google-iot"
volumes:
app-data:
I am using wait-for-it.sh in order to check if the previous container.
Here is an extract from the Dockerfile of the node-red microservice.
RUN chmod +x ./wait-for-it/wait-for-it.sh
# server.js will run when container starts up on the device
CMD ["bash", "/usr/src/app/start.sh", "bash", "/usr/src/app/wait-for-it/wait-for-it.sh google-iot:8883 -- echo Google IoT Service is up and running"]
I have seen the inotify
.
Basically all I want is to restart the container node-red
after a file has been created within the app-data
volume which is mounted to the node-red
container as well under /data
folder path, the file path for e.g. would be: /data/myfile.txt
.
Please note that this file gets generated automatically to the google-iot
micro service but node-red
container needs that file and pretty often is the case that the node-red
container starts and /data/myfile.txt
file is not present.
2
Answers
You can fix the issue with the race condition by using the
long-syntax
ofdepends_on
where you can specify a health check. This will guarantee that your file is present when yournode-red
service runs.Then you can define a
health-check
(see docs here) to see if your file is present in the volume. You can add the following to the service description forgoogle-iot
service:Feel free to tune the duration values as needed.
Does this fix your problem?
It sounds like you’re trying to delay one container’s startup until another has produced the file you’re looking for, or exit if it’s not available.
You can write that logic into a shell script fairly straightforwardly. For example:
In your Dockerfile, make this script be the
ENTRYPOINT
. You must use JSON-array syntax in theENTRYPOINT
line. YourCMD
can use any valid syntax. Note that we’re running thewait-for-it
script in the entrypoint wrapper, so you don’t need to include that in theCMD
. (And since the script is executable and begins with a "shebang" line#!/bin/sh
, we do not need to explicitly name an interpreter to run it.)The entrypoint wrapper has two checks, first that the
google-iot
container eventually accepts TCP connections on port 8883 and a second that the file is created. If either of these cases fails the scriptexit 1
before it runs theCMD
. This will cause the container as a whole to exit with that status code (arestart: on-failure
will still restart it).I also might consider whether some other approach to get the file might work, like using
curl
to make an HTTP request to the other container. There are several practical issues with sharing Docker volumes (particularly around ownership, but also if an old copy of the file is still around from a previous run) and sharing files works especially badly in a clustered environment like Kubernetes.