I want to run a shell script that will import Amazon RDS certificates when the container runs and then start my Java application.
I have the following ENTRYPOINT:
ENTRYPOINT ./import-amazon-rds-certs.sh && java -jar /app.jar
The problem is that ENTRYPOINT
command does not receive OS signals - as explained https://docs.docker.com/reference/build-checks/json-args-recommended/
I wonder how to run this script to make my Java application receive OS signals.
You can write a script that does the first-time setup, and then uses the special shell exec
command to replace the shell script with the main container process. Then your Java application will be pid 1 inside the container and it will directly receive docker stop
and similar signals.
I generally recommend splitting this into two parts, "do the setup" and "the main container command". If the "setup" part is run as the image's ENTRYPOINT
, then it receives the CMD
as parameters (possibly as overridden at container start time). So a typical script that does the setup could just be
#!/bin/sh
# run the setup script
if ! ./import-amazon-rds-certs.sh; then
echo 'failed to import certificates' >&2
exit 1
fi
# switch to the main container command
exec "$@"
In your Dockerfile, you need to split the setup script and the main command into two separate parts, like
COPY entrypoint.sh ./ # should be checked into source control as executable
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["java", "-jar", "/app/app.jar"]
There is one more subtlety here. ENTRYPOINT
and CMD
(and also RUN
) have two syntaxes. If you just write out a command string, Docker automatically wraps it in /bin/sh -c
. This has a couple of undesirable side effects. For your case, the shell wrapper receives the signals and not your main command. For ENTRYPOINT
specifically, sh -c
will also "swallow" the command-line arguments, so you can't actually run the CMD
. I've made both ENTRYPOINT
and CMD
be "exec form" JSON arrays, which avoids introducing the shell wrapper.
There is an occasional pattern of trying to make the CMD
list just be arguments to the application. I tend to avoid this pattern (if you docker run --rm -it ... sh
your image with the entrypoint wrapper above, for example, you can verify that the RDS credentials have appeared). If you're trying to use this pattern, the shell construct "$@"
expands to all of the current positional arguments, and Docker passes the CMD
that way.
In that case the entrypoint wrapper script could end with
exec java -jar /app/app.jar "$@"
and you could
docker run ... your-image --options-to-java-app