Docker WORKDIR path is added to relative path - docker

I have the trouble that the following DOCKERFILE ends up in a exception, where it cant find /src/webui/tail -f /dev/null and thats right, because I wanted to execute only tail -f /dev/null.
docker build is working, docker run is failing!
How can I avoid that the WORKDIR path is added to the tail command?
DOCKERFILE:
FROM node:12.17.0-alpine
WORKDIR /src/webui
RUN apk update && apk add bash
CMD ["tail -f /dev/null"]
Exception:
> docker run test
internal/modules/cjs/loader.js:969
throw err;
^
Error: Cannot find module '/src/webui/tail -f /dev/null'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:966:15)
at Function.Module._load (internal/modules/cjs/loader.js:842:27)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
System Information:
Docker Desktop (Windows 10 Pro)
Docker version 19.03.8, build afacb8b

When you give CMD (or RUN or ENTRYPOINT) in the JSON-array form, you're responsible for manually breaking up the command into "words". That is, you're running the equivalent of the quoted shell command
'tail -f /dev/null'
and the whole thing gets interpreted as one "word" -- the spaces and options are taken as part of the command name to look up in $PATH.
The most straightforward workaround to this is to remove the quoting and just use a bare string as CMD.
Note that the container you're building doesn't actually do anything: it doesn't include any application source code and the command you're providing intentionally does nothing forever. Aside from one running container with an idle process, you get the same effect by just not running the container at all. You typically want to copy your application code in and set CMD to actually run it:
FROM node:12.17.0-alpine
WORKDIR /src/webui
COPY package.json yarn.lock ./
RUN yarn install
COPY . ./
CMD ["yarn", "start"]
# Also works: CMD yarn start
# Won't work: CMD ["yarn start"]

The correct Dockerfile:
FROM node:12.17.0-alpine
WORKDIR /src/webui
RUN apk update && apk add bash
CMD ["tail", "-f", "/dev/null"]
So the difference is that this:
CMD ["tail -f /dev/null"]
needs to be:
CMD ["tail", "-f", "/dev/null"]
You can read more about CMD in the official Docker docs.

CMD will append after ENTRYPOINT
Since node:12.17.0-alpine have default ENTRYPONINT node
Your dockerfile will becomes
node tail -f /dev/null
option1
Override ENTRYPOINT in build time
ENTRYPOINT tail -f /dev/null
option2
Override ENTRYPOINT in run time
docker run --entrypoint sh my-image

Related

Docker container fails on Windows Powershell succeeds on WSL2 with identical Dockerfile and docker-compose

Problem Description
I have a docker image which I build and run using docker-compose. Normally I develop on WSL2, and when running docker-compose up --build the image builds and runs successfully. On another machine, using Windows powershell, with an identical clone of the code, executing the same command successfully builds the image, but gives an error when running.
Error
[+] Running 1/1
- Container fastapi-service Created 0.0s
Attaching to fastapi-service
fastapi-service | exec /start_reload.sh: no such file or directory
fastapi-service exited with code 1
I'm fairly experienced using Docker, but am a complete novice with PowerShell and developing on Windows more generally. Is there a difference in Dockerfile construction in this context, or a difference in the execution of COPY and RUN statements?
Code snippets
Included are all parts of the code required to replicate the error.
Dockerfile
FROM tiangolo/uvicorn-gunicorn:python3.7
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
COPY ./start.sh /start.sh
RUN chmod +x /start.sh
COPY ./start_reload.sh /start_reload.sh
RUN chmod +x /start_reload.sh
COPY ./data /data
COPY ./app /app
EXPOSE 8000
CMD ["/start.sh"]
docker-compose.yml
services:
web:
build: .
container_name: "fastapi-service"
ports:
- "8000:8000"
volumes:
- ./app:/app
command: /start_reload.sh
start-reload.sh
This is a small shell script which runs a prestart.sh if present, and then launches gunicorn/uvicorn in "reload mode":
#!/bin/sh
# If there's a prestart.sh script in the /app directory, run it before starting
PRE_START_PATH=/app/prestart.sh
HOST=${HOST:-0.0.0.0}
PORT=${PORT:-8000}
LOG_LEVEL=${LOG_LEVEL:-info}
echo "Checking for script in $PRE_START_PATH"
if [ -f $PRE_START_PATH ] ; then
echo "Running script $PRE_START_PATH"
. "$PRE_START_PATH"
else
echo "There is no script $PRE_START_PATH"
fi
# Start Uvicorn with live reload
exec uvicorn --host $HOST --port $PORT --log-level $LOG_LEVEL main:app --reload
The solution lies in a difference between UNIX and Windows systems, and the way they end lines. A discussion on the topic can be found [here].
(Difference between CR LF, LF and CR line break types?)
The presence/absence of these characters in the file, and configuration of the shell running the command leads to an error where the file being run is the Dockerfile start-reload.sh(CR-LF) but the file that exists is simply start-reload.sh, hence the no such file or directory error raised.

