优化NextJs 项目的Docker 镜像 从3.62G 优化到 296.85M

最近作为前端看到招聘信息上面出现了需要熟悉docker,说实话在公司内部项目里面确实有Dockerfile 文件

里面的内容就是简单的内容,构建和运行也没有其他东西了。想来我就在本地基于Docker 构建一下生成镜像

一用一个不晓得,WC生成的镜像文件竟然有3.62G,妈卖批的我咋说构建过程生成镜像之后推的时候消耗时间有点长

之后就开始进行优化,最后将镜像结果从3.62GB 优化到 296.85MB

先科普一下Docker 基础,当然也可以直接跳过

1. Docker 简介与安装验证

Docker 是一个容器化平台,可以将应用程序及其依赖项打包到轻量级、可移植的容器中。

验证 Docker 安装

bash 复制代码
docker run hello-world

如果输出"Hello from Docker!",说明安装成功。

2. Docker 操作流程

Docker 的层级关系:

arduino 复制代码
Image(镜像) → Container(容器) → Process(进程)

Docker 桌面版界面功能说明

  • Containers: 正在运行 / 已停止的容器(最常用)
  • Images: 镜像列表(相当于"程序安装包")
  • Volumes: 数据存储(数据库数据、文件持久化)
  • Kubernetes: K8s(目前可忽略)
  • Builds: 构建镜像记录
  • Docker Hub: 官方镜像仓库(类似 npm / pip)

Docker 常用命令汇总

类别 命令 说明
基本操作 docker ps 查看运行中的容器
基本操作 docker ps -a 查看所有容器(包括停止的)
基本操作 docker images 查看镜像
基本操作 docker logs <容器ID或名称> 查看容器日志
基本操作 docker logs -f <容器ID> 实时查看容器日志
基本操作 docker exec -it <容器ID> sh 进入容器
基本操作 docker history <镜像名> 查看镜像历史
构建镜像 docker build -t <名称> . 构建镜像
构建镜像 docker build --no-cache -t <名称> . 无缓存构建
运行容器 docker run -p <host>:<container> <镜像名> 运行镜像并映射端口
运行容器 docker run -it -v <host_dir>:<container_dir> <镜像名> 运行容器并挂载卷
容器管理 docker start <容器ID> 启动容器
容器管理 docker stop <容器ID> 停止容器
容器管理 docker rm <容器ID> 删除容器
镜像管理 docker rmi <镜像ID> 删除镜像
系统管理 docker system prune 清理无用镜像和缓存

删除镜像流程

先找到镜像里面的容器、停止容器、删除容器、删除镜像

bash 复制代码
# 1. 查找特定镜像的容器
docker ps -a --filter ancestor=next-app

# 2. 停止容器
docker stop <container_id>

# 3. 删除容器
docker rm <container_id>

# 4. 删除镜像
docker rmi next-app

构建和运行镜像

bash 复制代码
# 构建镜像
docker build -t next-web .

# 运行镜像
docker run -p 8080:8080 next-web

# 无缓存重新构建
docker build --no-cache -t next-app .

3. Docker Compose 使用指南

Docker Compose 是用来定义和运行复杂 Docker 应用的工具,可以通过一个 YAML 文件配置多容器应用。

安装 Docker Compose

Docker Desktop 已经内置了 Docker Compose,无需额外安装。

docker-compose.yml 示例

yaml 复制代码
version: "3.8"

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
    depends_on:
      - db

  db:
    image: postgres:13
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  postgres_data:

Docker Compose 常用命令

bash 复制代码
# 启动服务(后台运行)
docker-compose up -d

# 启动指定服务
docker-compose up service-name

# 停止服务
docker-compose down

# 查看服务日志
docker-compose logs

# 查看服务状态
docker-compose ps

# 重新构建并启动
docker-compose up --build

# 执行命令到指定容器
docker-compose exec service-name command

4. Docker 网络配置

Docker 提供多种网络模式,用于容器间通信和外部访问。

网络类型

  • bridge(默认):容器通过虚拟桥接连接,可互相通信
  • host:容器直接使用主机网络
  • none:容器无网络连接
  • overlay:用于多主机环境

网络管理命令

bash 复制代码
# 查看网络
docker network ls

# 创建网络
docker network create mynetwork

# 连接到网络
docker network connect mynetwork container-name

# 断开网络连接
docker network disconnect mynetwork container-name

# 删除网络
docker network rm mynetwork

# 查看网络详情
docker network inspect mynetwork

5. 数据持久化与卷管理

Docker 卷用于数据持久化,即使容器删除数据也不会丢失。

卷管理命令

bash 复制代码
# 列出卷
docker volume ls

# 创建卷
docker volume create myvolume

# 查看卷详情
docker volume inspect myvolume

# 删除卷
docker volume rm myvolume

