Suppose we have a Dockerfile with some CMD and we produced and image from it. Now suppose that we write a docker-compose and one of the services is built from that image.
What I want to do is running the same command but concatenating my own new parameters.
As an example, suppose the original CMD is
java -jar app.jar --argumentA=valA
I want the command to be
java -jar app.jar --argumentA=valA --argumentB=valB
Is it possible?
I'm not entirely sure if this is what you would want to accomplish, but...
Dockerfile exposes both ENTRYPOINT and CMD for being able to execute commands. These also can be used in conjunction, but in this case the ENTRYPOINT will be the command what we want to execute and the CMD will represent some default arguments for the ENTRYPOINT (docs).
For example:
FROM openjdk:11
COPY . /target/app.jar
ENTRYPOINT ["java", "-jar", "app.jar", "--argumentA=valA"]
CMD ["--argumentB=valB"]
The --argumentB=valB will be appended to the java -jar app.jar --argumentA=valA, if we run the image like this:
docker build -t app .
docker run app # # the command executed will be java -jar app.jar --argumentA=valA --argumentB=valB
But the CMD part will be overridden if we provide other arguments when we run the docker image:
docker build -t app .
docker run app --argumentA=valC # the command executed will be java -jar app.jar --argumentA=valA --argumentB=valC
Also, we can commit the CMD and have the ENTRYPOINT only, if we don't require some defaults to be appended to the ENTRYPOINT.
Related
I am trying to deploy an app in payara micro based on payara dockerimage and I need to pass one arguement snapshotversion in ENTRYPOINT(basically i want to access the build args in ENTRYFORM) exec form, as exec form of ENTRYPOINT is preferred: my docker file is as follows:
FROM payara/micro:5.193.1
ARG snapshotversion
ENV snapshotvs=$snapshotversion
RUN jar xf payara-micro.jar
COPY /service/war/target/app-emailverification-service-war-${snapshotversion}.war ${DEPLOY_DIR}/
COPY ojdbc6.jar ${PAYARA_HOME}/
COPY --chown=payara domain.xml /opt/payara/MICRO-INF/domain/domain.xml
RUN cd /opt/payara/MICRO-INF/domain && ls -lrt
#ENTRYPOINT ["java", "-jar", "/opt/payara/payara-micro.jar", "--deploy", "/opt/payara/deployments/app-service-war-$snapshotvs.war", "--domainConfig", "/opt/payara/MICRO-INF/domain/domain.xml","--addLibs", "/opt/payara/ojdbc6.jar"]
ENTRYPOINT java -jar /opt/payara/payara-micro.jar --deploy /opt/payara/deployments/app-service-war-$snapshotvs.war --domainConfig /opt/payara/MICRO-INF/domain/domain.xml --addLibs /opt/payara/ojdbc6.jar
The commented ENTRYPOINT does not work. Container logs says invalid deployment. What am i missing here? Also how can I use CMD with this. Can someone post an example.
The commented line doesn't work, because it is an exec form of ENTRYPOINT, which doesn't invoke shell (/bin/sh -c), so variable substitution doesn't happening.
If you want to use an exec form and environment variables you need to specify it directly:
ENTRYPOINT ["sh", "-c", "your command with env variable"]
To your question about how can you use CMD with this, for example like this:
ENTRYPOINT ["sh", "-c"]
CMD ["your command with env variable"]
You mentioned, that you want to use build args in ENTRYPOINT instruction. It's not really possible, because nor ARG nor ENV are expanded in ENTRYPOINT or CMD: https://docs.docker.com/engine/reference/builder/#environment-replacement, https://docs.docker.com/engine/reference/builder/#scope
Also you could take a look at great page with best practices for writing Dockerfile and ENTRYPOINT instructions specifically.
Two suggestions that complement each other:
If you're COPYing a file into the image, you can give it a fixed name inside the image. That avoids this problem.
WORKDIR /opt/payara
COPY service/war/target/app-emailverification-service-war-${snapshotversion}.war deployments/app-service.war
If you have a particularly long or involved command that you're trying to make be the main container process, wrap it in a shell script. You want to make sure to exec the main container process to avoid some trouble around signal handling (resulting in docker stop pausing for 10 seconds and then hard-killing your actual process).
#!/bin/sh
exec java \
-jar /opt/payara/payara-micro.jar \
--deploy /opt/payara/deployments/app-service.war \
--domainConfig /opt/payara/MICRO-INF/domain/domain.xml \
--addLibs /opt/payara/ojdbc6.jar
COPY launch.sh ./
RUN chmod +x launch.sh
CMD ["/opt/payara/launch.sh"]
In this second case, it's a shell script, so you can have ordinary shell variable substitutions.
There is no such file by name entrypoint.sh in my workspace.
But below instruction in docker-compose.yml is referring it:
builder:
build: ../../
dockerfile: docker/dev/Dockerfile
volumes:
- ../../target:/wheelhouse
volumes_from:
- cache
entrypoint: "entrypoint.sh"
command: ["pip", "wheel", "--non-index", "-f /build", "."]
where ../docker/dev/Dockerfile has
# Set defaults for entrypoint and command string
ENTRYPOINT ["test.sh"]
CMD ["python", "manage.py", "test", "--noinput"]
What does entrypoint: "entrypoint.sh" actually do?
entrypoint: "entrypoint.sh" overrides ENTRYPOINT ["test.sh"] from Dockerfile.
From the docs:
Setting entrypoint both overrides any default entrypoint set on the
service’s image with the ENTRYPOINT Dockerfile instruction, and clears
out any default command on the image - meaning that if there’s a CMD
instruction in the Dockerfile, it is ignored.
ENTRYPOINT ["test.sh"] is set in Dockerfile describing docker image
entrypoint: "entrypoint.sh" is set in docker-compose file which describes multicontainer environment while referencing the Dockerfile.
docker-compose build builder will build image and set entrypoint to ENTRYPOINT ["test.sh"] set in Dockerfile.
docker-compose up builder will start container with entrypoint entrypoint.sh pip wheel --no-index '-f /build' . set in docker-compose file
ENTRYPOINT is a command or script that is executed when you run the docker container.
If you specify entrypoint in the docker-compose.yaml, it overrides ENTRYPOINT from specified Dockerfile.
CMD is something that is passed as the parameters to the ENTRYPOINT
So if you just run the dev/Dockerfile, it would execute
test.sh python manage.py test --noinput
If you overrided CMD in docker-compose.yaml as you did, it would execute
test.sh pip wheel --non-index -f /build .
But because you also overrided ENTRYPOINT in your docker-compose.yaml, it is going to execute
entrypoint.sh pip wheel --non-index -f /build .
So basically, entrypoint.sh is a script that will run inside your container builder when you execute docker-compose up command.
Also you can check this answer for more info What is the difference between CMD and ENTRYPOINT in a Dockerfile?
Update:
If the base image has entrypoint.sh, it will run that, but if you override with your own entrypoint then the container will run the override entrypoint.
If you to override the default behaviour of base image then you can change, ohterwise you do not need to override it from docker-compose.
What does entrypoint: "entrypoint.sh" actually do?
It totally depend on the script or command inside entrypoint.sh, but few things can be considered.
ENTRYPOINT instruction allows you to configure a container that will
run as an executable. It looks similar to CMD, because it also allows
you to specify a command with parameters. The difference is ENTRYPOINT
command and parameters are not ignored when Docker container runs with
command line parameters. (There is a way to ignore ENTTRYPOINT, but it
is unlikely that you will do it.)
In simple word, entrypoint can be a complex bash script, for example in case of mysql entrypoint which is more then 200 LOC which does the following task.
start MySQL server
wait for MySQL server to up
Create DB
Can perform DB migration or DB initlization
So much complex task is not possible with CMD, as in CMD you can run the bash but it will be more headache to make it work. Also it make Dockerfile simple and put the complex task to entrypoint.
When there is entrypoint, anything that is passed to CMD will be consider as a argument for entrypoint.
In your case, CMD is CMD ["python", "manage.py", "test", "--noinput"] it will be passed as an argument and the best to run this is to use use
# set of command
#start long running process at the end that is passed from CMD
exec "$#"
Finally, the exec shell construct is invoked, so that the final
command given becomes the container's PID 1. $# is a shell variable
that means "all the arguments",
use-a-script-to-initialize-stateful-container-data
cmd-vs-entrypoint
Trying to access the command line args from a dotnet core console application in docker.
This is basically just the default template with default docker compose / dockerfile template.
Tried a few different approaches.
Add args to ENTRYPOINT in dockerfile
Added args to CMD in dockerfile
Added args under build in the docker-compose file
Cant get it to pass it on, how is this usually handled?
Test repo: https://github.com/lasrol/DotnetCoreDockerArgs
CMD is meant as an alternative to ENTRYPOINT, or a way to supply arguments to an entrypoint.
Rather than doing:
ENTRYPOINT ["dotnet", "TestDocker.dll", $arg1, $arg2]
CMD ["arg1", "arg2"]
Which will repeat the arguments,
Try:
ENTRYPOINT ["dotnet", "TestDocker.dll", "arg1", "arg2"]
or if you want to use both, simply use CMD for all the arguments only.
ENTRYPOINT ["dotnet", "TestDocker.dll"]
CMD ["arg1", "arg2"]
https://docs.docker.com/engine/reference/builder/#cmd
I have a Dockerfile which starts with:
FROM puppet/puppetserver
When I look at the source container it is built from another:
FROM puppet/puppetserver-standalone:5.0.0
The second contains a CMD command:
ENTRYPOINT ["dumb-init", "/docker-entrypoint.sh"]
CMD ["foreground" ]
In my own container I end with:
COPY start.sh /
CMD /start.sh
The CMD run but with unexpected results:
puppetserver: '/bin/sh' is not a puppetserver command. See 'puppetserver --help'.
I know that I have bash availible because I'm using RUN commands.sh before CMD in the same Dockerfile.
How do CMD commands stack when inheriting from base images?
Is my CMD not run as a normal bash command and instead run in conjunction with the CMD of the base image?
You need to reset the ENTRYPOINT from the parent image
COPY start.sh /
ENTRYPOINT []
CMD /start.sh
See https://docs.docker.com/engine/reference/builder/#understand-how-cmd-and-entrypoint-interact
CMD should be used as a way of defining default arguments for an ENTRYPOINT command or for executing an ad-hoc command in a container.
and https://docs.docker.com/engine/reference/builder/#cmd
There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the last CMD will take effect.
I tried to run the CMD "java -jar /tmp/migration.jar update_schema atlas " to create the Keyspace in the cassandra. But its not creating any keyspaces in cassandra. But if i run same command in the command line its creating any idea whats the issue?
My dockerfile is as follows
'FROM tomcat:8-jre8
ENV LANG en_US.UTF-8
ENV COMMAND="update"
ENV ARGS="--logLevel=debug"
WORKDIR /usr/local/tomcat/
ADD /migration.jar /tmp
ADD atlas_migration.sh /usr/local/bin/atlas_migration.sh
CMD ["/bin/sh", "/usr/local/bin/atlas_migration.sh"]
CMD ENTRYPOINT ["java","-jar","/tmp/migration.jar","update_schema", "atlas"]
CMD java -jar /tmp/migration.jar update_schema atlas
ENV CATALINA_OPTS "-Xmx256m -Xms192m"
EXPOSE 8085
CMD ./bin/catalina.sh start && tail -f ./logs/catalina.out'
CMD is for specifying the command the container should run when it starts. If you want to run a command during the build, so the state after execution is persisted in the image, you need to use RUN.
COPY is also preferable to ADD, so the relevant instructions should be:
COPY /migration.jar /tmp
COPY atlas_migration.sh /usr/local/bin/atlas_migration.sh
RUN /usr/local/bin/atlas_migration.sh
RUN ["java","-jar","/tmp/migration.jar","update_schema", "atlas"]