Skip to content

Commit

Permalink
build(docker): only install prod deps to speed up
Browse files Browse the repository at this point in the history
Signed-off-by: Rongrong <[email protected]>
  • Loading branch information
Rongronggg9 committed Apr 26, 2022
1 parent af8e685 commit a1bfdbd
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ app.json
app-minimal
.idea
.env
.editorconfig
Procfile
now.json
jsconfig.json
package-lock.json

#git but keep the git commit hash
.git/logs
Expand Down
66 changes: 48 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ FROM node:14-buster-slim as dep-builder

WORKDIR /app

# placing ARG statement before RUN statement which need it to avoid cache miss
# place ARG statement before RUN statement which need it to avoid cache miss
ARG USE_CHINA_NPM_REGISTRY=0
RUN \
set -ex && \
Expand All @@ -24,37 +24,68 @@ RUN \
npm config set registry https://registry.npmmirror.com; \
fi;

COPY ./yarn.lock /app
COPY ./package.json /app
COPY ./yarn.lock /app/
COPY ./package.json /app/

# lazy install Chromium to avoid cache miss
# lazy install Chromium to avoid cache miss, only install production dependencies to minimize the image size
RUN \
set -ex && \
export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true && \
yarn --frozen-lockfile --network-timeout 1000000 && \
yarn install --production --frozen-lockfile --network-timeout 1000000 && \
yarn cache clean

COPY . /app
RUN node scripts/docker/minify-docker.js


FROM debian:buster-slim as puppeteer-version-parser
FROM debian:buster-slim as dep-version-parser
# This stage is necessary to limit the cache miss scope.
# With this stage, any modification to package.json won't break the build cache of the next stage as long as the version
# of puppeteer unchanged.
# With this stage, any modification to package.json won't break the build cache of the next two stages as long as the
# version unchanged.
# node:14-buster-slim is based on debian:buster-slim so this stage would not cause any additional download.

WORKDIR /app
COPY ./package.json /app
RUN grep -Po '(?<="puppeteer": ")[^\s"]*(?=")' package.json | tee .puppeteer_version
WORKDIR /ver
COPY ./package.json /app/
RUN \
set -ex && \
grep -Po '(?<="puppeteer": ")[^\s"]*(?=")' /app/package.json | tee /ver/.puppeteer_version && \
grep -Po '(?<="@vercel/nft": ")[^\s"]*(?=")' /app/package.json | tee /ver/.nft_version && \
grep -Po '(?<="fs-extra": ")[^\s"]*(?=")' /app/package.json | tee /ver/.fs_extra_version


FROM node:14-buster-slim as docker-minifier
# The stage is used to further reduce the image size by removing unused files.

WORKDIR /minifier
COPY --from=dep-version-parser /ver/* /minifier/

ARG USE_CHINA_NPM_REGISTRY=0
RUN \
set -ex && \
if [ "$USE_CHINA_NPM_REGISTRY" = 1 ]; then \
npm config set registry https://registry.npmmirror.com; \
fi; \
yarn add @vercel/nft@$(cat .nft_version) fs-extra@$(cat .fs_extra_version) && \
yarn cache clean

COPY . /app
COPY --from=dep-builder /app /app

RUN \
set -ex && \
cp /app/scripts/docker/minify-docker.js /minifier/ && \
export PROJECT_ROOT=/app && \
node /minifier/minify-docker.js && \
rm -rf /app/node_modules /app/scripts && \
cp -r /app/app-minimal/node_modules /app/ && \
rm -rf /app/app-minimal && \
ls -la /app && \
du -hd1 /app


FROM node:14-buster-slim as chromium-downloader
# This stage is necessary to improve build concurrency and minimize the image size.
# Yeah, downloading Chromium never need those dependencies below.
# Yeah, downloading Chromium never needs those dependencies below.

WORKDIR /app
COPY --from=puppeteer-version-parser /app/.puppeteer_version /app/.puppeteer_version
COPY --from=dep-version-parser /ver/.puppeteer_version /app/.puppeteer_version

ARG USE_CHINA_NPM_REGISTRY=0
ARG PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
Expand Down Expand Up @@ -103,8 +134,7 @@ RUN \
rm -rf /var/lib/apt/lists/*

COPY --from=chromium-downloader /app/node_modules/puppeteer /app/node_modules/puppeteer
COPY --from=dep-builder /app/app-minimal/node_modules /app/node_modules
COPY . /app
COPY --from=docker-minifier /app /app

EXPOSE 1200
ENTRYPOINT ["dumb-init", "--"]
Expand Down
22 changes: 15 additions & 7 deletions scripts/docker/minify-docker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@
const fs = require('fs-extra');
const path = require('path');
const { nodeFileTrace } = require('@vercel/nft');
const files = ['lib/index.js', 'api/now.js'];
const resultFolder = 'app-minimal';
// !!! if any new dependencies are added, update the Dockerfile !!!

const projectRoot = path.resolve(process.env.PROJECT_ROOT || path.join(__dirname, '../..'));
const resultFolder = path.join(projectRoot, 'app-minimal'); // no need to resolve, ProjectRoot is always absolute
const files = ['lib/index.js', 'api/now.js'].map((file) => path.join(projectRoot, file));

(async () => {
console.log('Start analyizing...');
console.log('Start analyzing, project root:', projectRoot);
const { fileList: fileSet } = await nodeFileTrace(files, {
base: path.resolve(path.join(__dirname, '../..')),
base: projectRoot,
});
let fileList = Array.from(fileSet);
console.log('Total touchable files:', fileList.length);
fileList = fileList.filter((file) => file.startsWith('node_modules/')); // only need node_modules
console.log('Total files need to be copied (touchable files in node_modules/): ', fileList.length);
return Promise.all(fileList.map((e) => fs.copy(e, path.resolve(path.join(resultFolder, e)))));
})();
console.log('Total files need to be copied (touchable files in node_modules/):', fileList.length);
console.log('Start copying files, destination:', resultFolder);
return Promise.all(fileList.map((e) => fs.copy(path.join(projectRoot, e), path.join(resultFolder, e))));
})().catch((err) => {
// fix unhandled promise rejections
console.error(err, err.stack);
process.exit(1);
});

0 comments on commit a1bfdbd

Please sign in to comment.