Use dockerfile to build npm project - node.js

I have Dockerfile like:
FROM node:10-alpine
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
WORKDIR /home/node/app
COPY package*.json ./
USER node
RUN npm install
COPY --chown=node:node . .
RUN npm run build
I need compiled files on my local drive not in docker container.
VOLUME looks like I need I think, but dunno how to do it, to make the build and share those build files.
can someone help me ? thanks!

Assuming npm run build in your Dockerfile produces a build directory, you can get it locally using a volume indeed
docker build -t <yourcontainername> .
docker run \
-v ${PWD}/build:/home/node/app/build \
-it <yourcontainername>

You can use
docker cp <containerId>:/file/path/within/container /host/path/target

Related

docker USER not getting executed first, why?

FROM alpine:3.10
RUN apk add --update
USER node
RUN mkdir /home/node/code
WORKDIR /home/node/code
COPY --chown=node:node package-lock.json package.json ./
RUN npm ci
COPY --chown=node:node . .
EXPOSE 3000
CMD ["node", "index.js"]
This is my Dockerfile. When I execute this command docker run --init --rm -P --name node-app node-app-apline. I get this error:
=> ERROR [3/7] RUN mkdir /home/node/code
1.3s
------
[3/7] RUN mkdir /home/node/code:
------
executor failed running [/bin/sh -c mkdir /home/node/code]: unable to find user node:
no matching entries in passwd file
The thing is.. somehow or the other the RUN mkdir /home/node/code gets executed. Why?
Is this something to do with cache? I don't know.
PS: I'm new to asking questions, please help me if there is something wrong with my question. Also, I'm new to docker too.

Dockerizing React App but ERR_EMPTY_RESPONSE

I'm trying to turn this nodeJS video game into a docker container:
https://github.com/navignaw/TooManyChefs
But I'm getting "ERR_EMPTY_RESPONSE" when I try to access the started docker container:
http://localhost:3000/
I think the issue is my dockerfile:
# pull official base image
FROM node:13.12.0-alpine
# set working directory
WORKDIR /usr/src/app
ENV PATH /app/node_modules/.bin:$PATH
COPY package*.json ./
RUN npm install
COPY . ./
EXPOSE 3000
CMD ["npm", "start"]
Docker commands:
docker build -t hal/chefs .
docker run -p 3000:3000 -d hal/chefs
Docker logs:
docker logs 92928695b528a7ed4059bcc32af1d58a309f855294b48d49c60a2bb977755c4e
> TooManyChefs# start /usr/src/app
> watchify -o js/bundle.js -v -d js/main.js
Can someone please give advice how I can fix or troubleshoot? I really appreciate your help!
-Hal
change the following line:
ENV PATH /app/node_modules/.bin:$PATH
to :
ENV PATH /usr/src/app/node_modules/.bin:$PATH
Edit-01:
Also update your npm install command to following:
npm install --no-optional && npm cache clean --force

Running gulp in Docker compose - does not create files

