Why a dockerized script have a different behaviour when I docker run or I docker execute it?

Question:

I’m using a python script for send websocket notification,
as suggested here.

The script is _wsdump.py and I have a script script.sh that is:

#!/bin/sh

set -o allexport
. /root/.env set

env

python3 /utils/_wsdump.py "wss://mywebsocketserver:3000/message" -t "message" &

If I try to dockerizing this script with this Dockerfile:

FROM python:3.8-slim-buster

RUN set -xe 
    pip install --upgrade pip wheel && 
    pip3 install websocket-client

ENV TZ="Europe/Rome"

ADD utils/_wsdump.py /utils/_wsdump.py
ADD .env /root/.env
ADD script.sh /

ENTRYPOINT ["./script.sh"]
CMD []

I have a strange behaviour:

  • if I execute docker run -it --entrypoint=/bin/bash mycontainer and after that I call the script.sh everything works fine and I receive the notification.

  • if I run mycontainer with docker run mycontainer I see no errors but the notification doesn’t arrive.

What could be the cause?

Asked By: Kambei

||

Answers:

You install script.sh to the root dir /, but your ENTRYPOINT is defined to run the relative path ./script.sh.

Try changing ENTRYPOINT to reference the absolute path /script.sh instead.

Answered By: kwiknik

Your script doesn’t launch a long-running process; it tries to start something in the background and then completes. Since the script completes, and it’s the container’s ENTRYPOINT, the container exits as well.

The easy fix is to remove the & from the end of the last line of the script to cause the Python process to run in the foreground, and the container will stay alive until the process completes.


There’s a more general pattern of an entrypoint wrapper script that I’d recommend adopting here. If you look at your script, it does two things: (1) set up the environment, then (2) run the actual main container command. I’d suggest using the Docker CMD for that actual command

# end of Dockerfile
ENTRYPOINT ["./script.sh"]
CMD python3 /utils/_wsdump.py "wss://mywebsocketserver:3000/message" -t "message"

You can end the entrypoint script with the magic line exec "$@" to run the CMD as the actual main container process. (Technically, it replaces the current shell script with a command constructed by replaying the command-line arguments; in a Docker context the CMD is passed as arguments to the ENTRYPOINT.)

#!/bin/sh
# script.sh

# set up the environment
. /root/.env set

# run the main container command
exec "$@"

With this use you can debug the container setup by replacing the command part (only), like

docker run --rm your-image env

to print out its environment. The alternate command env will replace the Dockerfile CMD but the ENTRYPOINT will remain in place.

Answered By: David Maze
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.