Issue
I have the next Dockerfile for my Ubuntu container
FROM ubuntu:14.04
# Install.
RUN \
sed -i 's/# \(.*multiverse$\)/\1/g' /etc/apt/sources.list && \
apt-get update && \
apt-get -y upgrade && \
apt-get install -y build-essential && \
apt-get install -y software-properties-common && \
apt-get install -y byobu curl git htop man unzip vim wget jq && \
rm -rf /var/lib/apt/lists/*
# Set environment variables.
ENV HOME /root
# Define working directory.
WORKDIR /root
# Define default command.
ENTRYPOINT ["/bin/bash"]
#First create an Auth token for Sonar server
ENTRYPOINT [ "token=$(curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "name=WindowsTokenFinal" -u admin:pass 10.0.0.2:9000/api/user_tokens/generate | jq -r '.token')"]
#
# #Save session cookies
ENTRYPOINT ["COOKIEJAR="$(mktemp)""]
#
# #Generate crumb of Jenkins
ENTRYPOINT ["CRUMB=$(curl -u "admin:pass" --cookie-jar "$COOKIEJAR" "http://10.0.0.3:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,%22:%22,//crumb)")"]
#
# #Create Credentials on Jenkins Server
ENTRYPOINT ["curl -X POST -u "admin:pass" --cookie "$COOKIEJAR" -H "$CRUMB" 'http://10.0.0.3:8080/credentials/store/system/domain/_/createCredentials' --data-urlencode 'json={"": "0","credentials": {"scope": "GLOBAL","id": "WindowsAutoToken","description": "Automatically generated sonar token from windows","secret": "$Token", "$class": "org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl"}}'"]
The first problem is that it only executes the last ENTRYPOINT, but if I run the first one only, the
ENTRYPOINT [ "token=$(curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "name=WindowsTokenFinal" -u admin:pass 10.0.0.2:9000/api/user_tokens/generate | jq -r '.token')" ]
It doesn´t save the token variable.
If I execute the commands inside the container there is no problem and it works perfectly, but I need to run this commands once the container is up without running them by myself.
Solution
A pattern I've found useful is to use ENTRYPOINT
as a wrapper script that does first-time setup, and then use CMD
to actually say what the main process is. This will let you do whatever you need to do in the entrypoint wrapper script, and then run the main process as a foreground job.
With what you've shown in the Dockerfile, you could package that up into a shell script:
#!/bin/sh
#First create an Auth token for Sonar server
token=$(curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "name=WindowsTokenFinal" -u admin:pass 10.0.0.2:9000/api/user_tokens/generate | jq -r '.token')
#Save session cookies
COOKIEJAR="$(mktemp)"
#Generate crumb of Jenkins
CRUMB=$(curl -u "admin:pass" --cookie-jar "$COOKIEJAR" "http://10.0.0.3:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,%22:%22,//crumb)")
#Create Credentials on Jenkins Server
curl -X POST -u "admin:pass" --cookie "$COOKIEJAR" -H "$CRUMB" 'http://10.0.0.3:8080/credentials/store/system/domain/_/createCredentials' --data-urlencode 'json={"": "0","credentials": {"scope": "GLOBAL","id": "WindowsAutoToken","description": "Automatically generated sonar token from windows","secret": "$Token", "$class": "org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl"}}'
# Launch the main container process
exec "$@"
Then in the Dockerfile, COPY
this script in, set it as the ENTRYPOINT
, and set the CMD
to the single process you want the container to run (probably not an interactive shell).
COPY entrypoint.sh /usr/local/bin
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] # must be JSON-array syntax
CMD ["my_application", "--foreground"]
Remember that a container runs only one process. If you have both ENTRYPOINT
and CMD
directives, the CMD
gets passed as arguments to the ENTRYPOINT
, and if you have multiple ENTRYPOINT
or CMD
, only the last one takes effect and the previous ones are ignored. Also remember that the JSON-array syntax doesn't do any sort of processing or substitution, so things like $(subprocess)
invocations don't work with that syntax; also that the JSON-array syntax can be picky around things like nested quotes and there's no feedback if you get it wrong, Docker just silently falls back to shell-command form.
Answered By - David Maze
Answer Checked By - Terry (JavaFixing Volunteer)