最近作为前端看到招聘信息上面出现了需要熟悉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 化
- 创建基础 Next.js 项目
bash
npx create-next-app@latest web
cd web
- 创建 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"]

- 创建 .dockerignore
lua
node_modules
.next
.git
- 构建和运行
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
第四步:指定端口配置
- 修改 Dockerfile
dockerfile
EXPOSE 3008
- 修改 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 镜像过大
解决方案:
- 使用多阶段构建
- 使用 Next.js 的 standalone 模式
- 选择更小的基础镜像(如 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
优化策略
- 多阶段构建:将构建环境和运行环境分离
- 使用 .dockerignore:排除不必要的文件
- 使用 Alpine 镜像:更小的基础镜像
- 清理缓存:在构建过程中清理不必要的缓存文件