After spending hours to make it happen, I just can't make it work. I'm desperate for help as I couldn't find any questions related to my issue.
I've developed a Node.js web app for my university. IT department needs me to prepare a Docker image shared on a Docker Hub (although I chose Github Packages) and a docker-compose file so it can be easily run. I tried to host the app on my Raspberry Pi, but when I pull the image (with docker-compose.yaml, Dockerfile and .env present) it fails during build process:
npm ERR! enoent ENOENT: no such file or directory, open '/usr/src/app/package.json'
and during compose up process:
pi@raspberrypi:~/projects $ docker-compose up
Starting mysql ... done
Starting backend ... done
Attaching to mysql, backend
backend | exec /usr/local/bin/docker-entrypoint.sh: exec format error
mysql | 2022-09-22 08:04:47 00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.30-1.el8 started.
mysql | 2022-09-22 08:04:48 00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
mysql | 2022-09-22 08:04:48 00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.30-1.el8 started.
mysql | '/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
backend exited with code 1
I executed bash inside my Docker container (on my dev machine) so I'm sure that /usr/src/app folder structure matches my app folder structure.
What's wrong with my solution? Should I provide more files than just docker-compose.yaml, Dockerfile and .env?
Dockerfile:
FROM node:18-alpine
WORKDIR /usr/src/app
COPY . ./
RUN npm i && npm cache clean --force
RUN npm run build
ENV NODE_ENV production
CMD [ "node", "dist/main.js" ]
EXPOSE ${PORT}
docker-compose.yaml:
version: "3.9"
services:
backend:
command: npm run start:prod
container_name: backend
build:
context: .
dockerfile: Dockerfile
image: ghcr.io/rkn-put/web-app/docker-backend/test
ports:
- ${PORT}:${PORT}
depends_on:
- mysql
environment:
- NODE_ENV=${NODE_ENV}
- PORT=${PORT}
- ORIGIN=${ORIGIN}
- DB_HOST=${DB_HOST}
- DB_PORT=${DB_PORT}
- DB_NAME=${DB_NAME}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
- DB_SYNCHRONIZE=${DB_SYNCHRONIZE}
- EXPIRES_IN=${EXPIRES_IN}
- SECRET=${SECRET}
- GMAIL_USER=${GMAIL_USER}
- GMAIL_CLIENT_ID=${GMAIL_CLIENT_ID}
- GMAIL_CLIENT_SECRET=${GMAIL_CLIENT_SECRET}
- GMAIL_REFRESH_TOKEN=${GMAIL_REFRESH_TOKEN}
- GMAIL_ACCESS_TOKEN=${GMAIL_ACCESS_TOKEN}
mysql:
image: mysql:latest
container_name: mysql
hostname: mysql
restart: always
ports:
- ${DB_PORT}:${DB_PORT}
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${DB_NAME}
- MYSQL_USER=${DB_USERNAME}
- MYSQL_PASSWORD=${DB_PASSWORD}
volumes:
- ./mysql:/var/lib/mysql
cap_add:
- SYS_NICE
CodePudding user response:
Even if this is not a clear solution, there are multiple things that you should fix (and understand) and then things should work.
You say: "but when I pull the image (with docker-compose.yaml, Dockerfile and .env present) it fails during build process". This is actually where the biggest confusion happens. If you pull, there should be no build anymore.
You build locally, you push with docker-compose push
and the image that you have in Github is ready to use. Because of this, on the target machine (where you want to run the project) you don't need to build any more - therefor you don't need a Dockerfile anymore.
The docker-compose.yml that you deliver should not have the build
section for your app. Only the image name so that docker-compose knows where to pull the image from.
In local (your development environment) you should have the same docker-compose.yml
without the build
section, but also a file docker-compose.override.yml
that should look like:
version: "3.9"
services:
backend:
build:
context: .
docker-compose automatically merges docker-compose.yml
and docker-compose.override.yml
when it finds the second one. That's also why it is important to not deliver the override file.
Only this should make your application work on the target machine. Remember all you need there is docker-compose.yml (no build section) and the .env
.
Other points that you might want to address:
dockerfile: Dockerfile
- not needed since that is the defaultcommand: npm run start:prod
if you overwrite it, why not just put it this way in the Dockerfile? If you have a good reason to do this then leave itEXPOSE ${PORT}
you are not declaringPORT
anywhere in your Dockerfile. Just make your run on port 80 and expose port 80.- read the docs and save yourself some typing. if the env variables have the same names as in
.env
then docker-compose is clever enough to pick them if you only declare them - don't expose mysql ports on host:
${DB_PORT}:${DB_PORT}
- consider using a volume for mysql instead of a folder. If you use a folder maybe place is in a different location so that you don't delete it by mistake