I'm new to docker and I have a express server folder with package.json and a client folder with package.json. I have seen many tutorials out there where they have 2 separate images/containers one client and one server. They both have the same WORKDIR
WORKDIR /app
COPY ["package.json", "package-lock.json", "./"]
Does this not override one package.json with the other seen as they are in the same WORKDIR ?
My head is spinning reading different tutorials. Can someone set me straight here.
This was one of the tutorials I was following which has the same WORKDIR for both client and server https://towardsdatascience.com/deploying-a-react-nodejs-application-with-docker-part-i-of-ii-910bc6edb46e
CodePudding user response:
Think of images as templates for a system and containers as instances of those templates.
If you and I both bought brand new computers from the same manufacturer, same OS, etc, would /app
on mine be the same /app
on yours? The answer is of course no.
The WORKDIR
is just a directory. It can be helpful if the system you're creating requires known paths but you can name it literally anything you want, with the exception that you wouldn't want to copy your app files into a system directory like /etc
, /usr
, etc.
To address the Express / React app you're building, I would recommend the following multi-stage Dockerfile
to produce a single, production-ised image
## Build stage
FROM node:16-alpine AS build
ENV NODE_ENV=production
WORKDIR /client
COPY client/package*.json ./
RUN npm install
COPY client ./
RUN npm run build
## App stage
FROM node:16-alpine AS app
ENV NODE_ENV=production
WORKDIR /app
COPY server/package*.json ./
RUN npm install
COPY server ./
# Copy the built React app into your static files dir, eg "public"
COPY --from=build /client/build ./public
RUN npm start
For local development, if you want to use Docker I'd recommend this compose setup
# dev.Dockerfile
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
CMD npm start
# docker-compose.yml
version: '3.8'
services:
client:
build:
context: ./client
dockerfile: ../dev.Dockerfile
volumes:
- "./client:/app"
- "/app/node_modules" # don't overwrite node_modules
ports:
- "3000:3000" # adjust accordingly
server:
build:
context: ./server
dockerfile: ../dev.Dockerfile
volumes:
- "./server:/app"
- "/app/node_modules"
ports:
- "5000:5000" # adjust accordingly
Make sure you proxy requests from your React app to the server. In client/package.json
, add
"proxy": "http://server:5000"
See this answer to help understand the differences between development and production modes for such an application.
To run it, you simply execute
docker compose up
Then open http://localhost:3000
in your browser. Thanks to the proxy
config in dev
and having Express serve the files statically in prod, the React app can make requests to your Express API using path-only URLs, eg
axios.post("/api/login", { username, password });