# 清理未使用的卷
docker volume prune

使用卷运行容器

bash 复制代码
# 使用命名卷
docker run -v myvolume:/path/in/container image-name

# 使用绑定挂载
docker run -v /host/path:/container/path image-name

# 使用临时文件系统(数据不会持久化)
docker run --tmpfs /path/in/container image-name

6. Docker 安全最佳实践

容器安全

  • 使用官方或可信的基础镜像
  • 定期更新镜像
  • 避免以 root 用户运行容器
  • 限制容器资源使用
  • 禁用不必要的权限和功能

镜像安全

bash 复制代码
# 扫描镜像漏洞
docker scan image-name

# 验证镜像签名
docker trust inspect image-name

7. Next.js 在 Docker 中的递进式优化,先以最初的 Nextjs 为例

第一步:基础 Next.js 项目 Docker 化

  1. 创建基础 Next.js 项目
bash 复制代码
npx create-next-app@latest web
cd web
  1. 创建 Dockerfile
dockerfile 复制代码
FROM registry.cn-shanghai.aliyuncs.com/aipgpt/node:20-alpine

WORKDIR /app

# 启用 Corepack 功能
RUN corepack enable
# 安装并激活指定版本的 pnpm
RUN corepack prepare pnpm@latest --activate

COPY package*.json ./
RUN pnpm install

COPY . .

EXPOSE 3000

CMD ["npm", "run", "dev"]
  1. 创建 .dockerignore
lua 复制代码
node_modules
.next
.git
  1. 构建和运行
bash 复制代码
docker build -t next-app .
docker run -p 3000:3000 next-app

第二步:使用 Corepack 管理 pnpm(推荐)

dockerfile 复制代码
FROM node:18-alpine

WORKDIR /app

# 启用 Corepack 功能
RUN corepack enable
# 安装并激活指定版本的 pnpm
RUN corepack prepare pnpm@latest --activate

COPY package*.json ./
RUN pnpm install

COPY . .

EXPOSE 3000

CMD ["pnpm", "dev"]

第三步:配置热更新

bash 复制代码
docker run -it \
  -p 3000:3000 \
  -v $(pwd):/app \
  -w /app \
  node:18 \
  npm run dev

第四步:指定端口配置

  1. 修改 Dockerfile
dockerfile 复制代码
EXPOSE 3008
  1. 修改 package.json
json 复制代码
{
  "scripts": {
    "dev": "next dev -H 0.0.0.0 -p 3008"
  }
}

注意 : 必须添加-H 0.0.0.0参数,否则 Docker 外部无法访问。

第五步:多阶段构建优化

dockerfile 复制代码
# =====================
# Build
# =====================
FROM node:20-alpine AS builder
WORKDIR /app

# 启用 Corepack 功能
RUN corepack enable
# 安装并激活指定版本的 pnpm
RUN corepack prepare pnpm@latest --activate

COPY package.json ./
RUN pnpm install --registry=https://registry.npmmirror.com

COPY . .
RUN npm run build


# =====================
# Runtime
# =====================
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3008

COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

EXPOSE 3008
CMD ["npm", "run", "dev"]

第六步:Next.js Standalone 模式极致优化

这是 Next.js 12.2.0 版本引入的新特性,旨在优化构建输出和部署。Standalone 模式生成的包更小,启动更快。

配置 next.config.js
javascript 复制代码
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: "standalone", // 启用 standalone 模式
  experimental: {
    outputFileTracingRoot: path.join(__dirname, "../../"),
  },
};

module.exports = nextConfig;
Dockerfile 配置
dockerfile 复制代码
FROM node:20-alpine AS builder

WORKDIR /app

# 启用 Corepack 功能
RUN corepack enable
# 安装并激活指定版本的 pnpm
RUN corepack prepare pnpm@latest --activate

COPY package.json ./
RUN pnpm install --registry=https://registry.npmmirror.com

COPY . .

# 构建项目
RUN npm run build

FROM node:20-alpine AS runner

WORKDIR /app

# 仅复制 standalone 输出的文件
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

# 暴露端口
EXPOSE 3008
ENV PORT=3008

# 启动项目
CMD ["node", "server.js"]

因为初始化Nextjs 基本上没有任何内容显示不出来 使用 Standalone模式之后的对比效果

如果项目大的时候会有明显的对比

关于 Next.js Standalone 模式

Standalone 模式是 Next.js 团队为了优化部署而推出的新特性,它极大地简化了部署过程并减少了部署包的大小。从我自己的实践经验来看:

Next.js 版本 是否支持 standalone 说明
≤ 12.1 ❌ 不支持 只能 next start
12.2 首次引入 实验 → 可用
12.3 / 13.x ✅ 稳定 Docker 官方推荐
14 / 15 ✅ 默认生产方案 文档全面

