I just started playing around with Docker yesterday and am having issues between the build environment and the run environment. Build wise I have issues like...
RUN install.sh
/bin/sh: 1: install.sh: Permission denied
the command '/bin/sh -c install.sh' returned a non-zero code: 126
or ...
RUN . sourceme.env
/bin/sh: 1: .: sourceme.env: not found
The command '/bin/sh -c . sourceme.env' returned a non-zero code: 2
I build using 'sudo docker build -t joes' and
I run using 'sudo docker run -it joes'
The frustrating thing is that after build failure I can run it, see that I am in the working directory I expected, and run the command that failed during building successfully. So why the discrepancy?
This is on a linux system and I'm using 'FROM ubuntu:18.04'
To bypass the RUN install.sh error I used
RUN /bin/sh install.sh
which converts to
/bin/sh -c /bin/sh install.sh
Post your entire Dockerfile. The problem is you haven't pointed to the correct location. When you copy it, copy it in and then supply it with the absolute path.
e.g.
COPY install.sh /install.sh
CMD ./install.sh
EDIT: if your containers main job is to run the install.sh script then use it with CMD and not RUN. Use run to build env and evth else.
Using the RUN instruction in a Dockerfile with 'source' does not work Seems to be the bulk of my issue
That along with running multiple RUN commands instead of RUN ... && ... && ... etc
Related
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.
How do I execute an executable twice in a docker container?
For instance I need to run my application twice, the first time to initialize some stuff, and the second time to listen to a given port defined in an environment variables.
The commands from a shell would be something like this:
[j3d#gonzo test]$ kontrol -initial
[j3d#gongo test]$ kontrol
started... listening on port 6000...
Here below is my Dockerfile:
FROM golang:1.8.3 as builder
RUN go get -u github.com/golang/dep/cmd/dep
RUN go get -d github.com/koding/kite
WORKDIR ${GOPATH}/src/github.com/koding/kite
RUN ${GOPATH}/bin/dep ensure
RUN go install ./kontrol/kontrol
RUN mv ${GOPATH}/bin/kontrol /tmp
FROM busybox
ENV APP_HOME /opt/robotrader
RUN mkdir -p ${APP_HOME}
WORKDIR ${APP_HOME}
COPY --from=builder /tmp/kontrol .
ENTRYPOINT ["./kontrol", "-initial"]
CMD ["./kontrol"]
The container builds successfully... but when I start it I always get the following error message:
kontrol | standard_init_linux.go:190: exec user process caused "no such file or directory"
Any help would be really appreciated.
EDIT
Thanks to zero298 who helped me to figure out the issue, here below is a working Dockerfile:
FROM golang:1.8.3 as builder
RUN go get -u github.com/golang/dep/cmd/dep
RUN go get -d github.com/koding/kite
WORKDIR ${GOPATH}/src/github.com/koding/kite
RUN ${GOPATH}/bin/dep ensure
RUN CGO_ENABLED=0 go install ./kontrol/kontrol
RUN mv ${GOPATH}/bin/kontrol /tmp
FROM busybox
ENV APP_HOME /opt/robotrader
RUN mkdir -p ${APP_HOME}
WORKDIR ${APP_HOME}
COPY --from=builder /tmp/kontrol .
ENTRYPOINT ["./kontrol", "-initial"]
CMD ["./kontrol"]
The go application should be built with CGO_ENABLED=0 - see this post for more info.
I think you are running into a different issue than you think you are. Running your Dockerfile and then executing:
docker build -t j3d .
docker run -it --rm --name j3d-test --entrypoint sh j3d
Allows me to run my own commands from within the container.
Using ls lists out the PWD contents:
-rwxr-xr-x 1 root root 16.8M Jun 21 19:20 kontrol
Everything seems normal. However, trying to run that myself generates the following error:
sh: ./kontrol: not found
To me, this is likely similar to: Linux executable fails with “File not found” even though the file is there and in PATH.
In fact, if you instead:
Copy the compiled kontrol executable out of your builder image
Run the ubuntu container mounting the directory with the copied kontrol executable docker run -it --rm -v $PWD:/mnt/go ubuntu sh
Try to run kontrol
You will get the "correct" error which stipulates you haven't setup your keys correctly:
2018/06/21 19:56:57 cannot read public key file: open : no such file or directory
Your path forward is probably to figure out why you can't cross-compile
Create a script that runs it twice:
E.g in "startup.sh"
#!/bin/bash
# Run kontrol twice
./kontrol -initial
./kontrol
Then replace the last two lines in your Dockerfile with:
COPY startup.sh .
CMD ["./startup.sh"]
If kontrol terminates when you run it with the init flag, then you shuold just use
RUN /opt/robotrader/kontrol -init
CMD ["./kontrol"]
If it doesn't terminate, you'll have to find another way to architect your appp.
I have a relatively simple dockerfile
FROM python:3.6.5-alpine
COPY somebinary /usr/local/bin/
COPY install.sh /install.sh
RUN /install.sh
The binary gets copied across just fine (when I run the container to check) but the script doesn't seem to get copied across so that when I try to run it I get:
Step 4/5 : COPY install.sh /install.sh
---> 38ecc6dbad13
Step 5/5 : RUN /install.sh
---> Running in 0b06962d6e1b
/bin/sh: /install.sh: not found
The command '/bin/sh -c /install.sh' returned a non-zero code: 127
The same happens with any other test files I make, they aren't available when the image is run. Other people have had success running the exact same script so I suspect it could be to do with the fact that I'm running docker through Git Bash on Windows? Could it be a permissions thing?
e: I went and tried running through powershell and got the same error, so perhaps git bash is a red herring
It seems your install.sh script is having ^M characters.
Try saving your install.sh into unix format. dos2unix
Use notepad++ or sublime or any other editor which support converting end of lines from Windows to UNIX format.
Working with Docker and I notice almost everywhere the "RUN" command starts with an apt-get upgrade && apt-get install etc.
What if you don't have internet access and simply want to do a "dpkg -i ./deb-directory/*.deb" instead?
Well, I tried that and I keep failing. Any advice would be appreciated:
dpkg: error processing archive ./deb-directory/*.deb (--install):
cannot access archive: No such file or directory
Errors were encountered while processing: ./deb-directory/*.deb
INFO[0002] The command [/bin/sh -c dpkg -i ./deb-directory/*.deb] returned a non-zero code: 1`
To clarify, yes, the directory "deb-directory" does exist. In fact it is in the same directory as the Dockerfile where I build.
This is perhaps a bug, I'll open a ticket on their github to know.
Edit: I did it here.
Edit2:
Someone answered a better way of doing this on the github issue.
* is a shell metacharacter. You need to invoke a shell for it to be expanded.
docker run somecontainer sh -c 'dpkg -i /debdir/*.deb'
!!! Forget the following but I leave it here to keep track of my reflexion steps !!!
The problem comes from the * statement which doesn't seem to work well with the docker run dpkg command. I tried your command inside a container (using an interactive shell) and it worked well. It looks like dpkg is trying to install the so called ./deb-directory/*.deb file which doesn't exist instead of installing all the .deb files contained there.
I just implemented a workaround. Copy a .sh script in your container, chmod +x it and then use it as your command.
(FYI, prefer using COPY instead of ADD when the file isn't remotely copied. Check the best practices for writing Dockerfiles for more info.)
This is my Dockerfile for example purpose:
FROM debian:latest
MAINTAINER Vrakfall <jeremy#artphotolaurent.be>
COPY install.sh /
#debdir is a directory
COPY debdir /debdir
RUN chmod +x /install.sh
CMD ["/install.sh"]
The install.sh (copied at the root directory) simply contains:
#!/bin/bash
dpkg -i /debdir/*.deb
And the following
docker build -t debiantest .
docker run debiantest
works well and install all the packages contained in the /debdir directory.
In docker I want to do this:
git clone XYZ
cd XYZ
make XYZ
However because there is no cd command, I have to pass in the full path everytime (make XYZ /fullpath). Any good solutions for this?
To change into another directory use WORKDIR. All the RUN, CMD and ENTRYPOINT commands after WORKDIR will be executed from that directory.
RUN git clone XYZ
WORKDIR "/XYZ"
RUN make
You can run a script, or a more complex parameter to the RUN. Here is an example from a Dockerfile I've downloaded to look at previously:
RUN cd /opt && unzip treeio.zip && mv treeio-master treeio && \
rm -f treeio.zip && cd treeio && pip install -r requirements.pip
Because of the use of '&&', it will only get to the final 'pip install' command if all the previous commands have succeeded.
In fact, since every RUN creates a new commit & (currently) an AUFS layer, if you have too many commands in the Dockerfile, you will use up the limits, so merging the RUNs (when the file is stable) can be a very useful thing to do.
I was wondering if two times WORKDIR will work or not, but it worked :)
FROM ubuntu:18.04
RUN apt-get update && \
apt-get install -y python3.6
WORKDIR /usr/src
COPY ./ ./
WORKDIR /usr/src/src
CMD ["python3", "app.py"]
You can use single RUN command for all of them
RUN git clone XYZ && \
cd XYZ && \
make XYZ
In case you want to change the working directory for the container when you run a docker image, you can use the -w (short for --workdir) option:
docker run -it -w /some/valid/directory/inside/docker {image-name}
Ref:
docker run options: https://docs.docker.com/engine/reference/commandline/run/#options
Mind that if you must run in bash shell, you need not just the RUN make, but you need to call the bash shell before, since in Docker, you are in the sh shell by default.
Taken from /bin/sh: 1: gvm: not found, which would say more or less:
Your shell is /bin/sh, but source expects /bin/bash, perhaps because it
puts its initialization in ~/.bashrc.
In other words, this problem can occur in any setting where the "sh" shell is used instead of the "bash", causing "/bin/sh: 1: MY_COMMAND: not found".
In the Dockerfile case, use the recommended
RUN /bin/bash -c 'source /opt/ros/melodic/setup.bash'
or with the "[]" (which I would rather not use):
RUN ["/bin/bash", "-c", "source /opt/ros/melodic/setup.bash"]
Every new RUN of a bash is isolated, "starting at 0". For example, mind that setting WORKDIR /MY_PROJECT before the bash commands in the Dockerfile does not affect the bash commands since the starting folder would have to be set in the ".bashrc" again. It needs cd /MY_PROJECT even if you have set WORKDIR.
Side-note: do not forget the first "/" before "opt/../...". Else, it will throw the error:
/bin/bash: opt/ros/melodic/setup.bash: No such file or directory
Works:
=> [stage-2 18/21] RUN ["/bin/bash", "-c", "source /opt/ros/melodic/setup.bash"] 0.5s
=> [stage-2 19/21] [...]
See “/bin/sh: 1: MY_COMMAND: not found” at SuperUser for some more details on how this looks with many lines, or how you would fill the ".bashrc" instead. But that goes a bit beyond the actual question here.
PS: You might also put the commands you want to execute in a single bash script and run that bash script in the Dockerfile (though I would rather put the bash commands in the Dockerfile as well, just my opinion):
#!/bin/bash
set -e
source /opt/ros/melodic/setup.bash