实践篇:14-构建 Node.js 应用程序镜像

背景介绍
Node.js是一个基于 Chrome V8 引擎的 JavaScript 运行时环境,以其事件驱动、非阻塞 I/O 模型而闻名,广泛用于构建后端服务和前端应用。

Node.js 的特点使其非常适合容器化部署:

  • 轻量级运行时:相比传统后端语言,占用资源更少
  • 包管理系统:通过 npm 或 yarn 高效管理依赖
  • 异步非阻塞:天然适合高并发应用场景
  • 全栈开发:同一语言编写前后端,降低开发门槛

容器化 Node.js 应用需要特别关注以下几个方面:

  • 依赖管理:npm 或 yarn 的缓存和依赖安装策略
  • 环境隔离:开发、测试和生产环境的配置区分
  • 安全考量:避免使用 root 用户运行应用
  • 应用类型:区分不同应用类型的构建和部署方式

我们将遵循标准化的多阶段构建思想,为两种常见的 Node.js 应用场景创建优化、安全且高效的 Docker 镜像:

  1. 后端服务 (SSR 或 API): 通常基于 Express, Koa, NestJS 等框架,需要 Node.js 运行时环境
  2. 前端应用 (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 有以下几个重要特点:

  1. 基于 Debian:使用了标准化的 Debian bullseye 作为基础镜像
  2. 参数化版本:通过 ARG 参数化 Node.js 和 Yarn 版本,便于维护和更新
  3. 环境配置:设置了私有 NPM 和 Yarn 镜像源地址
  4. C/C++ 编译支持:安装了 gcc、g++、make 等编译工具,支持需要本地编译的模块
  5. 依赖管理:配置了预设的二进制下载镜像,加速 node-sass、canvas 等模块安装
  6. 验证安装:通过 smoke test 验证 Node.js 和 Yarn 安装成功
  7. 缓存清理:每个步骤后清理不必要的缓存文件,减小最终镜像体积

镜像构建脚本

使用以下脚本 (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 运行镜像具有以下关键特点:

  1. 基于 Node 工具环境:继承我们前面创建的 Node.js 工具环境
  2. 全局安装 PM2:作为进程管理器确保应用稳定运行
  3. 非 root 用户:创建专用的 nonroot 用户,提高容器安全性
  4. 标准目录结构:预先创建 /app/logs 目录和 PM2 主目录
  5. 权限设置:确保应用目录归非 root 用户所有
  6. 默认启动命令:配置使用 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;
    }
}

配置文件关键点解析

  1. SPA 路由支持:通过 try_files 指令将未匹配的路由重定向到 index.html,支持前端路由
  2. 缓存策略优化:
    • HTML 文件不缓存,确保内容始终最新
    • 静态资源(CSS、JS、图片等)设置 7 天缓存
    • 字体文件支持跨域请求和缓存
  3. 性能优化:
    • 开启 gzip 压缩减少传输数据量
    • 设置合理的 worker 连接数和文件处理参数
    • 使用 sendfile、tcp_nopush 等提升文件传输性能
  4. 安全设置:
    • 隐藏 Nginx 版本信息
    • 拒绝访问隐藏文件
    • 定制日志格式,便于安全审计和问题排查
  5. 日志优化:使用 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 分为两个明确的阶段:

  1. 编译阶段 (builder):
    • 使用我们创建的 Node.js 工具镜像
    • 接收构建参数(环境、应用名称、Git 信息等)
    • 先复制依赖描述文件安装依赖,最大化利用缓存
    • 使用 BuildKit 缓存加速 npm 依赖下载和安装
    • 执行对应环境的构建命令,生成静态文件
  2. 运行阶段 (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 应用不同:

  1. 编译阶段 (builder):
    • 同样使用 Node.js 工具环境,流程与 Vue 应用相似
    • 构建产物是 .output 目录,而非 dist 目录
  2. 运行阶段 (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 应用容器时,建议遵循以下最佳实践:

  1. 资源限制:使用 --memory 和 --cpus 设置容器资源上限,防止单个应用占用过多资源
  2. 健康检查:配置健康检查端点和容器健康检查,及时发现问题
  3. 日志管理:采用集中式日志收集系统,如 ELK 或 Loki,便于问题排查
  4. 环境变量:通过环境变量注入配置,实现同一镜像在不同环境运行
  5. 网络设置:仅暴露必要端口,使用内部网络进行服务间通信
  6. 容器编排:在生产环境中使用 Kubernetes 或 Docker Swarm 进行容器编排和管理

总结

通过本实践篇的学习,我们成功为两种典型的 Node.js 应用场景构建了优化、安全且高效的 Docker 镜像:

  1. 前端应用 (CSR):使用 Nginx 托管静态文件,具有高性能和优化的缓存策略

  2. 后端应用 (SSR/API):使用 PM2 管理 Node.js 进程,提供稳定可靠的服务

    我们的解决方案具有以下优势:

  3. 分层设计:工具环境和运行环境分离,职责明确

  4. 多阶段构建:大幅减小最终镜像体积,提高部署效率

  5. 安全性:使用非 root 用户运行应用,减少安全风险

  6. 缓存优化:合理利用 BuildKit 缓存加速重复构建

  7. 标准化:统一的构建流程和镜像结构,便于团队协作和自动化部署

这种方法不仅适用于示例中的 Vue 和 Nuxt 应用,也可以轻松扩展到其他 Node.js 框架和应用类型,为现代 Web 应用的容器化部署提供了可靠的参考方案。

相关推荐
RoyLin4 分钟前
V8引擎与VM模块
前端·后端·node.js
小Lu的开源日常1 小时前
如何使用 GitHub Action 发布 Docker 镜像
docker·开源·github
神秘人X7071 小时前
docker安装
docker·容器·eureka
失因2 小时前
Docker 容器与镜像
java·运维·spring cloud·docker·容器
耳东哇2 小时前
sentinel docker gateway k8s 集群 主从
docker·gateway·sentinel
蓝莓味的口香糖3 小时前
【npm】npm命令大全
前端·npm·node.js
aricvvang4 小时前
一行 Promise.all 争议:数据库查询并行真的没用?我和同事吵赢了!!!
javascript·后端·node.js
费益洲5 小时前
Docker 网络详解:(二)虚拟网络环境搭建与测试
docker·容器
郁大锤5 小时前
Docker 中删除镜像与容器的完整指南
运维·docker·容器
xx.ii5 小时前
docker镜像和容器
docker·容器·eureka