优点:

  • 部署包更小:只包含必要的文件,大幅减少镜像大小
  • 启动更快:优化了模块加载路径
  • 依赖更少:减少了运行时需要的文件数量
  • 更适合容器化部署:特别适合 Docker 部署

需要注意的问题:

  • 需要调整 next.config.js 配置
  • 如果使用了外部依赖或复杂的文件操作,需要确认它们在 standalone 模式下是否正常工作
  • 某些动态导入可能需要特殊处理

SSR/SSG/ISR/CSR 在两种构建模式下的对比:

在传统模式和 Standalone 模式下,各种渲染方式的行为基本相同,但有以下细微差别:

  • SSR (Server-Side Rendering):在两种模式下都正常工作,但在 Standalone 模式下启动更快
  • SSG (Static Site Generation):预生成的静态文件在两种模式下表现一致
  • ISR (Incremental Static Regeneration):在 Standalone 模式下,由于文件结构优化,可能会有轻微的性能提升
  • CSR (Client-Side Rendering):两种模式下完全相同,因为都在客户端执行

适用场景:

  • 对部署包大小敏感的应用
  • 容器化部署场景
  • 需要快速启动的服务
  • 需要简化部署流程的项目

8. 故障排查技巧

查看容器状态

bash 复制代码
# 查看容器详细信息
docker inspect container-name

# 查看容器资源使用情况
docker stats container-name

# 查看容器进程
docker top container-name

调试容器

bash 复制代码
# 进入正在运行的容器
docker exec -it container-name sh

# 查看容器挂载的卷
docker inspect -f '{{.Mounts}}' container-name

# 以 root 权限进入容器
docker exec -u root -it container-name sh

常见问题排查

  • 容器无法启动:检查日志 docker logs container-name
  • 端口无法访问:检查防火墙设置和端口映射
  • 网络连接问题:使用 docker network inspect 检查网络配置
  • 存储问题:使用 docker volume inspect 检查卷配置

9. 常见问题及解决方案

问题 1:容器中没有 pnpm

解决方案:在 Dockerfile 中安装 pnpm

dockerfile 复制代码
# 使用 Corepack 方式(推荐)
RUN corepack enable
RUN corepack prepare pnpm@latest --activate

问题 2:外部无法访问容器内服务

解决方案 :在启动命令中添加-H 0.0.0.0

json 复制代码
{
  "scripts": {
    "dev": "next dev -H 0.0.0.0 -p 3008"
  }
}

问题 3:Docker 镜像过大

解决方案

  1. 使用多阶段构建
  2. 使用 Next.js 的 standalone 模式
  3. 选择更小的基础镜像(如 alpine 版本)

问题 4:Node 版本问题

解决方案

bash 复制代码
# 强制重新构建镜像
docker build --no-cache -t next-app .

# 删除指定版本镜像
docker rmi node:18-alpine

# 验证运行的版本
docker run --rm next-app node -v

问题 5:缓存导致的问题

解决方案

bash 复制代码
# 无缓存构建
docker build --no-cache -t aip-web:new .

# 清理系统缓存
docker system prune

10. Docker 镜像大小优化技巧

查看镜像大小

bash 复制代码
# 进入容器查看
docker exec -it <容器名> sh

# 查看镜像体积
docker images next-prod

优化策略

  1. 多阶段构建:将构建环境和运行环境分离
  2. 使用 .dockerignore:排除不必要的文件
  3. 使用 Alpine 镜像:更小的基础镜像
  4. 清理缓存:在构建过程中清理不必要的缓存文件
相关推荐
怣疯knight15 小时前
Docker Desktop 4.55.0版本安装成功教程
windows·docker
东方佑16 小时前
使用Docker Compose一键部署OnlyOffice:完整指南与配置解析
运维·docker·容器
赵文宇(温玉)17 小时前
Docker的价值、特点、创新与关键技术
运维·docker·容器
Coder码匠18 小时前
Docker Compose 部署 Spring Boot 应用完全指南
spring boot·docker·容器
可爱又迷人的反派角色“yang”19 小时前
k8s(二)
linux·运维·docker·云原生·容器·kubernetes·云计算
计算机小手19 小时前
内网穿透系列十六:使用 wg-easy 快速搭建基于 wireguard 的虚拟局域网,支持Docker部署
经验分享·网络协议·docker·开源软件
旧日之血_Hayter19 小时前
docker部署项目,/var/lib/docker/overlay2目录满了如何清理?
运维·docker·容器
文言一心19 小时前
基于 Docker + Docker Compose 实现一键部署(单节点部署场景下轻量、易维护、可一键启停)
运维·docker·容器
守护砂之国泰裤辣19 小时前
Windows+docker下简单kafka测试联调
java·运维·spring boot·docker·容器