How to execute start script in Dockerfile - docker

I want to create new image from jdk, build it, it works; when I run my new imag, it return container id, but can't get the process-info when docker ps,this is my dockerfile:
# specified jdk version
FROM openjdk:7-jre
# env
ENV APP_HOME /usr/src/KOAL-OCSP
ENV PATH $APP_HOME:$PATH
# copy my app in .zip to /usr/src
COPY myapp.zip /usr/src/
# unzip copy file
RUN unzip /usr/src/myapp.zip
WORKDIR $APP_HOME
#port
expose 80
#run the setup script of my app when start container
CMD ["service.sh" "start"]
service.sh is a setup script is my app root-file, I wish the script can auto execuced when run the new self-build image.

I suspect that the container has executed and exited successfully. The container will stay alive as long as the processes that you have started using the services.sh script is still running.
In your case, the services.sh has executed and exited, thus causing the container to exit.
To view all containers, use docker ps -a
Update:
The error /bin/sh: 1: ./service.sh: not found indicates that the services.sh script is not found under $APP_HOME inside the Docker image. Make sure you add it under $APP_HOME using
ADD `service.sh` $APP_HOME

CMD ["service.sh" "start"]
The above is not valid json, it's missing a comma in the the array, so docker will execute it as a string which will fail since ["service.sh" will not be found as a command to run.
If you use docker ps -a you will see a list of all containers, including exited ones. From there, you can use docker logs $(docker ps -lq) to see the logs of the last container you tried to run. And you can docker inspect $(docker ps -lq) to see all the details about the last container it tried to run, including the exit code.
To get past your current error, correct your syntax with the missing comma:
CMD ["service.sh", "start"]
For the next problem you are seeing, a "not found" error can indicate:
The command doesn't exist inside your container (at the expected location). In your scenario, make sure it is included in /usr/src/KOAL-OCSP that you unzip in your image.
The shell script does exist, but calls a binary on the first line that doesn't exist in your image. E.g. if you call #!/bin/bash but only have /bin/sh in your container. This also happens when you edit the files on a Windows system and have ^M linefeeds that become part of the name of the binary that the container is looking for (/bin/sh^M instead of /bin/sh).
For binaries, this can happen if executable you are running has library dependencies that do not exist inside your container. For example, if you build on a glibc environment and run the container with a musl libc environment of Alpine, this same error message will appear.

Related

how to use a executable file created in a docker file in the same docker file

What I want: i want to run a cpp file witch use opencv inside a container
What I've done:
installing an image of opencv:
docker pull spmallick/opencv-docker:opencv
create a docker file
FROM spmallick/opencv-docker:opencv
RUN ["g++ a.cpp -o a.out"]
COPY . .
CMD ["./a.out"]
bash command
sudo docker build -t project_opencv
OCI runtime create failed: container_linux.go:349: starting container process caused "exec: "g++ a.cpp -o a.out": executable file not found in $PATH": unknown
first I try this with cmd instead of RUN (how to use cmd inside a Dockerfile to compile a file). It couldn't find a.out although I've done COPY . .
Now it seems that there is a problem to create a.out
When you use the JSON-array form of RUN (or CMD or ENTRYPOINT), you explicitly provide the set of "words" that make up the command. As you've shown it, it is a single word, and Docker tries to run it as such, including the spaces in the command name it's looking up. You need to split it into its constituent words yourself.
RUN ["g++", "a.cpp", "-o", "a.out"]
The reverse side of this is that there is no splitting, expansion, or interpolation that happens in this command:
# Preserves both the literal $ and the spaces
RUN ["cp", "dollars-word-$word.txt", "file name with spaces.txt"]
Especially for RUN it's common to use the shell form. This wraps the command in sh -c so it works like an ordinary command. (There are technical reasons you might not want this for CMD and especially ENTRYPOINT.)
RUN g++ a.cpp -o a.out
RUN cp dollars-word-\$word.txt, 'file name with spaces.txt'
RUN tail env-var-$word.txt
First copy your a.cpp into docker image then your RUN command will work , I am not sure about your RUN ["g++ a.cpp -o a.out"] command this will work or not but try this:
FROM spmallick/opencv-docker:opencv
COPY . .
RUN ["g++ a.cpp -o a.out"]
CMD ["./a.out"]
I think you need to check the permissions for the files you have copied, from your host machine into the container.
You could also check the directory you are in, and if you need to change the directory, then you can use the WORKDIR command in your Dockerfile.
It would also be useful to start a bash session in the container, and run the commands manually. For each successful command, you can enter the command into the Dockerfile, or if you encounter an error, you can also troubleshoot more easily, rather than change the Dockerfile each time and run, and if you need to debug which is time consuming.

How to copy a file from the host into a container while starting?

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

Source files are updated, but CMD does not reflect

