From 26e73ae33793a85bd14c65dd4f1ddde721896606 Mon Sep 17 00:00:00 2001 From: Sebastien Vanvelthem Date: Tue, 24 Mar 2026 18:40:14 +0100 Subject: [PATCH 1/4] chore: docker examples --- .dockerignore | 45 +++++- .gitignore | 2 +- examples/apps/nextjs-app/docker/.dockerignore | 52 ++++++- examples/apps/nextjs-app/docker/Dockerfile | 21 ++- .../nextjs-app/docker/Dockerfile.distroless | 132 ++++++++++++++++++ .../docker/docker-compose.distroless.yml | 17 +++ examples/apps/nextjs-app/next.config.mjs | 37 ----- 7 files changed, 247 insertions(+), 59 deletions(-) create mode 100644 examples/apps/nextjs-app/docker/Dockerfile.distroless create mode 100644 examples/apps/nextjs-app/docker/docker-compose.distroless.yml diff --git a/.dockerignore b/.dockerignore index 3a2d949a..bed8b6ca 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,10 +1,49 @@ # .dockerignore is used to exclude files and directories from being copied into the Docker image during the build process. This helps to reduce the size of the image and improve build times by only including necessary files. # keep it at the root of the project to ensure that we don't copy unnecessary files into the Docker image. -node_modules -**/.turbo +# git (disable if needed in the container) +.git + +# dependencies +**/node_modules + +# caches **/.cache +**/tsconfig.tsbuildinfo +**/tsconfig.*.tsbuildinfo +**/.eslintcache + +# package managers +**/.yarn/* +!**/.yarn/patches +!**/.yarn/releases +!**/.yarn/plugins +.pnp.* + +# testing +**/coverage +**/.out/ + +# Build directories **/apps/*/.next **/packages/*/dist **/packages/*/docs -**/.eslintcache + +# Misc +.DS_Store +*.pem + +# Debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# IDE +.idea/* +.project +.classpath +*.launch +*.sublime-workspace +.vscode/ + + diff --git a/.gitignore b/.gitignore index ac065e4c..e5f4487b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ _release # Turbo pruned files -out +.turbo-pruned # local env files (following nextjs convention) diff --git a/examples/apps/nextjs-app/docker/.dockerignore b/examples/apps/nextjs-app/docker/.dockerignore index 5fd6ba02..97cf5265 100644 --- a/examples/apps/nextjs-app/docker/.dockerignore +++ b/examples/apps/nextjs-app/docker/.dockerignore @@ -1,10 +1,48 @@ # this file should won't be read unless it exists in the # context directory specified in the docker compose file -node_modules -#**/.turbo -#**/.cache -#**/apps/*/.next -#**/packages/*/dist -#**/packages/*/docs -#**/.eslintcache \ No newline at end of file +# git (disable if needed in the container) +.git + +# dependencies +**/node_modules + +# caches +**/.cache +**/tsconfig.tsbuildinfo +**/tsconfig.*.tsbuildinfo +**/.eslintcache + +# package managers +**/.yarn/* +!**/.yarn/patches +!**/.yarn/releases +!**/.yarn/plugins +.pnp.* + +# testing +**/coverage +**/.out/ + +# Build directories +**/apps/*/.next +**/packages/*/dist +**/packages/*/docs + +# Misc +.DS_Store +*.pem + +# Debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# IDE +.idea/* +.project +.classpath +*.launch +*.sublime-workspace +.vscode/ + diff --git a/examples/apps/nextjs-app/docker/Dockerfile b/examples/apps/nextjs-app/docker/Dockerfile index 17bb0dc6..638ce921 100644 --- a/examples/apps/nextjs-app/docker/Dockerfile +++ b/examples/apps/nextjs-app/docker/Dockerfile @@ -27,7 +27,7 @@ RUN TURBO_VERSION=$(cat package.json | jq '.devDependencies["turbo"]' -r) npm i COPY --link . . # https://turbo.build/repo/docs/handbook/deploying-with-docker -RUN turbo prune --scope=@examples/nextjs-app --docker --out-dir=./out/nextjs-app/ +RUN turbo prune --scope=@examples/nextjs-app --docker --out-dir=./.turbo-pruned/nextjs-app/ ############################################################# # Stage 2 - App installation # @@ -57,8 +57,8 @@ WORKDIR /app # First install the dependencies (as they change less often) COPY --link .gitignore ./ -COPY --from=prepare --link /app/out/nextjs-app/json/ . -COPY --from=prepare --link /app/out/nextjs-app/yarn.lock ./yarn.lock +COPY --from=prepare --link /app/.turbo-pruned/nextjs-app/json/ . +COPY --from=prepare --link /app/.turbo-pruned/nextjs-app/yarn.lock ./yarn.lock # Option 1: run install without cache #RUN yarn install --inline-builds @@ -69,7 +69,7 @@ RUN --mount=type=cache,target=/root/.yarn3-cache,id=yarn3-cache,sharing=locked \ yarn install --inline-builds # Build the project -COPY --link --from=prepare /app/out/nextjs-app/full/ . +COPY --link --from=prepare /app/.turbo-pruned/nextjs-app/full/ . COPY --link .gitignore turbo.jsonc tsconfig.base.json ./ ENV NEXT_BUILD_IGNORE_ESLINT=true @@ -101,20 +101,19 @@ ENV NODE_ENV=production RUN apt-get update \ && apt-get install bash tzdata --no-install-recommends -y \ - && rm -rf /var/cache/apt/* \ + && rm -rf /var/cache/apt/* # If needed, we can enable corepack in the runner as well, but for now we don't need it \ # since we're running the built server.js directly with node. - && npm i -g corepack@${COREPACK_VERSION} && corepack enable + # && npm i -g corepack@${COREPACK_VERSION} && corepack enable WORKDIR /app -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs - # Set the correct permission for prerender cache -RUN mkdir .next -RUN chown nextjs:nodejs .next +RUN addgroup --system --gid 1001 nodejs \ + adduser --system --uid 1001 nextjs \ + mkdir .next \ + chown nextjs:nodejs .next USER nextjs diff --git a/examples/apps/nextjs-app/docker/Dockerfile.distroless b/examples/apps/nextjs-app/docker/Dockerfile.distroless new file mode 100644 index 00000000..adf6d502 --- /dev/null +++ b/examples/apps/nextjs-app/docker/Dockerfile.distroless @@ -0,0 +1,132 @@ +ARG NODE_VERSION=24.14 +ARG DISTROLESS_IMAGE=gcr.io/distroless/nodejs24-debian13 +ARG DEBIAN_VERSION=trixie-slim +ARG COREPACK_VERSION=0.34.6 + + +############################################################# +# Stage 1 - App extraction / pruning # +############################################################# + +FROM node:${NODE_VERSION}-${DEBIAN_VERSION} AS prepare + +RUN apt-get update \ + #&& apt-get install build-essential cmake curl unzip ca-certificates git jq --no-install-recommends -y \ + && apt-get install git jq --no-install-recommends -y \ + && rm -rf /var/cache/apt/* \ + ## Corepack won't be bundled in node 25+ + && npm i -g corepack@${COREPACK_VERSION} && corepack enable + + +WORKDIR /app + +COPY --link package.json turbo.jsonc ./ + +# We can't run turbo without yarn install first, let's install locally and make sure +# both local and docker are aligned on the package.json version. +RUN TURBO_VERSION=$(cat package.json | jq '.devDependencies["turbo"]' -r) npm i -g turbo@${TURBO_VERSION} + +COPY --link . . + +# https://turbo.build/repo/docs/handbook/deploying-with-docker +RUN turbo prune --scope=@examples/nextjs-app --docker --out-dir=./.turbo-pruned/nextjs-app/ + +############################################################# +# Stage 2 - App installation # +############################################################# + +FROM prepare AS builder + +ENV TZ=Etc/UTC + +# Optimize for YARN installation speed +ENV YARN_ENABLE_GLOBAL_CACHE=false +ENV YARN_ENABLE_MIRROR=false +ENV YARN_ENABLE_TELEMETRY=false +ENV YARN_NODE_LINKER=node-modules +ENV YARN_NM_MODE=hardlinks-local +ENV YARN_ENABLE_HARDENED_MODE=0 +ENV YARN_ENABLE_CONSTRAINTS_CHECKS=false +# If using different compression level than in local (recommended: prefer to not do this) +#ENV YARN_COMPRESSION_LEVEL 0 +#ENV YARN_CHECKSUM_BEHAVIOR ignore + +# Disabling some well-known postinstall scripts +ENV PRISMA_SKIP_POSTINSTALL_GENERATE=true +ENV HUSKY=0 + +WORKDIR /app + +# First install the dependencies (as they change less often) +COPY --link .gitignore ./ +COPY --from=prepare --link /app/.turbo-pruned/nextjs-app/json/ . +COPY --from=prepare --link /app/.turbo-pruned/nextjs-app/yarn.lock ./yarn.lock + +# Option 1: run install without cache +#RUN yarn install --inline-builds + +# Option 2: run install with buildx cache mount (buildx) +RUN --mount=type=cache,target=/root/.yarn3-cache,id=yarn3-cache,sharing=locked \ + YARN_CACHE_FOLDER=/root/.yarn3-cache \ + yarn install --inline-builds + +# Build the project +COPY --link --from=prepare /app/.turbo-pruned/nextjs-app/full/ . +COPY --link .gitignore turbo.jsonc tsconfig.base.json ./ + +ENV NEXT_BUILD_IGNORE_ESLINT=true +ENV NEXT_BUILD_IGNORE_TYPECHECK=true +ENV NEXT_BUILD_OUTPUT=standalone +ENV NODE_ENV=production +# ENV NEXT_BUILD_ENV_SENTRY_ENABLED=false +# ENV NEXT_BUILD_ENV_SENTRY_TRACING=false + +RUN yarn workspace @examples/db-sqlserver prisma-generate + +RUN yarn turbo run build --filter=@examples/nextjs-app +# Alternative we can also +#RUN yarn turbo run build --filter=@examples/nextjs-app... + +############################################################# +# Stage 3 - App runner # +############################################################# + +FROM ${DISTROLESS_IMAGE} AS runner + +ARG NEXTJS_APP_PORT + +# Bort PORT / HOSTNAME envs are respected by nextjs start/dev. +ENV HOSTNAME=0.0.0.0 +ENV PORT=${NEXTJS_APP_PORT:-3000} +ENV TZ=Etc/UTC +ENV NODE_ENV=production + +#RUN apt-get update \ +# && apt-get install tzdata --no-install-recommends -y \ +# && rm -rf /var/cache/apt/* + +WORKDIR /app + +#RUN addgroup --system --gid 1001 nodejs +#RUN adduser --system --uid 1001 nextjs + +# Set the correct permission for prerender cache +#RUN mkdir .next +#RUN chown nextjs:nodejs .next + +#USER nextjs + +COPY --from=builder /app/examples/apps/nextjs-app/next.config.mjs \ + /app/examples/apps/nextjs-app/package.json \ + ./ + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder /app/examples/apps/nextjs-app/.next/standalone ./ +COPY --from=builder /app/examples/apps/nextjs-app/.next/static ./examples/apps/nextjs-app/.next/static +COPY --from=builder /app/examples/apps/nextjs-app/public ./examples/apps/nextjs-app/public + +EXPOSE ${PORT} + +CMD ["node", "examples/apps/nextjs-app/server.js"] + diff --git a/examples/apps/nextjs-app/docker/docker-compose.distroless.yml b/examples/apps/nextjs-app/docker/docker-compose.distroless.yml new file mode 100644 index 00000000..f5450deb --- /dev/null +++ b/examples/apps/nextjs-app/docker/docker-compose.distroless.yml @@ -0,0 +1,17 @@ +name: flowblade-example-nextjs +services: + app-distroless: + build: + # Start from root of the monorepo + context: ../../../../ + dockerfile: ./examples/apps/nextjs-app/docker/Dockerfile.distroless + restart: no + networks: + - flowblade-net + ports: + - 3000:3000 + +networks: + flowblade-net: + driver: bridge + enable_ipv6: false diff --git a/examples/apps/nextjs-app/next.config.mjs b/examples/apps/nextjs-app/next.config.mjs index 91e8ea3d..9a58f3f8 100644 --- a/examples/apps/nextjs-app/next.config.mjs +++ b/examples/apps/nextjs-app/next.config.mjs @@ -62,43 +62,6 @@ let nextConfig = { }, }, - /* - turbopack: { - rules: { - '*.wasm': { - loaders: [ - { - loader: 'file-loader', - options: { - esModule: true, - }, - }, - ], - as: '*.js', - }, - }, - }, */ - - /* - webpack: (config, { isServer }) => { - config.module.rules.push({ - test: /\.wasm/, - loader: 'file-loader', - options: {}, - }); - - config.experiments = { - ...config.experiments, - asyncWebAssembly: true, // Enable async WebAssembly support - }; - - // config.module.rules.push({ - // test: /\.wasm$/, - // type: 'asset/resource', // Treat .wasm files as assets - // }); - return config; - }, */ - async headers() { return [ { From 51cfb37efddfa97a162d74a3c3a43d60d8cff237 Mon Sep 17 00:00:00 2001 From: Sebastien Vanvelthem Date: Tue, 24 Mar 2026 18:54:02 +0100 Subject: [PATCH 2/4] chore: docker examples --- examples/apps/nextjs-app/docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/apps/nextjs-app/docker/Dockerfile b/examples/apps/nextjs-app/docker/Dockerfile index 638ce921..84573b80 100644 --- a/examples/apps/nextjs-app/docker/Dockerfile +++ b/examples/apps/nextjs-app/docker/Dockerfile @@ -111,9 +111,9 @@ WORKDIR /app # Set the correct permission for prerender cache RUN addgroup --system --gid 1001 nodejs \ - adduser --system --uid 1001 nextjs \ - mkdir .next \ - chown nextjs:nodejs .next + && adduser --system --uid 1001 nextjs \ + && mkdir .next \ + && chown nextjs:nodejs .next USER nextjs From 9e0761e26fe096bea21bfbb0275da972618af9b3 Mon Sep 17 00:00:00 2001 From: Sebastien Vanvelthem Date: Tue, 24 Mar 2026 18:56:04 +0100 Subject: [PATCH 3/4] chore: docker examples --- .dockerignore | 3 +++ examples/apps/nextjs-app/docker/.dockerignore | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.dockerignore b/.dockerignore index bed8b6ca..83de55cd 100644 --- a/.dockerignore +++ b/.dockerignore @@ -13,6 +13,9 @@ **/tsconfig.*.tsbuildinfo **/.eslintcache +# turbo (comment if you want to copy the turbo cache into the image) +**/.turbo + # package managers **/.yarn/* !**/.yarn/patches diff --git a/examples/apps/nextjs-app/docker/.dockerignore b/examples/apps/nextjs-app/docker/.dockerignore index 97cf5265..a1473d71 100644 --- a/examples/apps/nextjs-app/docker/.dockerignore +++ b/examples/apps/nextjs-app/docker/.dockerignore @@ -13,6 +13,9 @@ **/tsconfig.*.tsbuildinfo **/.eslintcache +# turbo (comment if you want to copy the turbo cache into the image) +**/.turbo + # package managers **/.yarn/* !**/.yarn/patches From 82561f99e0f8900ff81a98b9812b8e61b4c0c611 Mon Sep 17 00:00:00 2001 From: Sebastien Vanvelthem Date: Tue, 24 Mar 2026 18:58:39 +0100 Subject: [PATCH 4/4] chore: docker examples --- examples/apps/nextjs-app/docker/Dockerfile.distroless | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/apps/nextjs-app/docker/Dockerfile.distroless b/examples/apps/nextjs-app/docker/Dockerfile.distroless index adf6d502..abc0b914 100644 --- a/examples/apps/nextjs-app/docker/Dockerfile.distroless +++ b/examples/apps/nextjs-app/docker/Dockerfile.distroless @@ -114,17 +114,18 @@ WORKDIR /app #RUN mkdir .next #RUN chown nextjs:nodejs .next -#USER nextjs +# Default distroless user +USER 65532:65532 COPY --from=builder /app/examples/apps/nextjs-app/next.config.mjs \ - /app/examples/apps/nextjs-app/package.json \ + /app/examples/apps/nextjs-app/package.json --chown=65532:65532 \ ./ # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=builder /app/examples/apps/nextjs-app/.next/standalone ./ -COPY --from=builder /app/examples/apps/nextjs-app/.next/static ./examples/apps/nextjs-app/.next/static -COPY --from=builder /app/examples/apps/nextjs-app/public ./examples/apps/nextjs-app/public +COPY --from=builder --chown=65532:65532 /app/examples/apps/nextjs-app/.next/standalone ./ +COPY --from=builder --chown=65532:65532 /app/examples/apps/nextjs-app/.next/static ./examples/apps/nextjs-app/.next/static +COPY --from=builder --chown=65532:65532 /app/examples/apps/nextjs-app/public ./examples/apps/nextjs-app/public EXPOSE ${PORT}