Vite SSR 项目 Docker 镜像最小化打包方案

以云看科技2024-09-02 14:43:55  98

最近准备把部署在 Cloudfalre, Vercel, Netlify 上的项目迁移到自己的 VPS 通过 Docker 运行,就复习了一下 Docker 镜像打包。 但是一个很小的项目打包出来就是 1.05GB, 这显然是不能接受的。所以研究了一下 Node.JS 项目 Docker 镜像最小化打包方案, 将镜像大小从 1.06GB 缩小到了 135 MB。

示例项目是一个 Astro 项目, 使用 Vite 作为构建工具, SSR 模式运行。

第 0 版

主要思路是使用最小化系统镜像,选用 Alpine Linux 镜像。

按照 Astro 官方文档服务端渲染模式(SSR), 将基础镜像替换为 node:lts-alpine, NPM 替换为 PNPM, 打包出来的体积是 1.06 GB。 也就是最差的状态。

FROM node:lts-alpine AS baseENV PNPM_HOME="/pnpm"ENV PATH="$PNPM_HOME:$PATH"RUN corepack enableWORKDIR /appCOPY . .RUN pnpm install --frozen-lockfileRUN export $(cat .env.example) && pnpm run buildENV HOST=0.0.0.0ENV PORT=4321EXPOSE 4321CMD node ./dist/server/entry.mjsCopydocker build -t v0 .[+] Building 113.8s (11/11) FINISHED docker:orbstack => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 346B 0.0s => [internal] load metadata for docker.io/library/node:lts-alpine 1.1s => [internal] load .dockerignore 0.0s => => transferring context: 89B 0.0s => [1/6] FROM docker.io/library/node:lts-alpine@sha256:1a526b97cace6b4006256570efa1a29cd1fe4b96a5301f8d48e87c5139438a45 0.0s => [internal] load build context 0.2s => => transferring context: 240.11kB 0.2s => CACHED [2/6] RUN corepack enable 0.0s => CACHED [3/6] WORKDIR /app 0.0s => [4/6] COPY . . 2.0s => [5/6] RUN pnpm install --frozen-lockfile 85.7s => [6/6] RUN export $(cat .env.example) && pnpm run build 11.1s => exporting to image 13.4s => => exporting layers 13.4s => => writing image sha256:653236defcbb8d99d83dc550f1deb55e48b49d7925a295049806ebac8c104d4a 0.0s => => naming to docker.io/library/v0Copy

第 1 版

主要思路是先安装生产环境依赖,产生第一层。 再安装全量依赖,打包生成 JavaScript 产物,产生第二层。 最后将生产环境依赖和 JavaScript 产物复制到运行环境。

按照 多层构建(使用 SSR) 的方案, 将镜像大小缩小到了 306MB,缩小不小,但是这个方案有个缺点,需要明确的制定生产依赖,如果少指定了生产依赖,运行时会报错

FROM node:lts-alpine AS baseENV PNPM_HOME="/pnpm"ENV PATH="$PNPM_HOME:$PATH"RUN corepack enableWORKDIR /appCOPY package.json pnpm-lock.yaml ./FROM base AS prod-depsRUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfileFROM base AS build-depsRUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfileFROM build-deps AS buildCOPY . .RUN export $(cat .env.example) && pnpm run buildFROM base AS runtimeCOPY --from=prod-deps /app/node_modules ./node_modulesCOPY --from=build /app/dist ./distENV HOST=0.0.0.0ENV PORT=4321EXPOSE 4321CMD node ./dist/server/entry.mjsCopydocker build -t v1 .[+] Building 85.5s (15/15) FINISHED docker:orbstack => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 680B 0.0s => [internal] load metadata for docker.io/library/node:lts-alpine 1.8s => [internal] load .dockerignore 0.0s => => transferring context: 89B 0.0s => [base 1/4] FROM docker.io/library/node:lts-alpine@sha256:1a526b97cace6b4006256570efa1a29cd1fe4b96a5301f8d48e87c5139438a45 0.0s => [internal] load build context 0.3s => => transferring context: 240.44kB 0.2s => CACHED [base 2/4] RUN corepack enable 0.0s => CACHED [base 3/4] WORKDIR /app 0.0s => [base 4/4] COPY package.json pnpm-lock.yaml ./ 0.2s => [prod-deps 1/1] RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile 35.1s => [build-deps 1/1] RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile 65.5s => [runtime 1/2] COPY --from=prod-deps /app/node_modules ./node_modules 5.9s => [build 1/2] COPY . . 0.8s => [build 2/2] RUN export $(cat .env.example) && pnpm run build 7.5s => [runtime 2/2] COPY --from=build /app/dist ./dist 0.1s => exporting to image 4.2s => => exporting layers 4.1s => => writing image sha256:8ae6b2bddf0a7ac5f8ad45e6abb7d36a633e384cf476e45fb9132bdf70ed0c5f 0.0s => => naming to docker.io/library/v1Copy