Docker says unknown operand golang alpine

I have the following docker image:
FROM golang:1.16-alpine
WORKDIR /app
COPY . /app
RUN go mod init auto-rebase
RUN go build
ENV PROJECT=""
CMD [ "echo", $PROJECT ]
After building and runnign:
docker build -t marge-auto-rebase .
docker run -e PROJECT=37473816 --rm -it marge-auto-rebase
I get the following error:
sh: 37473816: unknown operand
This runs just fine outside docker, what is the issue here? It seems like this is something related to alpine?
Seems to be a sh issue. I don't have explanations for this behavior. I made it work by rewriting your CMD instruction like so:
CMD ["/bin/sh", "-c", "echo $PROJECT"]

Shebang in JavaScript ignored when executed as command in Docker with "/bin/bash" as entrypoint

When I try to execute a JavaScript file with a shebang such as #!/usr/bin/env node through the command argument of docker run ... it seems to "ignore" the shebang.
$ docker run --rm foobar/hello-world /hello-world.js
/hello-world.js: line 2: syntax error near unexpected token `'Hello, World!''
/hello-world.js: line 2: `console.log('Hello, World!');'
Dockerfile
FROM node:13.12-alpine
COPY hello-world.js /hello-world.js
RUN chmod +x /hello-world.js
RUN apk update && apk update && apk add bash
ENTRYPOINT ["/bin/bash"]
hello-world.js
#!/usr/bin/env node
console.log('Hello, World!');
When I use /hello-world.js as the entrypoint directly (ENTRYPOINT ["/hello-world.js"]) it works correctly.
Add -c to the entrypoint so bash will expect a command. Without -c it interprets its argument as the name of a bash script to execute.
ENTRYPOINT ["/bin/bash", "-c"]
I'd recommend just setting the default CMD to the program you're installing in your container, and generally preferring CMD to ENTRYPOINT if you only need one of them.
FROM node:13.12-alpine
COPY hello-world.js /hello-world.js
RUN chmod +x /hello-world.js
CMD ["/hello-world.js"]
When you provide a command at the docker run command line, it overrides the Dockerfile CMD (if any), and it's appended to the ENTRYPOINT. In your original example the ENTRYPOINT from the Dockerfile is combined with the docker run command and you're getting a combined command bash /hello-world.js.
If you do need an interactive shell to debug the container, you can launch that with
docker run --rm -it foobar/hello-world /bin/sh

trouble with multiple parms and RUN

