背景介绍
Node.js是一个基于 Chrome V8 引擎的 JavaScript 运行时环境,以其事件驱动、非阻塞 I/O 模型而闻名,广泛用于构建后端服务和前端应用。
Node.js 的特点使其非常适合容器化部署:
- 轻量级运行时:相比传统后端语言,占用资源更少
- 包管理系统:通过 npm 或 yarn 高效管理依赖
- 异步非阻塞:天然适合高并发应用场景
- 全栈开发:同一语言编写前后端,降低开发门槛
容器化 Node.js 应用需要特别关注以下几个方面:
- 依赖管理:npm 或 yarn 的缓存和依赖安装策略
- 环境隔离:开发、测试和生产环境的配置区分
- 安全考量:避免使用 root 用户运行应用
- 应用类型:区分不同应用类型的构建和部署方式
我们将遵循标准化的多阶段构建思想,为两种常见的 Node.js 应用场景创建优化、安全且高效的 Docker 镜像:
- 后端服务 (SSR 或 API): 通常基于 Express, Koa, NestJS 等框架,需要 Node.js 运行时环境
- 前端应用 (CSR 构建): 使用 React, Vue, Angular 等框架构建出静态文件,最终由 Nginx 托管
构建 Node 工具镜像
Node 工具环境负责提供完整的 Node.js 运行时和开发工具链,用于开发、测试和构建 Node.js 应用。
创建 Node 工具环境目录
首先创建 Node 工具镜像的目录:
bash
mkdir -p common/tools/node
cd common/tools/node
Node 工具环境 Dockerfile 详解
bash
FROM harbor.leops.local/common/os/debian:bullseye
ARG NODE_VERSION=22.15.0 \
YARN_VERSION=1.22.22
LABEL org.opencontainers.image.authors="ops@leops.local" \
org.opencontainers.image.source="http://git.leops.local/ops/dockerfiles-base/common/tools/node/Dockerfile" \
org.opencontainers.image.description="node ${NODE_VERSION} compiler environment."
ENV NODE_VERSION=$NODE_VERSION \
YARN_VERSION=$YARN_VERSION \
NPM_REGISTRY="http://verdaccio.leops.local/" \
YARN_REGISTRY="http://verdaccio.leops.local/"
# install dependencies
RUN set -eux \
&& apt-get update \
&& apt-get install -y --no-install-recommends git python3 python3-pip gcc g++ make \
&& apt-get clean \
&& rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& truncate -s 0 /var/log/*log
# install node
RUN set -eux \
&& curl -fsSLO --compressed "http://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" \
&& tar -zxf "node-v$NODE_VERSION-linux-x64.tar.gz" -C /usr/local --strip-components=1 --no-same-owner \
&& rm "node-v$NODE_VERSION-linux-x64.tar.gz" \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs \
# smoke test
&& node --version \
&& npm --version \
# set registry
&& npm config set registry $NPM_REGISTRY \
&& echo "disturl=${NPM_REGISTRY}/-/binary/node/" >> /root/.npmrc \
&& echo "sass_binary_site=${NPM_REGISTRY}/-/binary/node-sass" >> /root/.npmrc \
&& echo "canvas_binary_host_mirror=${NPM_REGISTRY}/-/binary/canvas" >> /root/.npmrc \
&& echo "python_mirror=${NPM_REGISTRY}/-/binary/python/" >> /root/.npmrc \
&& npm config list
# install yarn
RUN set -eux \
&& curl -fsSLO -k --compressed "https://github.com/yarnpkg/yarn/releases/download/v$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
&& mkdir -p /opt \
&& tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \
&& ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \
&& ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \
&& rm -fv yarn-v$YARN_VERSION.tar.gz \
# smoke test
&& yarn --version \
# set registry
&& yarn config set registry $YARN_REGISTRY \
&& yarn config list
Dockerfile 关键点解析
该 Node.js 工具环境 Dockerfile 有以下几个重要特点:
- 基于 Debian:使用了标准化的 Debian bullseye 作为基础镜像
- 参数化版本:通过 ARG 参数化 Node.js 和 Yarn 版本,便于维护和更新
- 环境配置:设置了私有 NPM 和 Yarn 镜像源地址
- C/C++ 编译支持:安装了 gcc、g++、make 等编译工具,支持需要本地编译的模块
- 依赖管理:配置了预设的二进制下载镜像,加速 node-sass、canvas 等模块安装
- 验证安装:通过 smoke test 验证 Node.js 和 Yarn 安装成功
- 缓存清理:每个步骤后清理不必要的缓存文件,减小最终镜像体积
镜像构建脚本
使用以下脚本 (build.sh) 来构建和推送 Node 工具镜像:
bash
#!/bin/bash
set -e
# 配置
REGISTRY="harbor.leops.local"
IMAGE_BASE_NAME="common/tools/node"
VERSION="22.15.0"
# 声明镜像地址数组
declare -a IMAGE_PATHS
IMAGE_PATHS+=(
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION}"
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION%.*}"
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION%%.*}"
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION}-debian11"
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION%.*}-debian11"
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION%%.*}-debian11"
)
build_image() {
echo "Building and pushing image:"
for img in "${IMAGE_PATHS[@]}"; do echo -e " $img"; done
# 构建镜像
docker buildx build \
$(for img in "${IMAGE_PATHS[@]}"; do echo -n "-t $img "; done) \
--label "org.opencontainers.image.created=$(date --rfc-3339=seconds)" \
--build-arg "NODE_VERSION=${VERSION}" \
--add-host verdaccio.leops.local=192.168.77.140 \
--provenance=false \
--pull \
--push \
.
echo "Build complete."
}
# 参数处理
case "$1" in
"list-tags")
# 输出镜像标签列表
printf '%s\n'"${IMAGE_PATHS[@]}"
;;
*)
build_image
;;
esac
构建脚本通过灵活的标签生成逻辑,为镜像创建多个版本标签,包括:完整版本号(22.15.0)、主次版本号(22.15)、主版本号(22)以及带系统标识的组合标签,满足不同场景下的引用需求。
构建 Node.js 后端服务运行镜像 (SSR/API)
Node.js 后端服务运行镜像专注于安全、高效地运行 Node.js 服务端应用,采用 PM2 作为进程管理工具。这适用于 Express、Koa、NestJS、Nuxt 等需要服务端运行的框架。
为什么选择 PM2?
PM2 是一个强大的 Node.js 应用进程管理工具,提供以下关键特性:
- 进程守护:自动重启崩溃的应用
- 负载均衡:自动使用集群模式分发请求
- 日志管理:集中管理应用日志
- 监控功能:实时监控应用状态
- 零停机重载:不中断服务的情况下更新应用
创建 PM2 工具环境目录
首先创建 PM2 工具镜像的目录:
bash
mkdir -p common/runtime/pm2
cd common/runtime/pm2
PM2 工具环境 Dockerfile 详解
bash
#syntax=harbor.leops.local/library/docker/dockerfile:1
ARG NODE_VERSION=22
FROM harbor.leops.local/common/tools/node:${NODE_VERSION}
LABEL org.opencontainers.image.authors="ops@leops.local" \
org.opencontainers.image.source="http://git.leops.local/ops/dockerfiles-base/common/runtime/pm2/Dockerfile" \
org.opencontainers.image.description="pm2 runtime environment."
# install node
RUN set -eux \
&& npm install -g pm2 \
&& groupadd -r nonroot \
&& useradd -r -m -g nonroot nonroot \
&& mkdir -p /app/logs /home/nonroot/.pm2 \
&& export PM2_HOME=/home/nonroot/.pm2 \
&& chown nonroot:nonroot -R /app /home/nonroot
USER nonroot:nonroot
CMD [ "pm2-runtime", "start", "ecosystem.config.js" ]
运行镜像重点解析
这个 PM2 运行镜像具有以下关键特点:
- 基于 Node 工具环境:继承我们前面创建的 Node.js 工具环境
- 全局安装 PM2:作为进程管理器确保应用稳定运行
- 非 root 用户:创建专用的 nonroot 用户,提高容器安全性
- 标准目录结构:预先创建 /app/logs 目录和 PM2 主目录
- 权限设置:确保应用目录归非 root 用户所有
- 默认启动命令:配置使用 PM2 运行时模式启动应用
镜像构建脚本
使用以下脚本 (build.sh) 来构建和推送 PM2 工具镜像:
bash
#!/bin/bash
set -e
# 配置
REGISTRY="harbor.leops.local"
IMAGE_BASE_NAME="common/runtime/pm2"
VERSION="22"
# 声明镜像地址数组
declare -a IMAGE_PATHS
IMAGE_PATHS+=(
"${REGISTRY}/${IMAGE_BASE_NAME}:node-${VERSION}"
"${REGISTRY}/${IMAGE_BASE_NAME}:node-${VERSION%.*}"
)
build_image() {
echo "Building and pushing image:"
for img in "${IMAGE_PATHS[@]}"; do echo -e " $img"; done
# 构建镜像
docker buildx build \
$(for img in "${IMAGE_PATHS[@]}"; do echo -n "-t $img "; done) \
--label "org.opencontainers.image.created=$(date --rfc-3339=seconds)" \
--add-host verdaccio.leops.local=192.168.77.140 \
--build-arg "NODE_VERSION=${VERSION}" \
--provenance=false \
--pull \
--push \
.
echo "Build complete."
}
# 参数处理
case "$1" in
"list-tags")
# 输出镜像标签列表
printf '%s\n'"${IMAGE_PATHS[@]}"
;;
*)
build_image
;;
esac
构建前端应用静态文件镜像 (CSR)
对于前端应用(客户端渲染),最终产物是一堆静态的 HTML、CSS 和 JavaScript 文件,最适合使用 Nginx 这样的高性能 Web 服务器来托管。这适用于 React、Vue、Angular 等前端框架构建的静态应用。
为什么选择 Nginx?
Nginx 作为静态文件服务器有以下优势:
- 高性能:能够高效处理并发连接
- 低资源消耗:比动态服务占用更少的系统资源
- 缓存能力:内置优秀的静态文件缓存机制
- 简单配置:容易配置路由规则和重定向
- 安全性:能够限制访问和隐藏敏感信息
创建 Nginx 工具环境目录
首先创建 Nginx 工具镜像的目录:
bash
mkdir -p common/runtime/nginx-csr
cd common/runtime/nginx-csr
Nginx CSR Dockerfile 详解
bash
#syntax=harbor.leops.local/library/docker/dockerfile:1
FROM harbor.leops.local/common/os/debian:bullseye
ARG NGINX_VERSION=1.26.3
LABEL org.opencontainers.image.authors="ops@leops.local" \
org.opencontainers.image.source="http://git.leops.local/ops/dockerfiles-base/common/tools/node/Dockerfile" \
org.opencontainers.image.description="nginx [engine x] is an HTTP and reverse proxy server"
ENV NGINX_VERSION=$NGINX_VERSION
RUN echo 'deb [trusted=yes] https://nginx.org/packages/debian/ bullseye nginx' >> /etc/apt/sources.list.d/nginx.list \
&& apt-get update \
&& apt-get install -y nginx=${NGINX_VERSION}-1~bullseye \
&& apt-get clean \
&& chown www-data.www-data -R /var/cache/nginx \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log
COPY ./nginx.conf /etc/nginx/nginx.conf
EXPOSE80
STOPSIGNAL SIGQUIT
CMD ["/usr/sbin/nginx", "-g", "daemon off;"]
Nginx 配置文件详解
nginx.conf 是一个针对前端单页应用(SPA)优化的配置文件,包含以下关键特性:
bash
user www-data;
worker_processes 1;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
multi_accept on;
worker_connections 65535;
}
http {
charset utf-8;
# MIME
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format main_json '{"@timestamp": "$time_iso8601", '
'"remote_addr": "$remote_addr", '
'"Remoteip": "$http_Remoteip", '
'"http_x_forwarded_for": "$http_x_forwarded_for", '
'"scheme": "$scheme", '
'"request_method": "$request_method", '
'"host": "$host", '
'"request_uri": "$request_uri", '
'"body_bytes_sent": $body_bytes_sent, '
'"http_referer": "$http_referer", '
'"http_user_agent": "$http_user_agent", '
'"request_time": $request_time, '
'"request_length": $request_length, '
'"status": "$status"}';
access_log /var/log/nginx/access.log main_json;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
log_not_found off;
types_hash_max_size 2048;
types_hash_bucket_size 64;
client_max_body_size 100M;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
underscores_in_headers on;
# disable version in error messages and response header
server_tokens off;
proxy_hide_header X-Application-Context;
# use etag with expire
etag on;
server {
charset utf-8;
listen 80 default_server;
server_name _;
index index.html;
root /app/;
# index.html fallback
location / {
try_files $uri $uri/ $uri/index.html /index.html;
}
# no cache index.html
location ~* index.html {
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
add_header Pragma no-cache;
if_modified_since off;
etag off;
}
# favicon.ico
location = /favicon.ico {
log_not_found off;
access_log off;
}
# robots.txt
location = /robots.txt {
log_not_found off;
access_log off;
}
# assets, media
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
expires 7d;
access_log off;
}
# svg, fonts
location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {
add_header Access-Control-Allow-Origin "*";
expires 7d;
access_log off;
}
# deny hidden file
location ~ /\. {
deny all;
access_log off;
}
# gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1k;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
}
}
配置文件关键点解析
- SPA 路由支持:通过 try_files 指令将未匹配的路由重定向到 index.html,支持前端路由
- 缓存策略优化:
- HTML 文件不缓存,确保内容始终最新
- 静态资源(CSS、JS、图片等)设置 7 天缓存
- 字体文件支持跨域请求和缓存
- 性能优化:
- 开启 gzip 压缩减少传输数据量
- 设置合理的 worker 连接数和文件处理参数
- 使用 sendfile、tcp_nopush 等提升文件传输性能
- 安全设置:
- 隐藏 Nginx 版本信息
- 拒绝访问隐藏文件
- 定制日志格式,便于安全审计和问题排查
- 日志优化:使用 JSON 格式记录访问日志,便于日志收集和分析系统处理
镜像构建脚本
使用以下脚本 (build.sh) 来构建和推送镜像:
bash
#!/bin/bash
set -e
# 配置
REGISTRY="harbor.leops.local"
IMAGE_BASE_NAME="common/runtime/nginx-csr"
VERSION="1.26.3"
# 声明镜像地址数组
declare -a IMAGE_PATHS
IMAGE_PATHS+=(
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION}"
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION%.*}"
)
build_image() {
echo "Building and pushing image:"
for img in "${IMAGE_PATHS[@]}"; do echo -e " $img"; done
# 构建镜像
docker buildx build \
$(for img in "${IMAGE_PATHS[@]}"; do echo -n "-t $img "; done) \
--label "org.opencontainers.image.created=$(date --rfc-3339=seconds)" \
--build-arg "NGINX_VERSION=${VERSION}" \
--provenance=false \
--pull \
--push \
.
echo "Build complete."
}
# 参数处理
case "$1" in
"list-tags")
# 输出镜像标签列表
printf '%s\n'"${IMAGE_PATHS[@]}"
;;
*)
build_image
;;
esac
构建应用镜像 - 多阶段构建实战
在准备好基础工具镜像和运行环境镜像后,我们可以使用多阶段构建来创建最终的应用镜像。这种方法使我们能够在一个 Dockerfile 中同时处理构建和运行环境,大幅减小最终镜像体积。
Docker 多阶段构建简介:多阶段构建的核心优势:
- 分离关注点:构建阶段专注于编译和打包,运行阶段专注于高效执行
- 镜像体积优化:最终镜像只包含运行所需的文件,不含构建工具和中间产物
- 构建缓存利用:合理的缓存策略可以大幅提升重复构建速度
- 工作流简化:一个 Dockerfile 完成全部流程,无需额外脚本协调
准备示例应用 Vue
首先,我们获取一个简单的 Vue 应用示例:
bash
git clone https://github.com/lework/ci-demo-vue.git
cd ci-demo-vue
Vue 应用 Dockerfile 详解
下面是一个 Vue 前端应用的多阶段构建 Dockerfile:
bash
#
# ---- 编译环境 ----
FROM harbor.leops.local/common/tools/node:22 AS builder
ARG APP_ENV=test \
APP=undefine \
GIT_BRANCH= \
GIT_COMMIT_ID=
ENV APP_ENV=$APP_ENV \
APP=$APP \
GIT_BRANCH=$GIT_BRANCH \
GIT_COMMIT_ID=$GIT_COMMIT_ID
WORKDIR /app_build
COPY package.json package-lock.json ./
RUN --mount=type=cache,id=${APP}-npm,target=/root/.npm \
--mount=type=cache,id=${APP}-npm-modules,target=./node_modules \
npm install
COPY ./ ./
RUN --mount=type=cache,id=${APP}-npm,target=/root/.npm \
--mount=type=cache,id=${APP}-npm-modules,target=./node_modules \
npm run build:${APP_ENV}
#
# ---- 运行环境 ----
FROM harbor.leops.local/common/runtime/nginx-csr:1.26 AS running
ARG APP_ENV=test \
APP=undefine \
GIT_BRANCH= \
GIT_COMMIT_ID=
ENV APP_ENV=$APP_ENV \
APP=$APP \
GIT_BRANCH=$GIT_BRANCH \
GIT_COMMIT_ID=$GIT_COMMIT_ID
WORKDIR /app
COPY --from=builder /app_build/dist /app/
Vue 多阶段构建关键点解析
这个 Dockerfile 分为两个明确的阶段:
- 编译阶段 (builder):
• 使用我们创建的 Node.js 工具镜像
• 接收构建参数(环境、应用名称、Git 信息等)
• 先复制依赖描述文件安装依赖,最大化利用缓存
• 使用 BuildKit 缓存加速 npm 依赖下载和安装
• 执行对应环境的构建命令,生成静态文件 - 运行阶段 (running):
• 使用我们准备的 Nginx CSR 运行环境镜像
• 仅从编译阶段复制生成的 dist 目录中的静态文件
• 继承环境变量用于版本跟踪和问题排查
• 由 Nginx 提供高性能的静态文件服务
构建应用镜像
执行以下命令构建示例应用:
bash
bash /data/dockerfiles-base/app-build/build-app.sh dev ci-demo-vue
构建完成后,会生成如下格式的镜像标签:
harbor.leops.local/dev/ci-demo-vue:master-256c81b-202504290330
准备示例应用 Nuxt
接下来,我们获取一个 Nuxt.js 应用示例,Nuxt 是基于 Vue.js 的服务端渲染框架:
bash
git clone https://github.com/lework/ci-demo-nuxt.git
cd ci-demo-nuxt
Nuxt 应用 Dockerfile 详解
下面是一个 Nuxt SSR 应用的多阶段构建 Dockerfile:
bash
#syntax=harbor.leops.local/library/docker/dockerfile:1
#
# ---- 编译环境 ----
FROM harbor.leops.local/common/tools/node:22 AS builder
ARG APP_ENV=test \
APP=undefine \
GIT_BRANCH= \
GIT_COMMIT_ID=
ENV APP_ENV=$APP_ENV \
APP=$APP \
GIT_BRANCH=$GIT_BRANCH \
GIT_COMMIT_ID=$GIT_COMMIT_ID
WORKDIR /app_build
COPY package.json package-lock.json ./
RUN --mount=type=cache,id=${APP}-npm,target=/root/.npm \
--mount=type=cache,id=${APP}-node_modules,target=/app_build/node_modules \
npm install
COPY ./ ./
RUN --mount=type=cache,id=${APP}-npm,target=/root/.npm \
--mount=type=cache,id=${APP}-node_modules,target=/app_build/node_modules \
npm run build:${APP_ENV}
#
# ---- 运行环境 ----
FROM harbor.leops.local/common/runtime/pm2:node-22 AS running
ARG APP_ENV=test \
APP=undefine \
GIT_BRANCH= \
GIT_COMMIT_ID=
ENV APP_ENV=$APP_ENV \
APP=$APP \
GIT_BRANCH=$GIT_BRANCH \
GIT_COMMIT_ID=$GIT_COMMIT_ID
WORKDIR /app
COPY --from=builder --link --chown=999:999 /app_build/.output /app
CMD ["bash", "-c", "exec pm2-runtime start ecosystem.config.js --json --env ${APP_ENV}"]
Nuxt 多阶段构建关键点解析
这个 Dockerfile 同样分为两个阶段,但与 Vue 应用不同:
- 编译阶段 (builder):
• 同样使用 Node.js 工具环境,流程与 Vue 应用相似
• 构建产物是 .output 目录,而非 dist 目录 - 运行阶段 (running):
• 使用 PM2 运行环境镜像,而非 Nginx
• 使用 --link 优化 BuildKit 缓存策略
• 设置正确的文件所有权 (999:999 对应 nonroot 用户)
• 使用 PM2 运行时启动服务端应用,支持环境变量切换
构建 Nuxt 应用镜像
执行以下命令构建示例应用:
bash
bash /data/dockerfiles-base/app-build/build-app.sh dev ci-demo-nuxt
构建完成后,会生成如下格式的镜像标签:
harbor.leops.local/dev/ci-demo-nuxt:master-e13ed12-202504292036
版本控制
完成构建后,将所有文件提交到 Git 仓库进行版本控制:
bash
git add -A .
git commit -m "feat: add node"
git push
运行应用容器
最终,我们可以运行构建好的应用容器,并验证其功能。
容器运行与验证
bash
# 运行 Vue 前端容器
docker run --rm -d --name ci-demo-vue -p 18084:80 harbor.leops.local/dev/ci-demo-vue:master-256c81b-202504290330
# 运行 Nuxt 服务端容器
docker run --rm -d --name ci-demo-nuxt -p 18085:3000 harbor.leops.local/dev/ci-demo-nuxt:master-e13ed12-202504292036
# 访问应用
curl http://localhost:18084/
curl http://localhost:18085/
# 查看日志
docker logs ci-demo-vue
docker logs ci-demo-nuxt
# 停止容器
docker stop ci-demo-vue
docker stop ci-demo-nuxt
生产环境最佳实践
在生产环境中部署 Node.js 应用容器时,建议遵循以下最佳实践:
- 资源限制:使用 --memory 和 --cpus 设置容器资源上限,防止单个应用占用过多资源
- 健康检查:配置健康检查端点和容器健康检查,及时发现问题
- 日志管理:采用集中式日志收集系统,如 ELK 或 Loki,便于问题排查
- 环境变量:通过环境变量注入配置,实现同一镜像在不同环境运行
- 网络设置:仅暴露必要端口,使用内部网络进行服务间通信
- 容器编排:在生产环境中使用 Kubernetes 或 Docker Swarm 进行容器编排和管理
总结
通过本实践篇的学习,我们成功为两种典型的 Node.js 应用场景构建了优化、安全且高效的 Docker 镜像:
-
前端应用 (CSR):使用 Nginx 托管静态文件,具有高性能和优化的缓存策略
-
后端应用 (SSR/API):使用 PM2 管理 Node.js 进程,提供稳定可靠的服务
我们的解决方案具有以下优势:
-
分层设计:工具环境和运行环境分离,职责明确
-
多阶段构建:大幅减小最终镜像体积,提高部署效率
-
安全性:使用非 root 用户运行应用,减少安全风险
-
缓存优化:合理利用 BuildKit 缓存加速重复构建
-
标准化:统一的构建流程和镜像结构,便于团队协作和自动化部署
这种方法不仅适用于示例中的 Vue 和 Nuxt 应用,也可以轻松扩展到其他 Node.js 框架和应用类型,为现代 Web 应用的容器化部署提供了可靠的参考方案。