From 2c595727d10809b9a948e267969fe3de615022bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahlstr=C3=B6m=20Kalle?= Date: Mon, 15 Jan 2024 03:46:24 +0200 Subject: [PATCH] Docker image build improvements --- .dockerignore | 1 + .env.docker-compose.prod | 9 +++++++++ Dockerfile | 35 +++++++++++------------------------ apps/web/next.config.js | 15 --------------- apps/web/src/middleware.ts | 15 ++++++++++++++- docker-compose.prod.yml | 8 +++++--- 6 files changed, 40 insertions(+), 43 deletions(-) create mode 100644 .env.docker-compose.prod diff --git a/.dockerignore b/.dockerignore index e46dbb6c..6b36f89d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,3 +4,4 @@ npm-debug.log .gitignore *.md dist +uploads/ diff --git a/.env.docker-compose.prod b/.env.docker-compose.prod new file mode 100644 index 00000000..689bb498 --- /dev/null +++ b/.env.docker-compose.prod @@ -0,0 +1,9 @@ +PAYLOAD_DATABASE_URL="mongodb://mongo/payload" +PAYLOAD_SECRET="verysecretkey" +PAYLOAD_REVALIDATION_KEY="veryprivatekey" +PAYLOAD_PORT=3001 + +NEXT_REVALIDATION_KEY="veryprivatekey" + +PUBLIC_FRONTEND_URL="http://localhost:3000" +PUBLIC_SERVER_URL="http://cms:3001" diff --git a/Dockerfile b/Dockerfile index 7701f367..38b90837 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,31 +3,15 @@ ARG NODE_VERSION=20 # Use a specific version of the Node.js Alpine image as the base. Alpine images are minimal and lightweight. FROM node:${NODE_VERSION}-alpine AS base # Update the package list and install libc6-compat. This package is often required for binary Node.js modules. -RUN apk update && apk add --no-cache libc6-compat -ENV PNPM_HOME="/pnpm" -ENV PATH="$PNPM_HOME:$PATH" -RUN corepack enable -RUN pnpm config set store-dir ~/.pnpm-store - -# Set environment variables (copied from .env.example) -# TODO: Figure out a better way to do this -ENV PAYLOAD_DATABASE_URL="mongodb://127.0.0.1:27017/payload" -ENV PAYLOAD_SECRET="verysecretkey" -ENV PAYLOAD_REVALIDATION_KEY="veryprivatekey" -ENV PAYLOAD_PORT=3001 -ENV PAYLOAD_DEVELOPMENT_AUTOLOGIN_EMAIL=root@tietokilta.fi -ENV PAYLOAD_DEVELOPMENT_AUTOLOGIN_PASSWORD=root -ENV PAYLOAD_LOCAL_DEVELOPMENT=true - -ENV NEXT_REVALIDATION_KEY="veryprivatekey" - -ENV PUBLIC_FRONTEND_URL="http://localhost:3000" -ENV PUBLIC_SERVER_URL="http://localhost:3001" - +RUN apk add --no-cache libc6-compat # Setup pnpm and turbo # Start a new stage based on the base image for setting up pnpm (a package manager) and turbo (for monorepo management). FROM base as setup +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable +RUN pnpm config set store-dir ~/.pnpm-store RUN pnpm install --global turbo # Build argument for specifying the project @@ -56,7 +40,7 @@ RUN rm -rf /app/out/full/*/*/node_modules # Build the project using turbo # Start a new stage for building the project. This stage will compile and prepare the project for production. -FROM pruner AS builder +FROM setup AS builder WORKDIR /app # Copy pruned lockfile and package.json files @@ -68,7 +52,7 @@ COPY --from=pruner /app/out/json/ . # Install dependencies for the pruned project # Utilize BuildKit's cache to speed up the dependency installation process. RUN --mount=type=cache,id=pnpm,target=~/.pnpm-store pnpm install -# TODO Readd: --frozen-lockfile when turbo prune is fixed https://github.com/vercel/turbo/issues/3382#issuecomment-1684098542 +# TODO Re-add: --frozen-lockfile when turbo prune is fixed https://github.com/vercel/turbo/issues/3382#issuecomment-1684098542 # Copy pruned source code # Bring in the necessary source code to the builder stage for compilation. @@ -77,13 +61,16 @@ COPY --from=pruner /app/out/full/ . # Build with turbo and prune dev dependencies # Use turbo to build the project, followed by pruning development dependencies to minimize the final image size. RUN turbo build --filter=${PROJECT}... -RUN --mount=type=cache,id=pnpm,target=~/.pnpm-store pnpm prune --prod --no-optional +# NOTE: --no-optional breaks payload webpack build, let's not use it :) +RUN --mount=type=cache,id=pnpm,target=~/.pnpm-store rm -rf node_modules && pnpm install --prod # Remove source files to further reduce the image size, keeping only the compiled output and necessary runtime files. RUN rm -rf ./**/*/src # Final production image # Start the final stage for the production-ready image. FROM base AS runner +#this needs to be here for some reason again, otherwise the WORKDIR command doesn't pick it up +ARG PROJECT=web # Create a non-root user and group for better security. RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nodejs diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 5dd9d9d7..9662fa87 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -1,21 +1,6 @@ /** @type {import("next").NextConfig} */ module.exports = { reactStrictMode: true, - rewrites: () => [ - { - source: "/admin/:path*", - destination: `${process.env.PUBLIC_SERVER_URL}/admin/:path*`, - }, - { - source: "/api/:path*", - destination: `${process.env.PUBLIC_SERVER_URL}/api/:path*`, - }, - // TODO: only for dev: - { - source: "/media/:path*", - destination: `${process.env.PUBLIC_SERVER_URL}/media/:path*`, - }, - ], images: { // TODO: only for dev: remotePatterns: [ diff --git a/apps/web/src/middleware.ts b/apps/web/src/middleware.ts index b00c3076..7afd3e85 100644 --- a/apps/web/src/middleware.ts +++ b/apps/web/src/middleware.ts @@ -2,10 +2,23 @@ import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; export function middleware(request: NextRequest): NextResponse { + const pathname = request.nextUrl.pathname; + if ( + pathname.startsWith("/admin") || + pathname.startsWith("/media") || + pathname.startsWith("/api") + ) { + const destination = new URL(process.env.PUBLIC_SERVER_URL || ""); + const url = request.nextUrl.clone(); + url.host = destination.host; + url.port = destination.port; + url.pathname = pathname; + return NextResponse.rewrite(url); + } return NextResponse.redirect( new URL(`/fi/${request.nextUrl.pathname}`, request.url), ); } export const config = { - matcher: ["/((?!_next|api|media|admin|fi|en).*)"], + matcher: ["/((?!_next|fi|en).*)"], }; diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index f2bf7207..921b8160 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -20,7 +20,7 @@ services: depends_on: - mongo env_file: - - .env + - .env.docker-compose.prod expose: - 3001 @@ -30,11 +30,13 @@ services: args: - PROJECT=web depends_on: - - mongo + - cms env_file: - - .env + - .env.docker-compose.prod expose: - 3000 + ports: + - 3000:3000 volumes: data: