From 632420a0a5921800fb158fe6e9b002b2526bbf70 Mon Sep 17 00:00:00 2001 From: Boris Bera Date: Fri, 7 Oct 2022 12:19:55 -0400 Subject: [PATCH 1/6] Use RUN --mount=type=cache,... in example backend dockerfile Signed-off-by: Boris Bera --- packages/backend/Dockerfile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index 21ff07deb4..8e0d711cd3 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -13,9 +13,10 @@ FROM node:16-bullseye-slim # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, # in which case you should also move better-sqlite3 to "devDependencies" in package.json. -RUN apt-get update && \ +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update && \ apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \ - rm -rf /var/lib/apt/lists/* && \ yarn config set python /usr/bin/python3 # From here on we use the least-privileged `node` user to run the backend. @@ -38,7 +39,8 @@ COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz # Note that this install is not immutable, which is one of the reasons we don't recommend Yarn 3 yet -RUN yarn workspaces focus --all --production && rm -rf "$(yarn cache clean)" +RUN --mount=type=cache,uid=1000,gid=1000,target=/home/node/.yarn/berry/cache,sharing=locked \ + yarn workspaces focus --all --production # Then copy the rest of the backend bundle, along with any other files we might want. COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./ From 74801d277cafbeffb121211c2ff14d185465d424 Mon Sep 17 00:00:00 2001 From: Boris Bera Date: Tue, 11 Oct 2022 05:47:12 -0400 Subject: [PATCH 2/6] Use RUN --mount in Host build dockerfile Signed-off-by: Boris Bera --- docs/deployment/docker.md | 8 +++++--- .../templates/default-app/packages/backend/Dockerfile | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index d35e7dd593..f809b3794b 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -61,9 +61,10 @@ FROM node:16-bullseye-slim # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, # in which case you should also move better-sqlite3 to "devDependencies" in package.json. -RUN apt-get update && \ +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update && \ apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \ - rm -rf /var/lib/apt/lists/* && \ yarn config set python /usr/bin/python3 # From here on we use the least-privileged `node` user to run the backend. @@ -79,7 +80,8 @@ ENV NODE_ENV production COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz -RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" +RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \ + yarn install --frozen-lockfile --production --network-timeout 300000 # Then copy the rest of the backend bundle, along with any other files we might want. COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./ diff --git a/packages/create-app/templates/default-app/packages/backend/Dockerfile b/packages/create-app/templates/default-app/packages/backend/Dockerfile index 682798b826..3e9ca5ba48 100644 --- a/packages/create-app/templates/default-app/packages/backend/Dockerfile +++ b/packages/create-app/templates/default-app/packages/backend/Dockerfile @@ -13,9 +13,10 @@ FROM node:16-bullseye-slim # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, # in which case you should also move better-sqlite3 to "devDependencies" in package.json. -RUN apt-get update && \ +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update && \ apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \ - rm -rf /var/lib/apt/lists/* && \ yarn config set python /usr/bin/python3 # From here on we use the least-privileged `node` user to run the backend. @@ -31,7 +32,8 @@ ENV NODE_ENV production COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz -RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" +RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \ + yarn install --frozen-lockfile --production --network-timeout 300000 # Then copy the rest of the backend bundle, along with any other files we might want. COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./ From 463aa5422b7808ff21403b4b2a0012d597e378f8 Mon Sep 17 00:00:00 2001 From: Boris Bera Date: Tue, 11 Oct 2022 06:50:16 -0400 Subject: [PATCH 3/6] Optimize the multi-stage build docker image Signed-off-by: Boris Bera --- docs/deployment/docker.md | 44 +++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index f809b3794b..1cd351c2bc 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -165,53 +165,64 @@ RUN find packages \! -name "package.json" -mindepth 2 -maxdepth 2 -exec rm -rf { # Stage 2 - Install dependencies and build packages FROM node:16-bullseye-slim AS build -WORKDIR /app -COPY --from=packages /app . - # install sqlite3 dependencies -RUN apt-get update && \ +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update && \ apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \ yarn config set python /usr/bin/python3 -RUN yarn install --frozen-lockfile --network-timeout 600000 && rm -rf "$(yarn cache dir)" +USER node +WORKDIR /app -COPY . . +COPY --from=packages --chown=node:node /app . + +# Stop cypress from downloading it's massive binary. +ENV CYPRESS_INSTALL_BINARY=0 +RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \ + yarn install --frozen-lockfile --network-timeout 600000 + +COPY --chown=node:node . . RUN yarn tsc RUN yarn --cwd packages/backend build # If you have not yet migrated to package roles, use the following command instead: # RUN yarn --cwd packages/backend backstage-cli backend:bundle --build-dependencies +RUN mkdir packages/backend/dist/skeleton packages/backend/dist/bundle \ + && tar xzf packages/backend/dist/skeleton.tar.gz -C packages/backend/dist/skeleton \ + && tar xzf packages/backend/dist/bundle.tar.gz -C packages/backend/dist/bundle + # Stage 3 - Build the actual backend image and install production dependencies FROM node:16-bullseye-slim # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, # in which case you should also move better-sqlite3 to "devDependencies" in package.json. -RUN apt-get update && \ +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update && \ apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \ - rm -rf /var/lib/apt/lists/* && \ yarn config set python /usr/bin/python3 # From here on we use the least-privileged `node` user to run the backend. USER node WORKDIR /app -# This switches many Node.js dependencies to production mode. -ENV NODE_ENV production - # Copy the install dependencies from the build stage and context -COPY --from=build --chown=node:node /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton.tar.gz ./ -RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz +COPY --from=build --chown=node:node /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton/ ./ -RUN yarn install --frozen-lockfile --production --network-timeout 600000 && rm -rf "$(yarn cache dir)" +RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \ + yarn install --frozen-lockfile --production --network-timeout 600000 # Copy the built packages from the build stage -COPY --from=build --chown=node:node /app/packages/backend/dist/bundle.tar.gz . -RUN tar xzf bundle.tar.gz && rm bundle.tar.gz +COPY --from=build --chown=node:node /app/packages/backend/dist/bundle/ ./ # Copy any other files that we need at runtime COPY --chown=node:node app-config.yaml ./ +# This switches many Node.js dependencies to production mode. +ENV NODE_ENV production + CMD ["node", "packages/backend", "--config", "app-config.yaml"] ``` @@ -227,6 +238,7 @@ however ignore any existing build output or dependencies on the host. For our new `.dockerignore`, replace the contents of your existing one with this: ```text +dist-types node_modules packages/*/dist packages/*/node_modules From f87680543e592e50bb60cd5bba20b623270a7567 Mon Sep 17 00:00:00 2001 From: Boris Bera Date: Tue, 11 Oct 2022 06:51:43 -0400 Subject: [PATCH 4/6] Set uid= & gid= at the end of RUN --mount This is strictly to match up with the rest of those statements in the codebase Signed-off-by: Boris Bera --- packages/backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index 8e0d711cd3..60c6ffd27f 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -39,7 +39,7 @@ COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz # Note that this install is not immutable, which is one of the reasons we don't recommend Yarn 3 yet -RUN --mount=type=cache,uid=1000,gid=1000,target=/home/node/.yarn/berry/cache,sharing=locked \ +RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,sharing=locked,uid=1000,gid=1000 \ yarn workspaces focus --all --production # Then copy the rest of the backend bundle, along with any other files we might want. From 01dff06be456c0b01d22f98befa0725826875936 Mon Sep 17 00:00:00 2001 From: Boris Bera Date: Tue, 11 Oct 2022 07:47:48 -0400 Subject: [PATCH 5/6] Add changeset for cache mounts in dockerfile Signed-off-by: Boris Bera --- .changeset/short-plants-return.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/short-plants-return.md diff --git a/.changeset/short-plants-return.md b/.changeset/short-plants-return.md new file mode 100644 index 0000000000..3afdc81ceb --- /dev/null +++ b/.changeset/short-plants-return.md @@ -0,0 +1,6 @@ +--- +'example-backend': patch +'@backstage/create-app': patch +--- + +Leverage cache mounts in Dockerfile during `yarn install ...` and `apt-get ...` commands to speed up repeated builds. From 44c52b298ceff115fb0321193ac02260058f986a Mon Sep 17 00:00:00 2001 From: Boris Bera Date: Tue, 11 Oct 2022 09:47:45 -0400 Subject: [PATCH 6/6] Remove un-neccessary changeset for example-backend Signed-off-by: Boris Bera --- .changeset/short-plants-return.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/short-plants-return.md b/.changeset/short-plants-return.md index 3afdc81ceb..0a4974c38a 100644 --- a/.changeset/short-plants-return.md +++ b/.changeset/short-plants-return.md @@ -1,5 +1,4 @@ --- -'example-backend': patch '@backstage/create-app': patch ---