I'm trying to get Parcel Bundler to build assets from within a Dockerfile. But its failing with:
🚨 No entries found.
at Bundler.bundle (/usr/local/lib/node_modules/parcel-bundler/src/Bundler.js:260:17)
at ERROR: Service 'webapp' failed to build: The command '/bin/sh -c parcel build index.html' returned a non-zero code:
1
Here's my dockerfile:
FROM node:8 as base
WORKDIR /usr/src/app
COPY package*.json ./
# Development
FROM base as development
ENV NODE_ENV=development
RUN npm install
RUN npm install -g parcel-bundler
WORKDIR /usr/src/app
RUN parcel build index.html <----- this is where its failing!
#RUN parcel watch index.html
# Uncomment to use Parcel's dev-server
#CMD [ "npm", "run", "parcel:dev" ]
#CMD ["npm", "start"]
# Production
FROM base as production
ENV NODE_ENV=production
COPY . .
RUN npm install --only=production
RUN npm install -g parcel-bundler
RUN npm run parcel:build
CMD [ "npm", "start" ]
NOTE: I'm trying to get this to run in Development mode first.
When I "log into" the container, I found that this command does fail:
# /bin/sh -c parcel build index.html
But this works:
# parcel build index.html
And this works:
# /bin/sh -c "parcel build index.html"
But using these variations in the Dockerfile still do NOT work:
RUN /bin/sh -c "parcel build index.html"
or
RUN ["/bin/sh", "-c", "parcel build index.html"]
NOTE: I also tried 'bash' instead of 'sh' and it still didn't work.
Any ideas why its not working?
bash and sh are indeed different shells, but it shouldn't matter here. -c "command argument argument" passes the entire shell string to -c, whereas -c command argument argument only passes command to -c leaving the arguments to be interpreted as additional commands to the shell you're invoking. So the right invocation is indeed:
RUN parcel build index.html
or, if you prefer to explicitly do what Docker will do when it sees RUN followed by a string, you can do:
RUN [ "bash", "-c", "parcel build index.html" ]
But I don't think any of that is your problem. Looking at your docker file, I think you're probably either:
missing some files that Bundler needs ( you've only copied in package*.json at this point )
missing some additional config that Bundler needs to function (I don't see you explictly setting 'webapp' but that might be in a package*.json file)
I'd put my money on the first one.

Package docker maven application and run it using a shell script

I am building Scigraph database on my local machine and trying to move this entire folder to docker and run it, when I run the shell script on my local machine it runs without error when I add the same folder inside docker and try to run it fails
Am I doing this right way, here's my DOckerfile
FROM goyalzz/ubuntu-java-8-maven-docker-image
ADD ./SciGraph /usr/share/SciGraph
WORKDIR /usr/share/SciGraph/SciGraph-services
RUN pwd
EXPOSE 9000
CMD ['./run.sh']
when I try to run it I'm getting this error
docker run -p9005:9000 test
/bin/sh: 1: [./run.sh]: not found
if I run it using below command it works
docker run -p9005:9000 test -c "cd /usr/share/SciGraph/SciGraph-services && sh run.sh"
as I already marked the directory as WORKDIR and running the script inside docker using CMD it throws error
For scigraph as provided in their ReadMe, you can to run mvn install before you run their services. You can set your shell to bash and use a docker compose to run the docker image as shown below
Dockerfile
FROM goyalzz/ubuntu-java-8-maven-docker-image
ADD ./SciGraph /usr/share/SciGraph
SHELL ["/bin/bash", "-c"]
WORKDIR /usr/share/SciGraph
RUN mvn -DskipTests -DskipITs -Dlicense.skip=true install
RUN cd /usr/share/SciGraph/SciGraph-services && chmod a+x run.sh
EXPOSE 9000
build the scigraph docker image by running
docker build . -t scigraph_test
docker-compose.yml
version: '2'
services:
scigraph-server:
image: scigraph_test
working_dir: /usr/share/SciGraph/SciGraph-services
command: bash run.sh
ports:
- 9000:9000
give / after SciGraph-services and change it to "sh run.sh" ................ and look into run.sh file permissions also
It is likely that your run.sh doesn't have the #!/bin/bash header, so it cannot be executed only by running ./run.sh. Nevertheless, always prefer to run scripts as /bin/bash foo.sh or /bin/sh foo.sh when in docker, especially because you don't know what changes files have been sourced in images downloaded from public repositories.
So, your CMD statement would be:
CMD /bin/bash -c "/bin/bash run.sh"
You have to add the shell and the executable to the CMD array ...
CMD ["/bin/sh", "./run.sh"]

Resources