I trying to reduce the time take to build a docker image to react app,
the react should be static without server rendering.
now it takes around 5-10 minute to create an image and the image size on the local machine is around 1.5GB !!, the issue is that also after the second time of image creation, even I changed smth in the code it doesn't use any cache
I am looking for a solution to cut the time the size and here is my docker File after lot of changes
# Producation and dev build
FROM node:14.2.0-alpine3.10 AS test1
RUN apk update
RUN apk add \
build-base \
libtool \
autoconf \
automake \
jq \
openssh \
libexecinfo-dev
ADD package.json package-lock.json /app/
# set working directory
WORKDIR /app
# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH
# install app dependencies
COPY package.json ./
COPY package-lock.json ./
ADD . /app/
RUN rm -rf node_modules
RUN npm install --production
# copy production node_modules aside, to prevent collecting them
RUN cp -R node_modules prod_node_modules
# install ALL node_modules, including 'devDependencies'
RUN npm install
RUN npm install react-scripts#3.4.1 -g --silent
RUN npm run build
RUN rm -rf node_modules
RUN cp -R prod_node_modules node_modules
#FROM node:13.14.0
FROM test1
# copy app sources
COPY --from=test1 /app/build .
COPY --from=test1 /app/env-config.js .
# serve is what we use to run the web application
RUN npm install -g serve
# remove the sources & other needless stuff
RUN rm -rf ./src
RUN rm -rf ./prod_node_modules
# Add bash
RUN apk add --no-cache bash
CMD ["/bin/bash", "-c", "serve -s build"]
You're hitting two basic dynamics here. The first is that your image contains a pretty large amount of build-time content, including at least some parts of a C toolchain; since your run-time "stage" is built FROM the build stage as is, it brings all of the build toolchain along with it. The second is that each RUN command produces a new Docker layer with differences from the previous layer, so RUN commands only make the container larger. More specifically RUN rm -rf ... makes the image slightly larger and does not result in space savings.
You can use a multi-stage build to improve this. Each FROM line causes docker build to start over from some specified base image, and you can COPY --from=... previous build stages. I'd do this in two stages, a first stage that builds the application and a second stage that runs it.
# Build stage:
FROM node:14.2.0-alpine3.10 AS build
# Install OS-level dependencies (including C toolchain)
RUN apk update \
&& apk add \
build-base \
libtool \
autoconf \
automake \
jq \
openssh \
libexecinfo-dev
# set working directory
WORKDIR /app
# install app dependencies
# (copy _just_ the package.json here so Docker layer caching works)
COPY package.json package-lock.json ./
RUN npm install
# build the application
COPY . ./
RUN npm run build
# Final stage:
FROM node:14.2.0-alpine3.10
# set working directory
WORKDIR /app
# install dependencies
COPY package.json package-lock.json ./
RUN npm install --production
# get the build tree
COPY --from=build /app/build/ ./build/
# explain how to run the application
ENTRYPOINT ["npx"]
CMD ["serve", "-g", "build"]
Note that when we get to the second stage, we run npm install --production on a clean Node installation; we don't try to shuffle back and forth between dev and prod dependencies. Rather than trying to RUN rm -rf src, we just don't COPY it into the final image.
This also requires making sure you have a .dockerignore file that contains node_modules (which will reduce build times and avoid some potential conflicts; RUN npm install will recreate it in the directory). If you need react-scripts or serve those should be listed in your package.json file.
Related
I am testing a JavaScript app that is hung up on an 'invalid ELF header'.
A wide open search finds multiple solutions.
Suggested solutions (in no particular order:)
add .dockerignore
add node_modules
install npm
rm -rf node_modules
add bcrypt("*") to package.json
npm install --global
npm
install -g node#6.17.1
use nvm to install node.js and npm
npm rebuild bcryptjs / bcrypt.js
npm rebuild bcrypt --build-from-source
rm -rf node_modules
Trying them at random has not helped. I am using a Jelastic platform to run a server.js app that was built in Eclipse on Windows 10. The app worked in localhost. So, I expected it to run in a Jelastic environment. But, I have exhausted vendor support for ERR_DLopen_FAILED.
Most of the time, I have to run a clean build of my React Native project.
Currently I'm using this command: cd android && ./gradlew clean to clean gradle.
Is there a command to clean gradle, delete node_modules and watchman watches?
try to run the following command inside the terminal of your project's root directory.
watchman watch-del-all && rm -rf node_modules/ && yarn install && react-native start --reset-cache"
I was writing a Dockerfile and i have concatenated several RUN instructions into one for proper caching but i realised one of the RUN instruction having --no-cache. Could you please advise how the caching will work here.
RUN go mod download \
&& apk update --no-cache \
&& apk add git \
&& CGO_ENABLED=0 go build -o golang-sdk .
The apk update --no-cache does not make sense. Strike it and modify the git install to
RUN apk add git --no-cache \
&& go mod download \
&& CGO_ENABLED=0 go build -o golang-sdk .
Even better: do a two stage build:
FROM golang:latest AS build
WORKDIR /go/src/github.com/you/project/
RUN [yourstuff]
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /usr/local/bin
COPY --from=build /go/src/github.com/you/project/app .
CMD ["/usr/local/bin/app"]
This way, you can do all the stuff you like while building without needing to think about image sizes, and have the smallest possible image for app.
I have a yarn workspaces project which looks something like this:
node_modules
packages
shared
test.js
package.json
client
test.js
package.json
server
test.js
package.json
package.json
server.Dockerfile
As you can see, I have a server.Dockerfile, which builds an image of the server that I can push up to different hosting providers such as Heroku or AWS.
I copy packages and package.json into this container:
COPY packages packages
COPY package.json .
And I then install only the dependencies for the server package:
RUN cd packages/server && yarn install
All the dependencies are now in the node_modules folder, and the next thing I think of doing is to delete the packages folder to remove any unnecessary code from the docker image (e.g. the client code):
RUN rm -rf packages
The problem with this is that all the yarn workspace packages inside the node_modules folder are simply symlinks to the packages folder... so I cannot delete that folder.
How do I get yarn install to make a copy of the yarn workspace packages instead of creating symlinks?
Or, is there another way to remove all of the unused code (e.g. the client code) so that my docker image isn't bloated?
You can use yarn-workspace-isolator to extract the package with its local dependencies to avoid publishing them to npm if you don't want to.
isolate-workspace -w my-package -o ~/dist/my-package
Now, as the doc saying:
You can simply run yarn install inside of ~/dist/my-package and yarn will
install all dependencies as if you had not used workspaces at all
without having to publish any workspace dependency.
Running yarn install in workspaces does the same thing inside any package or the root directory. It installs the modules for every package and symlinks them etc.
If you want to build a docker image for just the server you should only copy that package into the container and install that as an independent package.
If the server has a dependency on the shared lib, you could publish it to npm so it can fetch it too.
I have created an image from the following Dockerfile.
FROM alpine
WORKDIR /usr/src/app
RUN apk add nodejs-current
RUN apk add nodejs-npm
RUN npm install pm2 -g
COPY process.yaml .
CMD pm2 start process.yaml --no-daemon --log-date-format 'DD-MM
HH:mm:ss.SSS'
process.yaml looks like this:
- script: ./run-services.sh
watch : false
But run-services.sh does not run in my docker. What is the problem?
The problem is that in alpine the bash is not installed by default. pm2 runs bash scripts files by bash command. so there is two way to solve the problem:
Changing default pm2 interpreter from bash to /bin/sh
- script: ./run-services.sh
interpreter: /bin/sh
watch : false
Installing bash in alpine. So the Dockerfile changes as following:
FROM alpine
RUN apk update && apk add bash
WORKDIR /usr/src/app
RUN apk add nodejs-current
RUN apk add nodejs-npm
RUN npm install pm2 -g
COPY process.yaml .
CMD pm2 start process.yaml --no-daemon --log-date-format 'DD-MM
HH:mm:ss.SSS'