I'm new to docker and am trying to dockerize an app I have. Here is the dockerfile I am using:
FROM golang:1.10
WORKDIR /go/src/github.com/myuser/pkg
ADD . .
RUN curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
RUN dep ensure
CMD ["go", "run", "cmd/pkg/main.go"]
The issue I am running into is that I will update source files on my local machine with some log statements, rebuild the image, and try running it in a container. However, the CMD (go run cmd/pkg/main.go) will not reflect the changes I made.
I looked into the container filesystem and I see that the source files are updated and match what I have locally. But when I run go run cmd/pkg/main.go within the container, I don't see the log statements I added.
I've tried using the --no-cache option when building the image, but that doesn't seem to help. Is this a problem with the golang image, or my dockerfile setup?
UPDATE: I have found the issue. The issue is related to using dep for vendoring. The vendor folder had outdated files for my package because dep ensure was pulling them from github instead of locally. I will be moving to go 1.1 which support to go modules to fix this.
I see several things:
According to your Dockerfile
Maybe you need a dep init before dep ensure
Probably you need to check if main.go path is correct.
According to docker philosophy
In my humble opinion, you should create an image with docker build -t <your_image_name> ., executing that where your Dockerfile is, but without CMD line.
I would execute your go run <your main.go> in your docker run -d <your_image_name> go run <cmd/pkg/main.go> or whatever is your command.
If something is wrong, you can check exited containers with docker ps -a and furthermore check logs with docker logs <your_CONTAINER_name/id>
Other way to check logs is access to the container using bash and execute go run manually:
docker run -ti <your_image_name> bash
# go run blablabla

Why is docker still running CMD when overridden in by docker run?

I have a Dockerfile with the following CMD as the last line
CMD ["/usr/local/myapp/bin/startup.sh", "docker"]
Part of a script that is executed against the docker image during startup is as follows
# find directory of cacerts file in DOCKER_JAVA_HOME of container
DOCKER_CACERTS_DIR=$(dirname "$(docker run "$DOCKER_IMAGE_ID" find "$DOCKER_JAVA_HOME" -name cacerts)")
However, this still executes the CMD line from my Dockerfile.
I have found that I can alter this behaviour by changing the line in the script as follows.
# find directory of cacerts file in DOCKER_JAVA_HOME of container
DOCKER_CACERTS_DIR=$(dirname "$(docker run --entrypoint find "$DOCKER_IMAGE_ID" "$DOCKER_JAVA_HOME" -name cacerts)")
However, I didn't think this would be necessary. Is it normal for docker to execute the CMD when overridden in the docker run command? I thought this was supposed to be one of the differences between using CMD and ENTRYPOINT, that you could easily override CMD without using the --entrypoint flag.
In case it's important, this is using docker version 17.03.0-ce
The image being run has an ENTRYPOINT defined somewhere. Probably in the image you are building FROM if there isn't one in your Dockerfile.
When ENTRYPOINT and CMD are defined, Docker will pass the CMD to the ENTRYPOINT as arguments. From there, it's up to the ENTRYPOINT executable to decide what to do.
The arguments could be ignored completely, modified as the entry point sees fit or it can pass the complete command on to be run. That behaviour is image specific.

docker: executable file not found in $PATH

