I have a Dockerfile like:
FROM frolvlad/alpine-oraclejdk8:slim
ADD build/libs/zuul*.jar /app.jar
ADD src/main/script/startup.sh /startup.sh
EXPOSE 8080 8999
ENTRYPOINT ["/startup.sh"]
startup.sh looks like:
#!/bin/sh
set -e
if [ $# -eq 0 ]
then
echo "Environment value required"
exit 1
fi
java -jar -Xms400m -Xmx400m -Dlog4j.configurationFile=log4j2-qa2.xml -Djava.security.egd=file:/dev/./urandom -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.rmi.port=8999 app.jar
But when I run it with docker run, I got docker: Error response from daemon: Container command '/startup.sh' not found or does not exist... The shell script has execute permission.
I used the same way to run my other apps and they're all working fine. I wrote the files in Mac and tried to run the container in a Linux machine.
It turns out to be the ^M DOS-style line ending character that caused the issue. But since I'm editing in Mac and I checked several times with vim, I'm pretty sure the starting script in my local machine doesn't have that char. But when opened with vim inside the container, I can see ^M everywhere. So somehow that char gets added to startup.sh when copied into the image, which is weird. That prevents the script from being invoked.
The solution is to add dos2unix filename before the ENTRYPOINT in Dockerfile. But make sure that your base image has that utility.
The shell script has execute permission.
Are you sure though? (I mean within the container, onced ADDed)
To be sure, I would use the Dockerfile:
EXPOSE 8080 8999
COPY src/main/script/startup.sh /startup.sh
RUN chmod 755 /startup.sh
WORKDIR /
ENTRYPOINT ["/startup.sh"]
A container exits when its main process exits. So check that /startup.sh is not ending.
Particularly check that this java
java -jar -Xms400m -Xmx400m -Dlog4j.configurationFile=log4j2-qa2.xml \
-Djava.security.egd=file:/dev/./urandom \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=8999 \
-Dcom.sun.management.jmxremote.local.only=false \
-Dcom.sun.management.jmxremote.rmi.port=8999 \
app.jar
I think the trouble here is when you specify path like /app.jar, it is really difficult to make out where the current working directory actually is.
It can be any where and I suspect Docker must have accidentally copy your start.sh to a place whatever at that point ./ is.
You might want to ssh into the container and do a find to search and see where startup.sh is sitting.
docker ps -a - Find docker container ID
docker -i -t [CONTAINER_ID] /bin/bash - SSH inside
find . -name "startup.sh" - Look for file.
If you intend to copy the files through using ./ (current working directory), I think it would be better to specify where current is. And you can do this using the WORKDIR keyword.
Example:
WORKDIR /path/to/workdir
The WORKDIR instruction sets the working directory for any RUN, CMD,
ENTRYPOINT, COPY and ADD instructions that follow it in the
Dockerfile. If the WORKDIR doesn’t exist, it will be created even if
it’s not used in any subsequent Dockerfile instruction.
That way docker will not get confused.
See:
https://docs.docker.com/engine/reference/builder/#/workdir
I had a similar problem which led me to this thread, however my issue was not quite the exact same as yours. For me the problem was that I was using an alpine base image and my script was referencing #!/bin/bash, I just had to update mine to #!/bin/sh at the top of my script instead.
Related
I'm stuck trying to achieve the objective described in the title. Tried various options last of which is found in this article. Currently my Dockerfile is as follows:
FROM ubuntu:18.04
EXPOSE 8081
CMD cd /var/www/html/components
CMD "bash myscript start" "-D" "FOREGROUND"
#ENTRYPOINT ["bash", "myscript", "start"]
Neither the CMD..."FOREGROUND" nor the commented-out ENTRYPOINT lines work. However, when I open an interactive shell into the container, cd into /var/.../components folder and execute the exact same command to run the script, it works.
What do I need to change?
Once you pass your .sh file, run it with CMD. This is a snippet:
ADD ./configure.and.run.myapp.sh /tmp/
RUN chmod +x /tmp/configure.and.run.myapp.sh
...
CMD ["sh", "-c", "/tmp/configure.and.run.myapp.sh"]
And here is my full dockerfile, have a look.
I see three problems with the Dockerfile you've shown.
There are multiple CMDs. A Docker container only runs one command (and then exits); if you have multiple CMD directives then only the last one has an effect. If you want to change directories, use the WORKDIR directive instead.
Nothing is COPYd into the image. Unless you explicitly COPY your script into the image, it won't be there when you go to run it.
The CMD has too many quotes. In particular, the quotes around "bash myscript start" make it into a single shell word, and so the system looks for an executable program named exactly that, including spaces as part of the filename.
You should be able to correct this to something more like:
FROM ubuntu:18.04
# Instead of `CMD cd`; a short path like /app is very common
WORKDIR /var/www/html/components
# Make sure the application is part of the image
COPY ./ ./
EXPOSE 8081
# If the script is executable and begins with #!/bin/sh then
# you don't need to explicitly say "bash"; you probably do need
# the path if it's not in /usr/local/bin or similar
CMD ./myscript start -D FOREGROUND
(I tend to avoid ENTRYPOINT here, for two main reasons. It's easier to docker run --rm -it your-image bash to get a debugging shell or run other one-off commands without an ENTRYPOINT, especially if the command requires arguments. There's also a useful pattern of using ENTRYPOINT to do first-time setup before running the CMD and this is a little easier to set up if CMD is already the main container command.)
I am trying to build a docker image using the dockerfile, my purpose is to copy a file into a specific folder when i run the "docker run" command!
this my dockerfile code:
FROM openjdk:7
MAINTAINER MyPerson
WORKDIR /usr/src/myapp
ENTRYPOINT ["cp"]
CMD ["/usr/src/myapp"]
CMD ls /usr/src/myapp
After building my image without any error (using the docker build command), i tried to run my new image:
docker run myjavaimage MainClass.java
i got this error: ** cp: missing destination file operand after ‘MainClass.java’ **
How can i resolve this? thx
I think you want this Dockerfile:
FROM openjdk:7
WORKDIR /usr/src/myapp
COPY MainClass.java .
RUN javac MainClass.java
ENV CLASSPATH=/usr/src/myapp
CMD java MainClass
When you docker build this image, it COPYs your Java source file from your local directory into the image, compiles it, and sets some metadata telling the JVM where to find the resulting .class files. Then when you launch the container, it will run the single application you've packaged there.
It's common enough to use a higher-level build tool like Maven or Gradle to compile multiple files into a single .jar file. Make sure to COPY all of the source files you need in before running the build. In Java it seems to be common to build the .jar file outside of Docker and just COPY that in without needing a JDK, and that's a reasonable path too.
In the Dockerfile you show, Docker combines ENTRYPOINT and CMD into a single command and runs that command as the single main process of the container. If you provide a command of some sort at the docker run command, that overrides CMD but does not override ENTRYPOINT. You only get one ENTRYPOINT and one CMD, and the last one in the Dockerfile wins. So you're trying to run container processes like
# What's in the Dockerfile
cp /bin/sh -c "ls /usr/src/myapp"
# Via your docker run command
cp MainClass.java
As #QuintenScheppermans suggests in their answer you can use a docker run -v option to inject the file at run time, but this will happen after commands like RUN javac have already happened. You don't really want a workflow where the entire application gets rebuilt every time you docker run the container. Build the image during docker build time, or before.
Two things.
You have used CMD twice.
CMD can only be used once, think of it as the purpose of your docker image. Every time a container is run, it will always execute CMD if you want multiple commands, you should use RUN and then lastly, used CMD
FROM openjdk:
MAINTAINER MyPerson
WORKDIR /usr/src/
ENTRYPOINT ["cp"]
RUN /usr/src/myapp
RUN ls /usr/src/myapp
Copying stuff into image
There is a simple command COPY the syntax being COPY <from-here> <to-here>
Seems like you want to run myjavaimage so what you will do is
COPY /path/to/myjavaimage /myjavaimage
CMD myjavaimage MainClass.java
Where you see the arrows, I've just written dummy code. Replace that with the correct code.
Also, your Dockerfile is badly created.
ENTRYPOINT -> not sure why you'd do "cp", but it's an actual entrypoint. Could point to the root dir of your project or to an app that will be run.
Don't understand why you want to do ls /usr/src/myapp but if you do want to do it, use RUN and not CMD
Lastly,
Best way to debug docker containers are in interactive mode. That means ssh'ing in to your container, have a look around, run code, and see what is the problem.
Run this: docker run -it <image-name> /bin/bash and then have a look inside and it's usually the best way to see what causes issues.
This stackoverflow page perfectly answers your question.
COPY foo.txt /data/foo.txt
# where foo.txt is the relative path on host
# and /data/foo.txt is the absolute path in the image
If you need to mount a file when running the command:
docker run --name=foo -d -v ~/foo.txt:/data/foo.txt -p 80:80 image_name
I am trying to use ENTRYPOINT and whenever I do that I am getting an error as no such file or directory
Dockerfile:
FROM ubuntu:18.04
COPY . /home
COPY docker-entrypoint.sh /usr/local/bin/
RUN ln -s /usr/local/bin/docker-entrypoint.sh
WORKDIR /home
RUN chmod 777 /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["/bin/bash"]
I have tried giving it permission, tried running it with absolute path also tried this, tried it with #!/bin/bash & #!/bin/sh and in the end, I still get the file not found error.
I am not sure what the problem is.
The question you asked:
I don't remember exactly why, but the file isn't being found because you're calling it docker-entrypoint.sh rather than ./docker-entrypoint.sh.
The question you'll ask soon:
That doesn't entirely fix your problem. You've added execute privileges to the copy of docker-entrypoint.sh in /usr/local/bin, but there's another copy of the file in /home that gets found first and doesn't have execute privileges. You'll get a permissions error when you try to use it. An easy workaround (depending on what you want to do) consists of a modified entrypoint:
ENTRYPOINT ["/bin/bash", "docker-entrypoint.sh"]
Extra details if you'll be using Docker a lot:
Being able to enter a container or image to examine its contents is invaluable. For ubuntu-based images, write down the following line somewhere (replace bash with sh for basically every other linux OS):
docker run -it --rm --entrypoint=bash my_image_name
This will open up a shell in that image and let you play around in the same environment the Dockerfile is running in and debug whatever is causing you problems.
I have an executable binary called abin that I want to containerize. All abin does is output a test string via printf. So I create a directory called test, which contains only abin and the following Dockerfile:
from alpine:3.7
copy abin /
entrypoint /abin
So I sudo docker build -t test/testy:tag . && sudo docker run --rm test/testy:tag, and get the following:
/bin/sh: /abin: not found
This baffles me for two reasons:
why is sh running despite setting the entrypoint to /abin?
why is /abin not found?
Changing the entrypoint to stat /abin then re-building and re-running gives the expected stat output, clearly indicating that there's an executable file at /abin. By the same token, removing the entrypoint and running in the container's interactive shell, I can see the abin file, and I can ls or stat and cat etc., but ./abin or /abin still give the /bin/sh: ./abin: not found error.
EDIT:
I incorrectly assumed that Alpine ran the same kind of binaries as most linuxes. Not so. Also, it doesn't even come with stdio - my second mistake. Lastly, I needed to specify the entrypoint as an absolute path. Thus the following Dockerfile works:
from alpine:3.7
workdir /
copy test.c .
run apk add gcc libc-dev && gcc test.c -o abin
entrypoint ["/abin"]
If your entrypoint is not inside square brackets, Docker will call sh <entrypoint>. Use ENTRYPOINT ["abin"] instead and I believe it should work.
I have the following Dockerfile:
FROM phusion/baseimage:0.9.16
RUN mv /build/conf/ssh-setup.sh /etc/my_init.d/ssh-setup.sh
EXPOSE 80 22
CMD ["node", "server.js"]
My /build/conf/ssh-setup.sh looks like the following:
#!/bin/sh
set -e
echo "${SSH_PUBKEY}" >> /var/www/.ssh/authorized_keys
chown www-data:www-data -R /var/www/.ssh
chmod go-rwx -R /var/www/.ssh
It just adds SSH_PUBKEY env to /var/www/.ssh/authorized_keys to enable ssh access.
I run my container just like the following:
docker run -d -p 192.168.99.100:80:80 -p 192.168.99.100:2222:22 \
-e SSH_PUBKEY="$(cat ~/.ssh/id_rsa.pub)" \
--name dev hub.core.test/dev
My container starts fine but unfortunately /etc/my_init.d/ssh-setup.sh script does't get executed and I'm unable to ssh my container.
Could you help me what is the reason why /var/www/.ssh/authorized_keys doesn't get executed on starting of my container?
I had a pretty similar issue, also using phusion/baseimage. It turned out that my start script needed to be executable, e.g.
RUN chmod +x /etc/my_init.d/ssh-setup.sh
Note:
I noticed you're not using baseimage's init system ( maybe on purpose? ). But, from my understanding of their manifesto, doing that forgoes their whole "a better init system" approach.
My understanding is that they want you to, in your case, move your start command of node server.js to a script within my_init.d, e.g. /etc/my_init.d/start.sh and in your dockerfile use their init system instead as the start command, e.g.
FROM phusion/baseimage:0.9.16
RUN mv /build/conf/start.sh /etc/my_init.d/start.sh
RUN mv /build/conf/ssh-setup.sh /etc/my_init.d/ssh-setup.sh
RUN chmod +x /etc/my_init.d/start.sh
RUN chmod +x /etc/my_init.d/ssh-setup.sh
EXPOSE 80 22
# Use baseimage-docker's init system.
CMD ["/sbin/my_init"]
That'll start baseimage's init system, which will then go and look in your /etc/my_init.d/ and execute all the scripts in there in alphabetical order. And, of course, they should all be executable.
My references for this are: Running start scripts and Getting Started.
As the previous answer states you did not execute ssh-setup.sh. You can only have one process in a Docker container (that is a lie, but it will do for now). Why not run ssh-setup.sh as your CMD/ENTRYPOINT process and have ssh-setup.sh exec into your final command, i.e.
exec node server.js
Or cleaner, have a script, like boot.sh, which runs any init scripts, like ssh-setup.sh, then execs to node.
Because you didn't invoke /etc/my_init.d/ssh-setup.sh when you started your container.
you should call it in CMD or ENTRYPOINT, read more here
RUN executes command(s) in a new layer and creates a new image. E.g.,
it is often used for installing software packages.
CMD sets default
command and/or parameters, which can be overwritten from command line
when docker container runs.
ENTRYPOINT configures a container that
will run as an executable.