Skip to content

improved Dockerfile using multistage to reduce image size #5187

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 77 additions & 12 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,86 @@
FROM node:carbon
# https://blog.hasura.io/an-exhaustive-guide-to-writing-dockerfiles-for-node-js-web-apps-bbee6bd2f3c4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to copy paste the sources of the code you're writing. please remove

# https://codefresh.io/docker-tutorial/node_docker_multistage/

RUN mkdir -p /parse-server
COPY ./ /parse-server/

RUN mkdir -p /parse-server/config
VOLUME /parse-server/config
# ------- Stage 1 - Base ---------
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove useless comments

FROM node:carbon-alpine as base
# apk - https://www.cyberciti.biz/faq/10-alpine-linux-apk-command-examples/
# RUN apk update && apk upgrade && \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why keep those??

# apk add --no-cache git bash
# python make and g++ - add this for bcrypt 3.x

RUN mkdir -p /parse-server/cloud
VOLUME /parse-server/cloud
# ENV, WORKDIR & COPY commands run as USER root
# to change ownership run chown (e.g. chown USER node /parse_server) after every command

# after this refer to workdir using ./
WORKDIR /parse-server

RUN npm install && \
npm run build
# specify multiple volumes in one line - reuse layers during build
VOLUME ["parse-server/config", "parse-server/cloud"]

ENV PORT=1337
# copy all package.json-related files
COPY package.json ./

EXPOSE $PORT

ENTRYPOINT ["npm", "start", "--"]
# ------- Stage 2 - Dependencies ---------
# base image for release stage with only prod dependencies
FROM base AS dependencies
# set npm configs
RUN npm set progress=false && npm config set depth 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the purpose of set depth 0?

There is no affected command: https://docs.npmjs.com/misc/config#depth

# install production packages only
RUN npm install --production


# ------- Stage 3 - Build ---------
FROM dependencies AS build
# install all npm required for build (and testing) - saves build time since prod dependencies are already installed
RUN npm install
# copy all context into WORKDIR (/parse-server) excluding items in .dockerignore
COPY . .
# Need to run build explicitly as npm will not auto run scripts as ROOT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why run as ROOT then? If there's no need, please run unpriviledged

# https://stackoverflow.com/questions/47748075/npm-postinstall-not-running-in-docker
# https://docs.npmjs.com/misc/scripts#user
RUN npm run prepare && npm run postinstall
# list all dir/files - for debugging purposes
# RUN ls -al

# ---- UNIT TESTS AND FLOW LINT in stage 3------
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why keep that if it is not run? We should probably either remove or run the tests

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that the tests depend on a db, so we cannot run them inside Dockerfile.
Also, the tests are already setup to run in Travis CI.
I am just leaving the comments here for future reference, in case someone wants to change this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So please remove it!

# do not run flow through npm - https://github.com/facebook/flow/issues/3649
# RUN apk add --no-cache --repository https://nl.alpinelinux.org/alpine/edge/testing flow
# run unit tests after COPY - any file change will invalidated cached layer and guarantees a new test run
# make sure flow is removed from pretest in package.json
# RUN npm test


# ------- Stage 4 - Release ---------
FROM dependencies AS release
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all in all each layer uses the previous one completely, what's the point then?

# lib is the output from babel in the build step
COPY --from=build /parse-server/lib ./lib
# copy required files listed in package.json -> files
COPY /bin ./bin
COPY /public_html ./public_html
COPY /views ./views
# COPY postinstall.js ./
# COPY PATENTS LICENSE *.md ./
# list all dir/files - for debugging purposes
# RUN ls -al

# capture git_commit in label
ARG GIT_COMMIT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this argument passed by anyone?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LABEL git_commit=$GIT_COMMIT

# run as non-root. USER node is provided with node images
# https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user
USER node

#EXPOSE - informational ony
EXPOSE 1337

# https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/
# start with node, not npm
ENTRYPOINT ["node", "./bin/parse-server", "--"]

# BUILD: docker build -t parse-platform/parse-server:test --build-arg GIT_COMMIT=$(git log -1 --format=%H) .
# RUN (entrypoint sh): sudo docker run --name parse-server --rm -it --entrypoint sh barakbd/parse-server:test
# to stop at a specific steps add --target flag
# sudo docker build --target release -t barakbd/parse-server:test .