version: "1.0.0"
services:
########################################################################################################
############################################# VALIDLY #################################################
########################################################################################################
validly-studio:
build:
context: ./studio
dockerfile: Dockerfile
volumes:
- type: bind
source: ./studio
target: /app
- /app/node_modules
restart: unless-stopped
ports:
- 3000:3000
networks:
- validly
networks:
validly:
above is my docker-compose.yml file
FROM node:16.14-alpine
# set working directory
WORKDIR /app
# install app dependencies
COPY package.json ./
COPY package-lock.json ./
RUN npm install
# add app
COPY . ./
# start app
CMD ["npm", "start"]
this is my Dockerfile.
docker builds the react app and it prompts me to goto localhost:3000 where the app is running. But when I goto localhost:3000. I shows connection refused.
In your Dockerfile you copy in folder App everything to app/
And in your docker-compose you map /app to /app/node_modules.
This will not work.
Choose 1 of the two, and my instinct (and many error in the past) tell me that you should build everything in Dockerfile, including copying node_modules, and don't touch it in docker-compose.
Dockerfile
Template Dockerfile for React: (this one with NextJS environment, which makes it only more complex)
# Dependencies Container
FROM node:lts-alpine3.12 AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Here we create node_modules
COPY package.json ./
COPY package-lock.json ./
RUN npm install -g npm#7.24.0 --no-update-notifier
RUN npm --version
RUN npm ci --no-update-notifier
# Rebuild the source code only when needed
FROM node:lts-alpine3.12 AS builder
WORKDIR /app
COPY . .
# Here we copy node_modules from previous intermediate container
COPY --from=deps /app/node_modules ./node_modules
RUN npm install -g npm#7.24.0 --no-update-notifier
RUN npm --version
RUN node -v
RUN npm run build --no-update-notifier
# Production Image
FROM node:16-bullseye AS runner
WORKDIR /app
ENV NODE_ENV production
# Here we only copy. No building needed, keeps the image small.
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/package-lock.json ./package-lock.json
RUN addgroup -gid 1001 nodejs
RUN adduser -uid 1002 nextjs
RUN adduser nextjs nodejs
RUN chown -R nextjs:nodejs /app/.next
USER nextjs
docker-compose.yml
Here a template docker-compose.yml using the above Dockerfile
version: "3.9"
services:
webshop:
build:
context: ./build
dockerfile: Dockerfile_webshop
image: mywebshop
restart: "no"
container_name: MyWebshop
command: ["npm", "start"]
As you see, no volumes needed.
it's my first time using Docker let alone docker-compose.
Could I get some insight on my docker-compose file to help me get both docker containers up and running.
Folder Structure
Both of my Dockerfiles work for running each application ( React or Flask ) separately. For example:
React Container
docker build -t wedding-client .
docker run -dp 3030:3030 wedding-client
Flask Container
docker build -t wedding-server .
docker run -dp 5030:5030 wedding-server
So I'm thinking my docker-compose file is the issue. Here are the docker files:
client/DockerFile
FROM node:alpine as build
WORKDIR /app
COPY . /app
RUN npm install
RUN npm run build
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
COPY --from=build /app/build .
COPY nginx/nginx.conf /etc/nginx/conf.d
EXPOSE 3030
CMD ["nginx", "-g", "daemon off;"]
server/DockerFile
FROM python:3.9
WORKDIR /app
COPY . /app
RUN pip install -r requirements.txt
ENV FLASK_APP server.py
EXPOSE 5030
CMD ["python", "server.py"]
docker-compose.yml
version: '3'
services:
server:
container_name: wedding-server
build:
context: server/
dockerfile: Dockerfile
network_mode: host
ports:
- 5030:5030
client:
container_name: wedding-client
build:
context: client/
dockerfile: Dockerfile
network_mode: host
ports:
- 3030:3030
depends_on:
- server
Docker Output:
Client Docker File
# Stage 0, "build-stage", based on Node.js to build the frontend
FROM node:alpine as build
WORKDIR /app
COPY package*.json /app/
RUN npm install
COPY . /app/
RUN npm run build
# Stage 1, based on NGINX to provide a configuration to be used with react-router
FROM nginx:alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY --from=build /app/build /usr/share/nginx/html
COPY ./nginx/nginx.conf /etc/nginx/conf.d
# RUN apk update && apk add bash
EXPOSE 3005
CMD ["nginx", "-g", "daemon off;"]
Flask Docker File
FROM python:3.9
RUN mkdir /server
WORKDIR /server
COPY requirements.txt /server/requirements.txt
RUN pip install --upgrade pip && \
pip install -r requirements.txt
COPY . .
docker-compose.yml
version: '3'
services:
api:
build: server
command: "flask run --host=0.0.0.0 --port=5005"
environment:
- FLASK_ENV=production
- FLASK_APP=server.py
ports:
- "5005:5005"
client:
build: client
ports:
- '3005:3005'
links:
- api
depends_on:
- api
I am trying to serve my mern stack app using nginx in production. I have a Dockerfile:
# build environment
FROM node:13.12.0-alpine as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
RUN npm install
COPY . ./
RUN npm run build
# production environment
FROM nginx:stable-alpine
COPY --from=build app/dist/ /usr/share/nginx/html
# new
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
a docker-compose.yml:
version: '3.7'
services:
web:
container_name: web
build:
context: .
dockerfile: Dockerfile
volumes:
- '.:/app'
- '/app/node_modules'
ports:
- 3001:3000
environment:
- CHOKIDAR_USEPOLLING=true
depends_on:
- mongo
mongo:
image: mongo
volumes:
- data:/data/db
ports:
- "27017:27017"
volumes:
node_modules:
data:
and this is my scripts portion of my package.json
"scripts": {
"development": "nodemon",
"build": "webpack --config webpack.config.client.production.js && webpack --mode=production --config webpack.config.server.js",
"start": "NODE_ENV=production node ./dist/server.generated.js"
},
However when I start the container only docker-compose logs are for mongo and nginx only shows the default page.
This is my nginx.conf
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Note: this setup works when I used create react app (only I replaced dist by build). This project is using server side rendering. I don't know what I am doing wrong but I would sure appreciate any thoughts. The project is located here: https://github.com/smeyerhot/mern-market the only difference is the docker-compose, Dockerfile and nginx/nginx.conf files.
Actually, you try to serve a nodejs app and not a static app. It's why you don't need the nginx server.
I think you should change the Dockerfile for:
FROM node:13.12.0-alpine as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
RUN npm install
COPY . ./
RUN npm run build
CMD npm run start
The only problem here it's that you will have all the build dependencies on your image.
For a react app with .env:
REACT_APP_ENV_VAR_1=A
REACT_APP_ENV_VAR_2=B
Customizing an environnement variable through docker-compose.yml doesn't alter its default value:
services:
front:
image: "react-app-image"
environment:
- REACT_APP_ENV_VAR_2=C
.env variable could be used in the react app:
let env_var_2 = process.env.REACT_APP_ENV_VAR_2;
Is there a way to directly access docker-compose ENV from react app or to map .env entries with docker ENV ?
Front Dockerfile for building react app image
FROM node:13.12.0-alpine as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
COPY package-lock.json ./
RUN npm ci --silent
RUN npm install react-scripts#3.4.1 -g --silent
COPY . ./
RUN npm run build
FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
I was wondering if anyone had any experience using create-react-app with docker. I was able to get it set up with a Dockerfile like:
from node
RUN mkdir /src
WORKDIR /src
ADD package.json /src/package.json
RUN npm install
EXPOSE 3000
CMD [ "npm", "start" ]
And then used a docker-compose file like:
app:
volumes:
- "./app:/src"
ports:
- "3000:3000"
- "35729:35729"
build: ./app
This allowed me to start up the container and view the app. However livereload didn't work when saving files in the mounted volume and webpack created several .json.gzip files in the src directory.
Any suggestions for getting this working correctly?
Yeah, as aholbreich mentioned, I'd use npm install / npm start locally on my machine for development, just because it's so easy. It's probably possible with docker-compose, mounting volumes etc. too, but I think it could be a bit fiddly to set up.
For deployment you can then very easily use a Dockerfile. Here's an example Dockerfile I'm using:
FROM node:6.9
# Create app directory
RUN mkdir -p /src/app
WORKDIR /src/app
# to make npm test run only once non-interactively
ENV CI=true
# Install app dependencies
COPY package.json /src/app/
RUN npm install && \
npm install -g pushstate-server
# Bundle app source
COPY . /src/app
# Build and optimize react app
RUN npm run build
EXPOSE 9000
# defined in package.json
CMD [ "npm", "run", "start:prod" ]
You need to add the start:prod option to your package.json:
"scripts": {
"start": "react-scripts start",
"start:prod": "pushstate-server build",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
You can run the tests on your CI service with:
docker run <image> npm test
There's nothing stopping you from running this docker container locally as well to make sure things work as expected.
I recently made a small project called hello-docker-react who just does what the op is looking for.
It's made with docker-compose, create-react-app, yarn, a node image, and a small entrypoint script.
Live reload work flawlessly and I haven't found any problems yet.
https://github.com/lopezator/hello-docker-react
here is good gide for this
https://mherman.org/blog/dockerizing-a-react-app/
for development
# base image
FROM node:9.6.1
# set working directory
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
# add `/usr/src/app/node_modules/.bin` to $PATH
ENV PATH /usr/src/app/node_modules/.bin:$PATH
# install and cache app dependencies
COPY package.json /usr/src/app/package.json
RUN npm install --silent
RUN npm install react-scripts#1.1.1 -g --silent
# start app
CMD ["npm", "start"]
for production
# build environment
FROM node:9.6.1 as builder
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
ENV PATH /usr/src/app/node_modules/.bin:$PATH
COPY package.json /usr/src/app/package.json
RUN npm install --silent
RUN npm install react-scripts#1.1.1 -g --silent
COPY . /usr/src/app
RUN npm run build
# production environment
FROM nginx:1.13.9-alpine
COPY --from=builder /usr/src/app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Not exactly a direct improvement of the author's code, but I was able to get a development environment working with very little code - and no direct dependency to node on my machine - like this:
docker-compose.yml
services:
node:
image: node:16
user: "node"
command: "npm start"
working_dir: /app
volumes:
- ./:/app
ports:
- 3000:3000
This way, you avoid creating docker images from a Dockerfile.
Usage is generally like this:
install dependencies before running: docker compose run node npm install
run development environment: docker compose up
install new dependencies: docker compose run node npm install [package name]
clean up docker instances created with compose run: docker compose rm
While using docker in development with create-react-app, i discovered that it is possible to override the webpackDevServer configuration by adding CHOKIDAR_USEPOLLING=1to your .env file. This will make the file watching work again. It even refreshes the browser page on the host! The only thing that i discovered is that it doesn't open up a webpage automatically.
I can also advise to add tty: true to your service to have your original console output back into your terminal. To remove the container name prefixes in the logs, you can run something like this after running docker-compose up -d:
docker-compose logs -f --tail=100 client | cut -f2 -d \"|\""
Running with CRA 4.0 and many dependencies
.dockerignore
.git
.gitignore
node_modules
build
Dockerfile.dev
FROM node:alpine
WORKDIR /app
COPY package.json /app
RUN yarn install
COPY . .
CMD ["yarn", "start"]
docker-compose.dev.yml
version: "3.8"
services:
print:
stdin_open: true
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- ".:/app"
- "/app/node_modules"
Dockerfile.prod
FROM node:alpine as build
WORKDIR /app
COPY package.json /app
RUN yarn install
COPY . /app
RUN yarn run build
FROM nginx:stable-alpine
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/build /usr/share/nginx/html
docker-compose.prod.yml
version: "3.8"
services:
print:
stdin_open: true
build:
context: .
dockerfile: Dockerfile.prod
ports:
- "80:80"
nginx.conf
server {
listen 80;
server_name frontend;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri /index.html;
}
}
To run
docker-compose.exe -f .\docker-compose.yml up --build
or
docker-compose.exe -f .\docker-compose.dev.yml up --build
Here is a simple (pure docker) solution without local installation of runtime (e.g. node):
cd /tmp
docker run -it --rm -v "$PWD":/app -w /app node yarn create react-app my-app
sudo chown -R $USER:root my-app/
cd my-app
nano docker-compose.yml # see docker-compose.yml below
docker compose up -d
docker-compose.yml:
services:
node:
image: node:16-alpine
environment:
- CHOKIDAR_USEPOLLING=true
- FAST_REFRESH=true
working_dir: /app
ports:
- '3000:3000'
command: "yarn start"
volumes:
- './:/app'
open localhost:3000 in your browser. Hot reload should work out of the box.