实践篇: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 应用的容器化部署提供了可靠的参考方案。

相关推荐
cui_hao_nan2 小时前
Docker后端部署
运维·docker·容器
大苏打seven3 小时前
Docker学习笔记:Docker网络
笔记·学习·docker
小张是铁粉4 小时前
docker在Linux的安装遇到的问题
linux·docker·容器
没有名字的小羊6 小时前
8.Docker镜像讲解
运维·docker·容器·tomcat
会飞的鱼先生6 小时前
Node.js-path模块
node.js
做一个AC梦8 小时前
Docker安装失败:Docker Desktop installation failed
运维·docker·容器
Shan12058 小时前
浅谈Docker Kicks in的应用
运维·docker·容器
Li&&Tao9 小时前
docker 常用命令
docker·容器·eureka
Jiude10 小时前
MinIO 社区版被故意阉割,Web管理功能全面移除。我来试试国产RustFS
后端·docker·架构