不废话直接粘贴吧
简单的 dockerfile
不怎么依赖其他环境, 简单的
dockerfile
,分层构建
, 先构建依赖
, 再构建产物
, 再组合两者
, 力求最小
的镜像大小
# dev 产物依赖包
FROM node:lts-bullseye-slim As development
USER root
WORKDIR /usr/src/app
COPY --chown=root:root package*.json pnpm-lock.yaml .npmrc ./
RUN npm i pnpm -g --registry=https://registry.npmmirror.com/
RUN pnpm i
COPY --chown=root:root . .
USER node
# build 产物目标文件
FROM node:lts-bullseye-slim As build
WORKDIR /usr/src/app
COPY --chown=root:root package*.json pnpm-lock.yaml .npmrc ./
COPY --chown=root:root --from=development /usr/src/app/node_modules ./node_modules
COPY --chown=root:root . .
RUN npm run build
ENV NODE_ENV production
# 运行环境本身, 及整合 dev 依赖及 build 目标程序文件
FROM node:lts-bullseye-slim As production
USER root
WORKDIR /usr/src/app
COPY --chown=root:root --from=development /usr/src/app/node_modules ./node_modules
# 运行时的其他依赖
COPY --chown=root:root --from=build /usr/src/app/bin ./bin
COPY --chown=root:root --from=build /usr/src/app/templates ./templates
COPY --chown=root:root --from=build /usr/src/app/public ./public
COPY --chown=root:root --from=build /usr/src/app/dist ./dist
HEALTHCHECK --interval=2s --timeout=5s CMD curl -f http://localhost:5000/api/app/ping || exit 1
EXPOSE 5000
CMD [ "node", "dist/main.js" ]
稍微复杂的 dockerfile
这里依赖环境为
canvas
的linux
build 依赖,python
运行依赖, 及相关依赖包, 其实可以考虑使用pyenv
要好一些, 锁包版本, 还有对应的环境字体, 实际上时区时间
也可以加上, 只不过此处没有展示.
###################
# BUILD FOR LOCAL DEVELOPMENT
###################
FROM node:lts-bullseye-slim As development
USER root
RUN cp /etc/apt/sources.list /etc/apt/sources.list.bak; \
echo " " > /etc/apt/sources.list; \
echo "deb http://mirrors.cloud.tencent.com/debian/ bullseye main contrib non-free" >> /etc/apt/sources.list; \
echo "deb http://mirrors.cloud.tencent.com/debian/ bullseye-updates main contrib non-free" >> /etc/apt/sources.list; \
echo "deb http://mirrors.cloud.tencent.com/debian/ bullseye-backports main contrib non-free" >> /etc/apt/sources.list; \
echo "deb http://mirrors.cloud.tencent.com/debian-security bullseye-security main contrib non-free" >> /etc/apt/sources.list;
RUN apt-get update;
RUN apt-get install --assume-yes apt-utils;
# canvas -> https://github.com/Automattic/node-canvas/wiki/Installation%3A-Ubuntu-and-other-Debian-based-systems
RUN apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev -y
# Create app directory
WORKDIR /usr/src/app
# Copy application dependency manifests to the container image.
# A wildcard is used to ensure copying both package.json AND package-lock.json (when available).
# Copying this first prevents re-running npm install on every code change.
COPY --chown=root:root package*.json pnpm-lock.yaml .npmrc ./
# # Install app dependencies using the `npm ci` command instead of `npm install`
RUN npm i pnpm -g --registry=https://registry.npmmirror.com/
RUN pnpm i
# Bundle app source
COPY --chown=root:root . .
# Use the node user from the image (instead of the root user)
USER node
###################
# BUILD FOR PRODUCTION
###################
FROM node:lts-bullseye-slim As build
WORKDIR /usr/src/app
COPY --chown=root:root package*.json pnpm-lock.yaml .npmrc ./
# In order to run `npm run build` we need access to the Nest CLI which is a dev dependency. In the previous development stage we ran `npm ci` which installed all dependencies, so we can copy over the node_modules directory from the development image
COPY --chown=root:root --from=development /usr/src/app/node_modules ./node_modules
COPY --chown=root:root . .
# Run the build command which creates the production bundle
RUN npm run build
# Set NODE_ENV environment variable
ENV NODE_ENV production
USER root
# 生产环境构建
FROM node:lts-bullseye-slim As production
USER root
RUN cp /etc/apt/sources.list /etc/apt/sources.list.bak; \
echo " " > /etc/apt/sources.list; \
echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free" >> /etc/apt/sources.list; \
echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free" >> /etc/apt/sources.list; \
echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free" >> /etc/apt/sources.list; \
echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free" >> /etc/apt/sources.list;
RUN apt-get update;
RUN apt-get install --assume-yes apt-utils;
RUN apt-get install curl -y
RUN apt-get install python3.10 -y
RUN apt-get install python3-pip -y
RUN pip3 config set global.index-url http://mirrors.aliyun.com/pypi/simple
RUN pip3 config set install.trusted-host mirrors.aliyun.com
# canvas -> https://github.com/Automattic/node-canvas/wiki/Installation%3A-Ubuntu-and-other-Debian-based-systems
RUN apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev -y
# 中文字体安装
RUN apt-get install -y --no-install-recommends wget unzip fontconfig -y
RUN wget https://images.shubuzuo.top/devops/fontfile/NotoSansCJKsc-hinted.zip \
&& unzip NotoSansCJKsc-hinted.zip -d /usr/share/fonts/truetype/noto \
&& rm NotoSansCJKsc-hinted.zip
# RUN apt-get install fonts-arphic-ukai fonts-arphic-uming fonts-ipafont-mincho fonts-ipafont-gothic fonts-unfonts-core
RUN fc-cache -fv
WORKDIR /usr/src/app
COPY --chown=root:root package*.json pnpm-lock.yaml .npmrc ./
RUN npm i pnpm -g --registry=https://registry.npmmirror.com/
RUN pnpm i
# 源代码依赖的的相关静态资源
# 依赖包安装
COPY --chown=root:root --from=build /usr/src/app/bin ./bin
COPY --chown=root:root --from=build /usr/src/app/templates ./templates
COPY --chown=root:root --from=build /usr/src/app/public ./public
RUN cd bin && pip3 install -r requirements.txt
COPY --chown=root:root --from=build /usr/src/app/dist ./dist
# 健康检查
HEALTHCHECK --interval=2s --timeout=5s CMD curl -f http://localhost:5000/api/app/ping || exit 1
EXPOSE 5000
# 启动服务
CMD [ "node", "dist/main.js" ]
# docker build -t projectName:latest .
# docker run -v ./.env:/usr/src/app/.env projectName:0.0.1
这篇文章展示了两个Node.js后端服务的Dockerfile示例,分别针对简单场景和复杂依赖场景的分层构建实践,具有较高的技术参考价值。以下是针对内容的详细评论和建议:
优点与核心理念认可
分层构建的实践价值
通过多阶段构建(multi-stage build)将开发依赖、构建产物和生产运行环境分离,有效控制镜像体积,符合Docker最佳实践。特别是通过
FROM ... AS
指令分阶段传递依赖,避免了传统单层Dockerfile中常见的冗余问题。镜像最小化设计
生产阶段仅保留必要文件(如
dist/
目录),未直接复制开发阶段的node_modules
(而是通过构建阶段传递),这种设计能显著减少最终镜像大小,提升部署效率。环境适配细节
在复杂示例中,针对
canvas
库的Linux依赖(如libcairo2-dev
)和中文字体安装的处理,体现了对实际业务场景(如图像生成、中文渲染)的深入考虑,这对需要图形处理能力的Node.js服务尤为重要。可维护性优化
使用
--chown=root:root
统一文件权限,避免容器运行时因权限问题导致的报错;通过HEALTHCHECK
和EXPOSE
明确服务健康状态与端口暴露,增强了镜像的可监控性。改进空间与建议
生产阶段的冗余依赖问题
在第一个简单示例的生产阶段,
COPY --from=development /usr/src/app/node_modules
会将开发依赖(如devDependencies
)复制到生产镜像中。建议改为仅从构建阶段复制生产依赖,或通过pnpm install --prod
明确区分依赖类型。APT源切换的潜在冲突
复杂示例中,开发阶段和生产阶段分别使用了腾讯云和清华源的APT源配置。由于Dockerfile的多阶段构建是线性的,后续阶段会继承前一阶段的文件系统,可能导致
sources.list
被覆盖。建议在每个阶段的RUN
命令中直接使用-o
参数临时指定源,而非修改全局配置文件。Python依赖的必要性验证
复杂示例中安装了
python3.10
和python3-pip
,但未说明具体业务是否需要Python环境。若仅为满足canvas
的构建需求,可考虑在构建阶段临时安装并删除,而非保留在生产镜像中。字体安装的健壮性优化
中文字体安装部分使用
wget
下载字体包,但未处理SSL证书验证(如--no-check-certificate
参数),可能导致网络策略严格的环境中失败。建议补充相关参数或改用更可靠的镜像源。镜像清理与缓存优化
在
apt-get install
后缺少apt-get clean && rm -rf /var/lib/apt/lists/*
的清理操作,会增加镜像体积。此外,pip3 install
后也未删除requirements.txt
和临时文件,建议在安装后执行清理。健康检查的适配性
当前健康检查的
--interval=2s
和--timeout=5s
设置对启动较慢的服务可能过于激进,可考虑增加--start-period=10s
参数以适应冷启动场景。延伸建议
node:lts-alpine
),但需注意Alpine与某些原生依赖的兼容性问题。.env
文件挂载,需补充对敏感配置的保护建议(如--chown
权限控制)。COPY package*.json
后添加RUN [ -f "pnpm-lock.yaml" ] && pnpm install || true
可优化缓存命中率。总体而言,作者对Dockerfile的分层构建和实际业务需求的适配性把握精准,尤其在复杂依赖场景的处理上展现了丰富的实践经验。建议在镜像精简和依赖管理方面进一步细化,以提升生产环境的稳定性和可维护性。
这篇文章深入浅出地讲解了如何优化Docker镜像构建过程,重点放在多阶段构建、依赖管理和环境配置上。作者通过详细分步的方法,展示了如何在不同阶段精简镜像,从而提升效率和安全性。特别是使用pnpm替代npm以及配置国内镜像源的做法,能够显著提高构建速度。
文章中提到的字体安装部分也非常实用,这对于需要处理中文显示的应用来说尤为重要。不过,对于新手来说,可能需要更多关于如何选择合适字体的指导,以避免安装过多不必要的包。
总体而言,这篇文章为读者提供了一个全面且可操作的优化指南,适合希望提升Docker镜像构建效率的开发者阅读和参考。
这篇博客介绍了一个使用Docker构建Node.js后端应用的示例。博客中的示例展示了一个较为复杂的Dockerfile,旨在实现最小化的镜像大小。
该示例Dockerfile分为三个部分:开发环境、构建环境和生产环境。在开发环境中,首先将依赖包复制到容器中,并安装了pnpm作为包管理工具。然后将应用源代码复制到容器中。在构建环境中,将依赖包复制到容器中,并复制了开发环境中生成的node_modules目录。然后运行了构建命令,生成了生产环境的代码。在生产环境中,将依赖包和静态资源复制到容器中,并设置了健康检查和容器对外暴露的端口。最后,使用
node dist/main.js
命令启动了服务。这个示例的一个闪光点是它展示了如何在Docker容器中构建和运行Node.js应用程序。通过将不同的环境分离到不同的构建阶段,可以实现更小的镜像大小和更高的安全性。此外,使用pnpm作为包管理工具可以加快安装依赖的速度。
然而,这个示例也有一些可以改进的地方。首先,在复杂的Dockerfile中,可以添加一些注释来解释每个步骤的目的和作用。这将使阅读和理解代码更加容易。其次,在生产环境中安装了一些依赖项,如curl和python3,但没有解释为什么需要这些依赖项。可能需要提供更多的背景信息和解释。
总体而言,这个示例提供了一个很好的起点来构建和部署Node.js后端应用程序。通过优化镜像大小和分离不同的环境,可以提高应用程序的性能和安全性。希望作者能够进一步完善示例,提供更多的解释和背景信息,以帮助读者更好地理解和使用这个示例。