第 2 版

主要思路是将 node_modules 内联进 JavaScript 文件,最终只复制 JavaScript 文件到运行环境。

之前看 Next.JS 的时候,记得可以将 node_modules 内联进 JavaScript 文件,这样就不需要 node_modules 了。 所以就研究了一下,发现 Vite SSR 也是支持的,所以判断 Docker 环境就使用内联的方式,不需要复制 node_modules ,只复制最终的 dist 产物,将镜像大小缩小到 135MB 了。

打包脚本改动:

vite: { ssr: { noExternal: process.env.DOCKER ? !!process.env.DOCKER : undefined; }}Copy

最终的 Dockerfile 如下

FROM node:lts-alpine AS baseENV PNPM_HOME="/pnpm"ENV PATH="$PNPM_HOME:$PATH"RUN corepack enableWORKDIR /appCOPY package.json pnpm-lock.yaml ./# FROM base AS prod-deps# RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfileFROM base AS build-depsRUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfileFROM build-deps AS buildCOPY . .RUN export $(cat .env.example) && export DOCKER=true && pnpm run buildFROM base AS runtime# COPY --from=prod-deps /app/node_modules ./node_modulesCOPY --from=build /app/dist ./distENV HOST=0.0.0.0ENV PORT=4321EXPOSE 4321CMD node ./dist/server/entry.mjsCopy docker build -t v2 .[+] Building 24.9s (13/13) FINISHED docker:orbstack => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 708B 0.0s => [internal] load metadata for docker.io/library/node:lts-alpine 1.7s => [internal] load .dockerignore 0.0s => => transferring context: 89B 0.0s => [base 1/4] FROM docker.io/library/node:lts-alpine@sha256:1a526b97cace6b4006256570efa1a29cd1fe4b96a5301f8d48e87c5139438a45 0.0s => [internal] load build context 0.3s => => transferring context: 240.47kB 0.2s => CACHED [base 2/4] RUN corepack enable 0.0s => CACHED [base 3/4] WORKDIR /app 0.0s => CACHED [base 4/4] COPY package.json pnpm-lock.yaml ./ 0.0s => CACHED [build-deps 1/1] RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile 0.0s => [build 1/2] COPY . . 1.5s => [build 2/2] RUN export $(cat .env.example) && export DOCKER=true && pnpm run build 15.0s => [runtime 1/1] COPY --from=build /app/dist ./dist 0.1s => exporting to image 0.1s => => exporting layers 0.1s => => writing image sha256:0ed5c10162d1faf4208f5ea999fbcd133374acc0e682404c8b05220b38fd1eaf 0.0s => => naming to docker.io/library/v2Copy

最终对比,体积从 1.06GB 降低到 135MB, 构建时间从 113.8s 降低到 24.9s

docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEv2 latest 0ed5c10162d1 5 minutes ago 135MBv1 latest 8ae6b2bddf0a 6 minutes ago 306MBv0 latest 653236defcbb 11 minutes ago 1.06GBCopy

示例项目是开源的,可以在 GitHub 查看。

https://github.com/ccbikai/BroadcastChannel/pkgs/container/broadcastchannel

作者:面条实验室

转载此文是出于传递更多信息目的。若来源标注错误或侵犯了您的合法权益,请与本站联系,我们将及时更正、删除、谢谢。
https://www.414w.com/read/1154736.html
0
最新回复(0)