My project directory structure:
myapp/
src/
Dockerfile
docker-compose.yml
docker-deploy.sh
wait-for-it.sh
.env
Where wait-for-it.sh
is a copy of the famous wait-for-it script.
My Dockerfile
:
FROM node:16
WORKDIR /usr/src/app
COPY package*.json ./
COPY wait-for-it.sh ./
COPY docker-deploy.sh ./
RUN chmod +x docker-deploy.sh
RUN npm install --legacy-peer-deps
COPY . .
RUN npm run build
ENTRYPOINT ["docker-deploy.sh"]
And docker-deploy.sh
is:
#!/bin/bash
# make wait-for-it executable
chmod +x wait-for-it.sh
# call wait-for-it with passed in args and then start node if it succeeds
bash wait-for-it.sh -h $1 -p $2 -t 300 -s -- node start
And my docker-compose.yml
:
version: '3.7'
services:
my-service:
build: .
postgres:
container_name: postgres
image: postgres:14.3
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USER}
POSTGRES_DB: my-service-db
PG_DATA: /var/lib/postgresql2/data
ports:
- ${DB_PORT}:${DB_PORT}
volumes:
- pgdata:/var/lib/postgresql2/data
volumes:
pgdata:
And where my .env
looks like:
DB_PASSWORD=1234
DB_USER=root
DB_PORT=5432
When I run the following command-line from the project root:
docker-compose --env-file .env up --build
I get:
Creating myapp_my-service_1 ... error
Creating postgres ...
Creating postgres ... done
ERROR: for my-service Cannot start service my-service: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "docker-deploy.sh": executable file not found in $PATH: unknown
ERROR: Encountered errors while bringing up the project.
What is going on? Is the error coming from the wait-for-it.sh
script itself, from a poorly configured CMD
directive in the Dockerfile
, or from the actual Node/JS app running as my-service
?
Update
Latest errors after applying @ErikMD’s suggested changes:
Creating postgres ... done
Creating myapp_my-service_1 ... error
ERROR: for myapp_my-service_1 Cannot start service my-service: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "./docker-deploy.sh": permission denied: unknown
ERROR: for my-service Cannot start service my-service: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "./docker-deploy.sh": permission denied: unknown
ERROR: Encountered errors while bringing up the project.
So it is spinning up the DB (postgres
) no problem but is still for some reason getting permissions-related issues with the docker-deploy.sh
script.
2
Answers
As pointed out in @derpirscher‘s comment and mine, one of the issues was the permission of your script(s) and the way they should be called as the
ENTRYPOINT
(notCMD
).Consider this alternative code for your Dockerfile :
docker-deploy.sh script :
See this other SO question for more context on the need for the
exec
builtin in a Docker shell entrypoint.Also, note that the fact this
exec ...
command line is written inside a shell script (not directly in anENTRYPOINT / CMD
exec form) is a key ingredient for using the parameter expansion.In other words: in the revision 2 of your question, the
"${DB_HOST}:${DB_PORT}"
argument was understood literally because no shell interpolation occurs in anENTRYPOINT / CMD
exec form.Regarding the docker-compose.yml :
Note that in this Docker setting, the
wait-for-it
host should bepostgres
(the Docker service name of your database), not0.0.0.0
norlocalhost
. Because thewait-for-it
script acts as a client that tries to connect to the specified web service in the ambientdocker-compose
network.For a bit more details on the difference between
0.0.0.0
(a server-side, catch-all special IP) andlocalhost
in a Docker context, see e.g. this other SO answer of mine.(§): last but not least, the
ports: [ "${DB_PORT}:${DB_PORT}" ]
lines should rather be removed because they are not necessary for the Compose services to communicate (the services just need to belong to a common Compose network and use the other Compose services’ hostname), while exposing one such port directly on the host increases the attack surface.Last but not least:
To follow-up this comment of mine, suggesting to run
ls -l docker-deploy.sh; file docker-deploy.sh
in yourmyapp/
directory as a debugging step (BTW: feel free to do this later on then comment for the record):Assuming there might be an unexpected bug in Docker similar to this one as pointed by @Lety:
I’d suggest to just replacing (in the Dockerfile) the line
with
and running directly in a terminal on the host machine:
If this does not work, here is another useful information you may want to provide: what is your OS, and what is your Docker package name? (e.g. docker-ce or podman…)
It’s a bit like in the shell on your computer: You enter the command to execute (just a basename of the command) and the shell tells you if it can’t find it – except it won’t tell you its not withing
$PATH
as it could be (comparehash
utility).Now Docker ain’t a shell and therefore the message is a bit more verbose (and that docker-compose is running docker is also adding in front of it):
So the part of Docker is:
And that is effectively due to the commandment in the Dockerfile:
Whatever the (absolute) path of
docker-deploy.sh
is within the container, the basename of it (docker-deploy.sh
, again) could not be found within the containers environmentPATH
parameter (compare PATH (in), Pathname Resolution, etc.).Use the basename of an executable that is actually in PATH within the container or an absolute (or relative to the containers PWD environment parameter a.k.a. working directory) so that it actually can be executed (by Docker).