I have issues where gulp is not making any files. It says finished, but no file is being created.
If I log in to my docker instance using:
docker exec -t -i myservice-service /bin/bash
and if I run the gulp command, then it creates it properly
Then all the files defined in the gulpfile.js are created. In other words, public/dist/ is populated with the main.js and other css files.
This is my Dockerfile.
FROM node:9
RUN mkdir -p /usr/src/app
RUN mkdir -p /usr/src/logs
WORKDIR /usr/src/app
# GULP Installation
RUN npm install -g gulp
RUN npm install gulp
COPY package*.json /usr/src/app/
COPY .npmrc /usr/src/app/
RUN cd /usr/src/app/ && npm install && npm install -g nodemon
COPY . /usr/src/app
RUN chown -R node:node /usr/src/app && chown -R node:node /usr/src/logs
USER node
EXPOSE 3000
RUN gulp
CMD ["npm", "run-script", "start" ]
And this is my composer file (development):
version: "3"
services:
myservice-service:
build: .
image: myservice-service
container_name: myservice-service
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
environment:
- NODE_ENV=dev
ports:
- 3000:3000
command: nodemon --delay 2 ./bin/www
I run it as:
docker-compose -f docker-compose.development.yml up --build
When I run it like that, it does not create any files. I get the same output on the screen, when I run the command manually.
I have spent hours trying to make it work, I tried with setting permissions and what not, but it just does not work.
My expectation was to have public/dist/ populated with files.
Any help is appreciated.
UPDATE. It works, but I have doubts:
I manage to make it work by using command inside the composerfile itself.
So in my case:
command: bash -c "gulp && nodemon --delay 2 ./bin/www"
In my reasoning, gulp should be done inside the Dockerfile itself, not on the composer files. But then again, it is out of my scope of knowledge.
The Dockerfile is run at build time and will COPY all the files in your local directory into the container, then run gulp and create any files.
You then mount the local folder over the docker containers file system, pretty much overwriting what was done in the docker file with the original files, as gulp ran on the files in the container, it did not effect the original files so you are undoing the changes.
The solutions are either to do as as you have mentioned in your question (add it to the command in docker-compose.yml or run it via docker-compose exec) or write a custom entrypoint script that will run gulp and then the command, something like:
bin/entrypoint.sh
#!/bin/sh
gulp
exec "$#"
Dockerfile
FROM node:9
COPY bin/entrypoint.sh /entrypoint.sh
RUN chmod 755 /entrypoint.sh
RUN mkdir -p /usr/src/app
RUN mkdir -p /usr/src/logs
WORKDIR /usr/src/app
# GULP Installation
RUN npm install -g gulp
RUN npm install gulp
COPY package*.json /usr/src/app/
COPY .npmrc /usr/src/app/
RUN cd /usr/src/app/ && npm install && npm install -g nodemon
COPY . /usr/src/app
RUN chown -R node:node /usr/src/app && chown -R node:node /usr/src/logs
USER node
EXPOSE 3000
ENTRYPOINT ["/entrypoint.sh"]
CMD ["npm", "run-script", "start" ]
This will make your build a little less predictable though as it will run gulp each time the container starts (e.g. after every deployment) if you use the same Dockerfile in dev and production.

Nodemon inside docker container

I'm trying to use nodemon inside docker container:
Dockerfile
FROM node:carbon
RUN npm install -g nodemon
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD [ "nodemon" ]
Build/Run command
docker build -t tag/apt .
docker run -p 49160:8080 -v /local/path/to/apt:/usr/src/app -d tag/apt
Attaching a local volume to the container to watch for changes in code, results in some override and nodemon complains that can't find node modules (any of them). How can I solve this?
In you Dockerfile, you are running npm install after copying your package*json files. A node_modules directory gets correctly created in /usr/src/app and you're good to go.
When you mount your local directory on /usr/src/app, though, the contents of that directory inside your container are overriden with your local version of the node project, which apparently is lacking the node_modules directory, causing the error you are experiencing.
You need to run npm install on the running container after you mounted your directory. For example you could run something like:
docker exec -ti <containername> npm install
Please note that you'll have to temporarily change your CMD instruction to something like:
CMD ["sleep", "3600"]
In order to be able to enter the container.
This will cause a node_modules directory to be created in your local directory and your container should run nodemon correctly (after switching back to your current CMD).
TL;DR: npm install in a sub-folder, while moving the node_modules folder to the root.
Try this config to see and it should help you.
FROM node:carbon
RUN npm install -g nodemon
WORKDIR /usr/src/app
COPY package*.json /usr/src/app/
RUN npm install && mv /usr/src/app/node_modules /node_modules
COPY . /usr/src/app
EXPOSE 8080
CMD [ "nodemon" ]
As the other answer said, even if you have run npm install at your WORKDIR. When you mount the volume, the content of the WORKDIR is replaced by your mount folder temporarily, which the npm install did not run.
As node search its require package in serveral location, a workaround is to move the 'installed' node_modules folder to the root, which is one of its require path.
Doing so you can still update code until you require a new package, which the image needs another build.
I reference the Dockerfile from this docker sample project.
In a Javascript or a Nodejs application when we bind src file using bind volume in a Docker container either using docker command or docker-compose we end up overriding node_modules folder. To overcome this issue you need to use anonymous volume. In an anonymous volume, we provide only the destination folder path as compared to the bind volume where we specify source:destination folder path.
General syntax
--volume <container file system directory absolute path>:<read write access>
An example docker run command
docker container run \
--rm \
--detach \
--publish 3000:3000 \
--name hello-dock-dev \
--volume $(pwd):/home/node/app \
--volume /home/node/app/node_modules \
hello-dock:dev
For further reference you check this handbook by Farhan Hasin Chowdhury
Maybe there's no need to mount the whole project. In this case, I would only mount the directory where I put all the source files, e.g. src/.
This way you won't have any problem with the node_modules/ directory.
Also, if you are using Windows you may need to add the -L (--legacy-watch) option to the nodemon command, as you can see in this issue. So it would be nodemon -L.

