Synchronizing docker containers with netcat
A user in
/r/docker
asked “How can i wait for container to exit with code 1 before starting another
container using docker-compose”. Ignoring the question of “why?” (a fair
question, but let’s assume a valid use case), one response was “use a shared
volume and write the exit code to a file”. Not a terrible solution, shared
volumes are quite useful. However, I realized this was a great use of the
somewhat-standard netcat
, so whipped up a sample compose file for fun.
Here’s a simple compose file with two containers: second
that starts a netcat
server on port 3000 that will return “OK” on connect, then print the message
(cat
, this is where any logic based on the exit code would go) and run our
desired workload. first
runs our first workload (sleep for five seconds) then
opens a connection to second
, passing the exit code. Note that there’s a few
versions of netcat
out there, but I think this basic usage is the same between
them.
version: '3'
services:
second:
image: alpine
command:
- '/bin/sh'
- '-c'
- 'echo "OK" | nc -l -p 3000 | cat && echo "doing the second thing"'
first:
image: alpine
command:
- '/bin/sh'
- '-c'
- 'echo "doing the first thing" && sleep 5 && echo "$$?" | nc second 3000'
Output:
) docker-compose up
Recreating container_wait_second_1 ... done
Recreating container_wait_first_1 ... done
Attaching to container_wait_second_1, container_wait_first_1
first_1 | doing the first thing
second_1 | 0
first_1 | OK
second_1 | doing the second thing
container_wait_first_1 exited with code 0
container_wait_second_1 exited with code 0
A neat variation on this is to use the -e
argument (in this version of netcat
anyways) to have netcat
run the workload, and send the stdout back to first
. diff:
- - 'echo "OK" | nc -l -p 3000 | cat && echo "doing the second thing"'
+ - 'nc -l -p 3000 -e echo "doing the second thing"'
output:
) docker-compose -f docker-compose.passback.yml up
Recreating container_wait_second_1 ... done
Starting container_wait_first_1 ... done
Attaching to container_wait_first_1, container_wait_second_1
first_1 | doing the first thing
first_1 | doing the second thing
container_wait_first_1 exited with code 0
container_wait_second_1 exited with code 0