I have a docker image which installs grunt, but when I try to run it, I get an error:
Error response from daemon: Cannot start container foo_1: \
exec: "grunt serve": executable file not found in $PATH
If I run bash in interactive mode, grunt is available.
What am I doing wrong?
Here is my Dockerfile:
# https://registry.hub.docker.com/u/dockerfile/nodejs/ (builds on ubuntu:14.04)
FROM dockerfile/nodejs
MAINTAINER My Name, me#email.com
ENV HOME /home/web
WORKDIR /home/web/site
RUN useradd web -d /home/web -s /bin/bash -m
RUN npm install -g grunt-cli
RUN npm install -g bower
RUN chown -R web:web /home/web
USER web
RUN git clone https://github.com/repo/site /home/web/site
RUN npm install
RUN bower install --config.interactive=false --allow-root
ENV NODE_ENV development
# Port 9000 for server
# Port 35729 for livereload
EXPOSE 9000 35729
CMD ["grunt"]
This was the first result on google when I pasted my error message, and it's because my arguments were out of order.
The container name has to be after all of the arguments.
Bad:
docker run <container_name> -v $(pwd):/src -it
Good:
docker run -v $(pwd):/src -it <container_name>
When you use the exec format for a command (e.g., CMD ["grunt"], a JSON array with double quotes), it will be executed without a shell. This means that most environment variables will not be present.
If you specify your command as a regular string (e.g. CMD grunt) then the string after CMD will be executed with /bin/sh -c.
More info on this is available in the CMD section of the Dockerfile reference.
I found the same problem. I did the following:
docker run -ti devops -v /tmp:/tmp /bin/bash
When I change it to
docker run -ti -v /tmp:/tmp devops /bin/bash
it works fine.
For some reason, I get that error unless I add the "bash" clarifier. Even adding "#!/bin/bash" to the top of my entrypoint file didn't help.
ENTRYPOINT [ "bash", "entrypoint.sh" ]
There are several possible reasons for an error like this.
In my case, it was due to the executable file (docker-entrypoint.sh from the Ghost blog Dockerfile) lacking the executable file mode after I'd downloaded it.
Solution: chmod +x docker-entrypoint.sh
I had the same problem, After lots of googling, I couldn't find out how to fix it.
Suddenly I noticed my stupid mistake :)
As mentioned in the docs, the last part of docker run is the command you want to run and its arguments after loading up the container.
NOT THE CONTAINER NAME !!!
That was my embarrassing mistake.
Below I provided you with the picture of my command line to see what I have done wrong.
And this is the fix as mentioned in the docs.
A Docker container might be built without a shell (e.g. https://github.com/fluent/fluent-bit-docker-image/issues/19).
In this case, you can copy-in a statically compiled shell and execute it, e.g.
docker create --name temp-busybox busybox:1.31.0
docker cp temp-busybox:/bin/busybox busybox
docker cp busybox mycontainerid:/busybox
docker exec -it mycontainerid /bin/busybox sh
In the error message shown:
Error response from daemon: Cannot start container foo_1: \
exec: "grunt serve": executable file not found in $PATH
It is complaining that it cannot find the executable grunt serve, not that it could not find the executable grunt with the argument serve. The most likely explanation for that specific error is running the command with the json syntax:
[ "grunt serve" ]
in something like your compose file. That's invalid since the json syntax requires you to split up each parameter that would normally be split by the shell on each space for you. E.g.:
[ "grunt", "serve" ]
The other possible way you can get both of those into a single parameter is if you were to quote them into a single arg in your docker run command, e.g.
docker run your_image_name "grunt serve"
and in that case, you need to remove the quotes so it gets passed as separate args to the run command:
docker run your_image_name grunt serve
For others seeing this, the executable file not found means that Linux does not see the binary you are trying to run inside your container with the default $PATH value. That could mean lots of possible causes, here are a few:
Did you remember to include the binary inside your image? If you run a multi-stage image, make sure that binary install is run in the final stage. Run your image with an interactive shell and verify it exists:
docker run -it --rm your_image_name /bin/sh
Your path when shelling into the container may be modified for the interactive shell, particularly if you use bash, so you may need to specify the full path to the binary inside the container, or you may need to update the path in your Dockerfile with:
ENV PATH=$PATH:/custom/dir/bin
The binary may not have execute bits set on it, so you may need to make it executable. Do that with chmod:
RUN chmod 755 /custom/dir/bin/executable
The binary may include dynamically linked libraries that do not exist inside the image. You can use ldd to see the list of dynamically linked libraries. A common reason for this is compiling with glibc (most Linux environments) and running with musl (provided by Alpine):
ldd /path/to/executable
If you run the image with a volume, that volume can overlay the directory where the executable exists in your image. Volumes do not merge with the image, they get mounted in the filesystem tree same as any other Linux filesystem mount. That means files from the parent filesystem at the mount point are no longer visible. (Note that named volumes are initialized by docker from the image content, but this only happens when the named volume is empty.) So the fix is to not mount volumes on top of paths where you have executables you want to run from the image.
If you run a binary for a different platform, and haven't configured binfmt_misc with the --fix-binary option, qemu will be looking for the interpreter inside the container filesystem namespace instead of the host filesystem. See this Ubuntu bug report for more details on this issue.
If the error is from a shell script, the issue is often with the first line of that script (e.g. the #!/bin/bash). Either the command doesn't exist inside the image for a reason above, or the file is not saved as ascii or utf8 with Linux linefeeds. You can attempt dos2unix to fix the linefeeds, or check your git and editor settings.
in my case i order params wrong move all switchs before image name
I got this error message, when I was building alpine base image :
ERROR: for web Cannot start service web: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "bash": executable file not found in $PATH: unknown
In my docker-compose file, I had the command directive in which executing command using bash and bash does not come with alpine base image.
command: bash -c "python manage.py runserver 0.0.0.0:8000"
Then I realized and executed command using sh (shell).
It worked for me.
problem is glibc, which is not part of apline base iamge.
After adding it worked for me :)
Here are the steps to get the glibc
apk --no-cache add ca-certificates wget
wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk
apk add glibc-2.28-r0.apk
Refering to the title.
My mistake was to put variables via --env-file during docker run. Among others the file consisted of a PATH extension: PATH=$PATH:something, which caused PATH var look literally like PATH=$PATH:something (var resolution hadn't been performed) instead of PATH:/usr/bin...:something.
I couldn't make the resolution work through --env-file, so the only way I see this working is by using ENV in Dockerfile.
I ran into this issue using docker-compose. None of the solutions here or on this related question resolved my issue. Ultimately what worked for me was clearing all cached docker artifacts with docker prune -a and restarting docker.
to make it work add soft reference to /usr/bin:
ln -s $(which node) /usr/bin/node
ln -s $(which npm) /usr/bin/npm

Resources