How do I get node.js “live editing” to work with Docker
My weekend project was to explore Docker and I thought a simple node.js project would be good. By “live edit” I mean I’d like to be able to manipulate files on my host system and (with as little effort as possible) see the Docker container reflect those changes immediately.
The Dockerizing a Node.js web app went smoothly, and then the Googling and thrashing began. I think that I now know the following:
If I use the
ADDmethod noted on the nodejs tutorial, then I can’t have live edit because
ADDis fulfilled completely at
docker build(not at
If I mount the node project’s directory with something like
-v `pwd`:/usr/src/app, then it won’t run because either
node_modulesdoesn’t exist (and the volume is not available at build time to get populated because
docker runargument) or I need to prepopulate
node_modulesin the host’s project directory, which just doesn’t feel right and could have OS compatibility issues.
My mad newbie thrashing can be distilled to three attempts, each with their own drawbacks or apparent failures.
1) The Node.js tutorial using
ADD Works perfectly, but no “live edit”. I have no expectation this should be what I need, but it at least proved I have the basic wiring in place and running.
FROM node:argon # Create app directory RUN mkdir -p /usr/src/app WORKDIR /usr/src/app # Install app dependencies COPY package.json /usr/src/app/ RUN npm install # Bundle app source COPY . /usr/src/app EXPOSE 8080 CMD [ "npm", "start" ]
2) Try building the node dependencies as globals from the Dockerfile. This seemed less cool, but reasonable (since I wouldn’t expect to change dependencies often). However, it also simply didn’t work, which really surprised me.
FROM node:argon RUN npm install -g express WORKDIR /usr/src/app # which will be added via `docker run -v...` EXPOSE 8080
3) Upon build,
ADD only the
package.json to a temporary location and get
node_modules set up, then move that to the host’s project directory, then mount the project’s directory with
-v `pwd`:/usr/src/app. If this would have worked I’d have tried to add
nodemon and would theoretically have what I want. This seemed to me to be by far the most clever and commonsense, but this simply didn’t work. I monkeyed with a few things attempting to fix, including host directory permissions, and had no joy.
FROM node:argon WORKDIR /usr/src/app # Provides cached layer for node_modules ADD package.json /tmp/package.json RUN cd /tmp && npm install RUN cp -a /tmp/node_modules /usr/src/app/ EXPOSE 8080
I suspect there are multiple instances of me not understanding some basic concept, but as I searched around it seemed like there were a lot of different approaches, sometimes complicated by additional project requirements. I was, perhaps foolishly, trying to keep it simple. 🙂
- Running on Mac OS 10.10
- Docker 1.12.0-rc2-beta17 (latest at time of writing)
- Kitematic 0.12.0 (latest at time of writing)
- Node.js 4.4.7 (latest pre-6 at time of writing)
UPDATE: Attempting to pull some of what I’ve tried to learn together, I’ve done the following and had better luck. Now it builds but
docker run -v `pwd`:/usr/src/app -p 49160:8080 -d martink/node-docker3 doesn’t stay running. However, I can “Run” and “Exec” in Kiteomatic and in shell I can see that
node_modules looks good and has been moved into the right place, and I can manually do
node server.js and have joy.
FROM node:argon # Copy over the host's project files COPY . /usr/src/app # This provides a starting point, but will later be overridden by `-v`, I hope # Use this app directory moving forward through this file WORKDIR /usr/src/app # PULL TOGETHER `NODE_MODULES` ## Grab the package.json from the host and copy into `tmp` COPY package.json /tmp/package.json ## Use that to get `node_modules` set up in `tmp` RUN cd /tmp && npm install ## Copy that resulting node_modules into the WORKDIR RUN cp -a /tmp/node_modules /usr/src/app/ EXPOSE 8080
I think my questions might now be whittled down to…
- How do I make
server.jsstart when I run this?
- How do I see “live edits” (possibly start this with
One Solution collect form web for “How do I get node.js “live editing” to work with Docker”
It appears this Dockerfile gets me what I need.
FROM node:argon # Adding `nodemon` as a global so it's available to the `CMD` instruction below RUN npm install -g nodemon # Copy over the host's project files COPY . /usr/src/app # This provides a starting point, but will later be overridden by `docker run -v...` # Use this app directory moving forward through this file WORKDIR /usr/src/app # PREPARE `NODE_MODULES` ## Grab the `package.json` from the host and copy into `tmp` COPY package.json /tmp/package.json ## Use that to get `node_modules` set up RUN cd /tmp && npm install ## Copy that resulting `node_modules` into the WORKDIR RUN cp -a /tmp/node_modules /usr/src/app/ EXPOSE 8080 CMD [ "nodemon", "./server.js" ]
I build this like so:
docker build -t martink/node-docker .
And run it like so:
docker run -v `pwd`:/usr/src/app -p 49160:8080 -d martink/node-docker
- Stays running
- Responds as expected at http://localhost:49160
- Immediately picks up changes to
server.jsmade on the host machine’s file
I’m happy that it seems I have this working. If I’ve any bad practices in there, I’d appreciate feedback. 🙂