Docker - Override content of linked volume

Having simple Node.js docker container
docker-compose.yml:
app:
build: ./dockerfiles/app
volumes:
- /Users/home/work/app:/usr/app
Dockerfile:
FROM node:6.7-slim
COPY package.json /tmp
RUN cd /tmp && npm install
RUN mkdir -p /usr/app
WORKDIR /usr/app
CMD ["node", "./src/app.js"]
What I want to achieve is container where I have package.json and installed node modules (npm install). Part where I copy package.json and install modules inside container is pretty straighforward, but problem occur, when I want to use these node_modules inside linked app. I can't find any way, how to copy /tmp/node_modules into /usr/app/node_modules
Is there any Docker way ho to do that? If not, can I tell my node app to look for node_modules somewhere else than in root directory?
You can achieve what you want by changing the CMD used when starting the container, either in your Dockerfile, or in the docker-compose.yml file.
Instead of just starting node ./src/app.js, you want to do two things:
Copy the node_modules over.
Start Node
Using the docker-compose.yml, I would do the following:
app:
build: ./dockerfiles/app
volumes:
- /Users/home/work/app:/usr/app
command: >
bash -c "
rm -rf /usr/app/node_modules
&& cp -R /tmp/node_modules /usr/app/node_modules
&& node ./src/app.js
"
This will delete the existing node modules on the mapped-in volume, then copy in the ones from container, and then finally starts the node app. This is going to happen every time the container is started.
As #schovi has mentioned in order to not override the contents of node_modules within the container and the contents of node_modules within the folder of the host machine, it is necessary to create another internal volume in the docker-compose.yml file:
volumes:
- ${APP_PATH}:/usr/app
- /usr/app/node_modules
Doing that makes it safe to copy the files from /tmp/node_modules into /usr/app/node_modules using this instructions.
FROM node
# Node modules
COPY *.json /tmp/
RUN cd /tmp && yarn
# App
RUN mkdir -p /usr/app
WORKDIR /usr/app
RUN cp -a /tmp/node_modules /usr/app/node_modules
ENV NODE_ENV docker
CMD ["run-node", "src/app.js"]
However, I would create first the app folder and install node_modules directly on it, reducing considerably the cache layers and increasing the building speed.
FROM node:12.8.1 #always mind the version
# Node modules
RUN mkdir -p /usr/app
WORKDIR /usr/app
#Mind that point (workdir)
COPY package*.json .
RUN yarn
ENV NODE_ENV docker
CMD ["run-node", "src/app.js"]
I hope it helps! :D
Thing that helped me is following usage of volumes
volumes:
- ${APP_PATH}:/usr/app
# Empty node_modules directory
- /usr/app/node_modules
Then in Dockerfile:
FROM node
# Node modules
COPY *.json /tmp/
RUN cd /tmp && yarn
ENV NODE_PATH /tmp/node_modules:${NODE_PATH}
# App
RUN mkdir -p /usr/app
WORKDIR /usr/app
ENV NODE_ENV docker
CMD ["run-node", "src/app.js"]
This allow me to have node_modules in another directory and app will look for them there.

Resources