{T}

Docker容器化部署前端项目实战

Docker容器化部署前端项目实战

学习目标:掌握 Docker 容器化部署、Docker Compose 配置、Dockerfile 编写、多阶段构建、镜像优化。


一、容器化部署概述

1.1 容器化 vs 直装部署对比

code
部署方式对比:
│
├── 直装部署(传统方式)
│   ├── 优点
│   │   ├── 简单直接
│   │   ├── 资源占用少
│   │   └── 调试方便
│   │
│   ├── 缺点
│   │   ├── 环境依赖强
│   │   ├── 部署复杂
│   │   ├── 环境不一致问题
│   │   └── 难以迁移
│   │
│   └── 适用场景
│       ├── 单机部署
│       ├── 环境固定
│       └── 小型项目
│
└── 容器化部署(推荐)
    ├── 优点
    │   ├── 环境隔离
    │   ├── 一致性强
    │   ├── 易于迁移
    │   ├── 快速部署
    │   └── 版本管理
    │
    ├── 缺点
    │   ├── 学习成本
    │   ├── 资源占用略高
    │   └── 调试稍复杂
    │
    └── 适用场景
        ├── 多环境部署
        ├── 微服务架构
        ├── CI/CD 流水线
        └── 大型项目 

1.2 容器化部署核心优势

code
容器化部署核心优势:
│
├── 1. 环境隔离 
│   ├── 网络隔离:不同容器端口独立
│   ├── 文件系统隔离:容器间互不影响
│   ├── 进程隔离:独立的进程空间
│   └── 环境变量隔离:独立的环境配置
│
├── 2. 环境一致性 
│   ├── 开发环境 = 生产环境
│   ├── 固定的运行环境
│   ├── 无需担心依赖冲突
│   └── "一次构建,到处运行"
│
├── 3. 快速部署 
│   ├── 秒级启动
│   ├── 一键部署
│   ├── 快速回滚
│   └── 弹性扩缩容
│
└── 4. 版本管理 
    ├── 镜像版本控制
    ├── 快速回滚到历史版本
    ├── 镜像仓库管理
    └── CI/CD 集成

1.3 前端容器化两种方式

code
前端容器化两种方式:
│
├── 方式一:Docker + Nginx + Volume 映射 
│   ├── 原理
│   │   ├── 使用 Nginx 官方镜像
│   │   ├── 宿主机目录映射到容器
│   │   └── Nginx 提供静态资源服务
│   │
│   ├── 优点
│   │   ├── 配置简单
│   │   ├── 灵活性高
│   │   ├── 无需构建镜像
│   │   └── 便于调试
│   │
│   ├── 缺点
│   │   ├── 依赖宿主机目录
│   │   ├── 迁移稍复杂
│   │   └── 环境不够独立
│   │
│   └── 适用场景
│       ├── 快速测试
│       ├── 开发环境
│       └── 需要频繁修改
│
└── 方式二:构建 Docker 镜像(推荐)
    ├── 原理
    │   ├── 编写 Dockerfile
    │   ├── 将代码打包到镜像中
    │   ├── 基于 Nginx 镜像构建
    │   └── 镜像即应用
    │
    ├── 优点
    │   ├── 环境完全独立
    │   ├── 一键部署
    │   ├── 易于迁移
    │   ├── 版本管理清晰
    │   └── CI/CD 友好
    │
    ├── 缺点
    │   ├── 需要学习 Dockerfile
    │   ├── 构建时间较长
    │   └── 镜像管理成本
    │
    └── 适用场景
        ├── 生产环境
        ├── 多环境部署
        ├── CI/CD 流水线
        └── 大型项目 

二、方式一:Docker + Nginx + Volume 映射

2.1 Docker Compose 基础配置

docker-compose.yml 基础配置:

yaml
# docker-compose.yml
version: '3'  # Docker Compose 版本

services:
  nginx:  # 服务名称
    restart: always  # 重启策略:总是重启
    image: nginx  # 使用官方 Nginx 镜像
    container_name: nginx  # 容器名称(唯一)
    environment:  # 环境变量
      - TZ=Asia/Shanghai  # 设置时区
    ports:  # 端口映射
      - "4080:80"  # 宿主机端口:容器端口
    volumes:  # 目录映射
      - /home/website:/usr/share/nginx/html  # 网站目录映射

配置详解:

code
Docker Compose 配置详解:
│
├── version: '3'
│   ├── Docker Compose 配置文件版本
│   ├── 常用版本:2、2.1、3、3.1、3.8
│   └── 推荐使用 3.x 版本
│
├── services
│   ├── 定义服务列表
│   ├── 每个服务对应一个容器
│   └── 可以定义多个服务
│
├── restart: always
│   ├── no:不自动重启(默认)
│   ├── always:总是重启
│   ├── on-failure:失败时重启
│   └── unless-stopped:除非手动停止
│
├── image: nginx
│   ├── 使用官方镜像
│   ├── 格式:镜像名:标签
│   └── 默认使用 latest 标签
│
├── container_name: nginx
│   ├── 容器名称(必须唯一)
│   ├── 不指定则自动生成
│   └── 建议:项目名-服务名
│
├── environment
│   ├── 环境变量配置
│   ├── TZ=Asia/Shanghai:设置时区
│   └── 可以配置多个环境变量
│
├── ports
│   ├── 端口映射:宿主机端口:容器端口
│   ├── 可以映射多个端口
│   └── 注意端口冲突
│
└── volumes
    ├── 目录映射:宿主机路径:容器路径
    ├── 可以映射多个目录
    └── 支持相对路径和绝对路径

2.2 端口映射原理详解

code
端口映射原理:
│
├── 概念
│   ├── 宿主机端口:外部访问的端口
│   ├── 容器端口:容器内部服务端口
│   └── 映射关系:宿主机端口 → 容器端口
│
├── 示例解析
│   ├── "4080:80"
│   │   ├── 宿主机端口:4080
│   │   ├── 容器端口:80(Nginx 默认)
│   │   └── 访问:http://server-ip:4080
│   │
│   ├── "4082:8000"
│   │   ├── 宿主机端口:4082
│   │   ├── 容器端口:8000(Nginx 监听 8000)
│   │   └── 访问:http://server-ip:4082
│   │
│   └── "9000:80"
│       ├── 宿主机端口:9000
│       ├── 容器端口:80
│       └── 访问:http://server-ip:9000
│
├── 注意事项
│   ├── 宿主机端口不能冲突
│   ├── 容器端口必须与 Nginx 配置一致
│   ├── 修改 Nginx 配置后需重启容器
│   └── 端口范围:1-65535
│
└── 常见错误
    ├── 端口被占用:修改宿主机端口
    ├── 容器端口错误:检查 Nginx 配置
    └── 防火墙拦截:开放对应端口

端口映射示例:

yaml
# 示例 1:Nginx 默认端口 80
ports:
  - "4080:80"  # 访问 http://server-ip:4080

# 示例 2:Nginx 监听 8000
ports:
  - "4082:8000"  # 访问 http://server-ip:4082

# 示例 3:映射多个端口
ports:
  - "4080:80"    # HTTP
  - "4443:443"   # HTTPS

2.3 Volume 映射详解

code
Volume 映射详解:
│
├── 概念
│   ├── 将宿主机目录映射到容器内部
│   ├── 容器内修改 → 宿主机同步修改
│   └── 宿主机修改 → 容器内同步修改
│
├── 映射类型
│   ├── 目录映射:/host/path:/container/path
│   ├── 文件映射:/host/file:/container/file
│   └── 匿名卷:/container/path(不推荐)
│
├── 常见映射目录
│   ├── 网站目录
│   │   └── /home/website:/usr/share/nginx/html
│   │
│   ├── Nginx 配置目录
│   │   └── /etc/nginx/conf.d:/etc/nginx/conf.d
│   │
│   ├── Nginx 主配置文件
│   │   └── /etc/nginx/nginx.conf:/etc/nginx/nginx.conf
│   │
│   └── 日志目录
│       └── /var/log/nginx:/var/log/nginx
│
├── 注意事项
│   ├── 宿主机目录必须存在
│   ├── 路径使用绝对路径
│   ├── 容器内路径由镜像决定
│   └── 权限问题:确保读写权限
│
└── 最佳实践
    ├── 使用数据卷(named volumes)
    ├── 配置文件单独映射
    ├── 日志目录单独映射
    └── 使用相对路径(docker-compose.yml 所在目录)

Volume 映射完整示例:

yaml
# docker-compose-nginx.yml
version: '3'

services:
  nginx:
    restart: always
    image: nginx
    container_name: nginx1
    environment:
      - TZ=Asia/Shanghai
    ports:
      - "4082:8000"  # Nginx 监听 8000
    volumes:
      # 网站目录映射
      - /home/website:/usr/share/nginx/html
      
      # Nginx 配置文件映射
      - /etc/nginx/conf.d:/etc/nginx/conf.d
      
      # Nginx 主配置文件映射
      - /etc/nginx/nginx.conf:/etc/nginx/nginx.conf
      
      # 日志目录映射
      - /var/log/nginx:/var/log/nginx

2.4 Nginx 配置文件映射示例

场景:自定义 Nginx 配置

yaml
# docker-compose-nginx.yml
version: '3'

services:
  nginx1:
    restart: always
    image: nginx
    container_name: nginx1
    environment:
      - TZ=Asia/Shanghai
    ports:
      - "4082:8000"  # 注意:容器内监听 8000
    volumes:
      # 网站目录
      - /home/website:/usr/share/nginx/html
      
      # Nginx 配置文件(包含监听 8000)
      - /etc/nginx/conf.d:/etc/nginx/conf.d

对应的 Nginx 配置文件:

nginx
# /etc/nginx/conf.d/site1.conf
server {
    listen 8000;  # 监听 8000 端口
    server_name site1.com;
    
    location / {
        root /usr/share/nginx/html/project-front-vue3;
        index index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
}

重要提示:

code
端口映射与 Nginx 配置关系:
│
├── Docker Compose 端口映射
│   └── ports: "4082:8000"
│       ├── 4082:宿主机端口(外部访问)
│       └── 8000:容器端口(Nginx 监听端口)
│
├── Nginx 配置文件
│   └── listen 8000;
│       └── 必须与容器端口一致 
│
├── 访问方式
│   └── http://server-ip:4082
│
└── 流程
    ├── 浏览器 → http://server-ip:4082
    ├── Docker → 映射到容器 8000 端口
    └── Nginx → 监听 8000 端口,响应请求

2.5 方式一完整部署流程

code
方式一完整部署流程:
│
├── 第一步:准备网站文件
│   ├── 构建项目:npm run build
│   ├── 上传文件到宿主机
│   └── 目标路径:/home/website/project-front-vue3
│
├── 第二步:创建 Docker Compose 配置
│   ├── 创建文件:vi /home/nginx/docker-compose.yml
│   ├── 编写配置内容
│   └── 保存退出
│
├── 第三步:启动容器
│   ├── 启动:docker-compose up -d
│   ├── 查看状态:docker ps
│   └── 查看日志:docker logs nginx
│
├── 第四步:测试访问
│   ├── 浏览器访问:http://server-ip:4080
│   ├── 检查页面显示
│   └── 检查静态资源加载
│
└── 第五步:更新部署
    ├── 上传新的构建文件
    ├── 无需重启容器(Volume 映射自动生效)
    └── 刷新浏览器即可看到更新

方式一常用命令:

bash
# 启动容器
docker-compose up -d

# 指定配置文件启动
docker-compose -f docker-compose-nginx.yml up -d

# 查看容器状态
docker ps

# 查看容器日志
docker logs nginx

# 重启容器
docker-compose restart

# 停止容器
docker-compose down

# 进入容器内部
docker exec -it nginx bash

三、方式二:构建 Docker 镜像(推荐)

3.1 Dockerfile 最佳实践

多阶段构建 Dockerfile(推荐):

dockerfile
# ==================== 构建阶段 ====================
# 使用 Node.js 作为构建环境
FROM node:18-alpine AS builder

# 设置工作目录
WORKDIR /app

# 配置 npm 镜像源(可选)
RUN npm config set registry https://registry.npmmirror.com

# 安装 pnpm(如果项目使用 pnpm)
RUN npm install -g pnpm

# 复制 package.json 和 lock 文件
COPY package.json pnpm-lock.yaml ./

# 安装依赖
RUN pnpm install --frozen-lockfile

# 复制项目代码
COPY . .

# 构建项目
RUN pnpm run build

# ==================== 生产阶段 ====================
# 使用 Nginx 作为运行环境
FROM nginx:alpine

# 复制构建产物到 Nginx 目录
COPY --from=builder /app/dist /usr/share/nginx/html

# 复制 Nginx 配置文件(可选)
# COPY nginx.conf /etc/nginx/conf.d/default.conf

# 暴露端口
EXPOSE 80

# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]

Dockerfile 结构详解:

code
Dockerfile 多阶段构建详解:
│
├── 构建阶段(Build Stage)
│   ├── FROM node:18-alpine AS builder
│   │   ├── 使用 Node.js 18 Alpine 镜像
│   │   ├── Alpine:极简 Linux 环境(体积小)
│   │   └── AS builder:命名此阶段为 builder
│   │
│   ├── WORKDIR /app
│   │   ├── 设置工作目录
│   │   └── 后续操作都在 /app 目录下
│   │
│   ├── RUN npm config set registry
│   │   ├── 配置 npm 镜像源
│   │   └── 加速依赖下载
│   │
│   ├── RUN npm install -g pnpm
│   │   ├── 全局安装 pnpm
│   │   └── 如果使用 npm 则不需要
│   │
│   ├── COPY package.json pnpm-lock.yaml ./
│   │   ├── 复制依赖配置文件
│   │   ├── 优先复制:利用 Docker 缓存
│   │   └── package.json 未变化则不重新安装依赖
│   │
│   ├── RUN pnpm install --frozen-lockfile
│   │   ├── 安装依赖
│   │   ├── --frozen-lockfile:严格按照 lock 文件
│   │   └── 确保依赖版本一致
│   │
│   ├── COPY . .
│   │   ├── 复制所有项目文件
│   │   └── 受 .dockerignore 影响
│   │
│   └── RUN pnpm run build
│       ├── 构建项目
│       ├── 生成 dist 目录
│       └── 这是最终需要的产物
│
├── 生产阶段(Production Stage)
│   ├── FROM nginx:alpine
│   │   ├── 使用 Nginx Alpine 镜像
│   │   ├── Alpine 镜像体积小(~20MB)
│   │   └── 不包含 Node.js 等构建工具
│   │
│   ├── COPY --from=builder /app/dist /usr/share/nginx/html
│   │   ├── 从构建阶段复制产物
│   │   ├── --from=builder:指定源阶段
│   │   ├── /app/dist:构建阶段的产物路径
│   │   └── /usr/share/nginx/html:Nginx 默认静态资源目录
│   │
│   ├── EXPOSE 80
│   │   ├── 声明暴露端口
│   │   ├── 仅为文档说明
│   │   └── 实际映射在 docker run 时指定
│   │
│   └── CMD ["nginx", "-g", "daemon off;"]
│       ├── 启动 Nginx
│       ├── -g "daemon off;":前台运行
│       └── 容器需要前台进程
│
└── 多阶段构建优势
    ├── 最终镜像不包含 Node.js
    ├── 不包含 node_modules
    ├── 不包含源代码
    ├── 镜像体积小(~20MB)
    └── 安全性高 

3.2 镜像体积优化策略

code
镜像体积优化策略:
│
├── 1. 使用 Alpine 镜像 
│   ├── node:18-alpine(~40MB)
│   ├── nginx:alpine(~20MB)
│   ├── 相比标准镜像减少 80%+
│   └── 缺点:部分包可能不兼容
│
├── 2. 多阶段构建 
│   ├── 构建阶段:使用 Node.js 镜像
│   ├── 生产阶段:使用 Nginx 镜像
│   ├── 最终镜像:只包含 Nginx + dist
│   └── 镜像体积:~22MB
│
├── 3. 优化依赖安装 
│   ├── 使用 --frozen-lockfile
│   ├── 只安装生产依赖:--production
│   ├── 清理缓存:npm cache clean
│   └── 删除不必要的依赖
│
├── 4. 使用 .dockerignore 
│   ├── 忽略 node_modules
│   ├── 忽略 .git
│   ├── 忽略构建产物
│   └── 忽略测试文件
│
└── 5. 减少镜像层数 
    ├── 合并 RUN 命令
    ├── 使用 && 连接多个命令
    └── 清理临时文件

镜像体积对比:

方式镜像内容体积推荐度
单阶段构建Node.js + 源码 + node_modules + dist~1GB+
多阶段构建Nginx + dist~22MB
Alpine + 多阶段Nginx Alpine + dist~20MB

3.3 .dockerignore 配置

.dockerignore 文件:

gitignore
# 依赖目录
node_modules
.pnpm-store

# 构建产物
dist
.output
.next
.nuxt
build

# 日志文件
logs
*.log
npm-debug.log*
pnpm-debug.log*

# 环境配置
.env
.env.local
.env.*.local

# 编辑器
.idea
.vscode
*.swp
*.swo
*~

# Git
.git
.gitignore

# 测试文件
coverage
.nyc_output
**/*.test.js
**/*.spec.js
**/*.test.ts
**/*.spec.ts

# 文档
README.md
CHANGELOG.md
LICENSE

# 其他
.DS_Store
Thumbs.db

.dockerignore 作用:

code
.dockerignore 作用详解:
│
├── 概念
│   ├── 类似 .gitignore
│   ├── 控制哪些文件不被复制到镜像
│   └── 减少 COPY . . 时复制的文件
│
├── 作用
│   ├── 减少构建上下文大小
│   ├── 加快构建速度
│   ├── 减小镜像体积
│   └── 提高安全性(不包含敏感文件)
│
├── 必须忽略的文件 
│   ├── node_modules(已在镜像中安装)
│   ├── .git(源码控制,不需要)
│   ├── dist(会在镜像中构建)
│   ├── .env(敏感信息,不应打包)
│   └── 测试文件(生产环境不需要)
│
└── 最佳实践
    ├── 从 .gitignore 复制基础配置
    ├── 添加 Docker 特定的忽略项
    └── 定期审查和更新

3.4 构建与运行 Docker 镜像

构建镜像:

bash
# 基础构建
docker build -t frontend:v1.0.0 .

# 详细构建过程
docker build --no-cache -t frontend:v1.0.0 .

# 查看构建的镜像
docker images

# 镜像输出示例
# REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
# frontend     v1.0.0    abc123def456   10 seconds ago   22MB

运行镜像:

bash
# 基础运行
docker run -d --name frontend-app -p 9000:80 frontend:v1.0.0

# 参数详解
# -d:后台运行
# --name frontend-app:容器名称
# -p 9000:80:端口映射(宿主机:容器)
# frontend:v1.0.0:镜像名称:标签

# 查看运行状态
docker ps

# 查看容器日志
docker logs frontend-app

# 进入容器内部
docker exec -it frontend-app sh

# 停止容器
docker stop frontend-app

# 删除容器
docker rm frontend-app

# 删除镜像
docker rmi frontend:v1.0.0

构建流程详解:

code
Docker 镜像构建流程:
│
├── 第一步:准备项目文件
│   ├── 确保项目可以正常构建
│   ├── 创建 Dockerfile
│   ├── 创建 .dockerignore
│   └── 检查 package.json
│
├── 第二步:构建镜像
│   ├── docker build -t frontend:v1.0.0 .
│   ├── Docker 读取 Dockerfile
│   ├── 执行构建指令
│   └── 生成镜像
│
├── 第三步:查看镜像
│   ├── docker images
│   ├── 检查镜像大小
│   └── 检查镜像标签
│
├── 第四步:运行容器
│   ├── docker run -d --name app -p 9000:80 frontend:v1.0.0
│   ├── Docker 创建容器
│   ├── 启动容器内的 Nginx
│   └── 映射端口
│
├── 第五步:测试访问
│   ├── 浏览器访问:http://localhost:9000
│   ├── 检查页面显示
│   └── 检查静态资源加载
│
└── 第六步:镜像管理
    ├── 推送到镜像仓库
    ├── 版本管理
    └── 分发部署

3.5 常见问题与解决方案

问题 1:依赖安装失败

code
问题:依赖安装失败
│
├── 现象
│   ├── npm ERR! network request failed
│   ├── pnpm: ERR_PNPM_FETCH_*
│   └── 依赖下载超时
│
├── 原因
│   ├── 国外镜像源访问慢
│   ├── 网络连接问题
│   └── 镜像源配置错误
│
└── 解决方案 
    ├── 配置淘宝镜像源
    │   └── RUN npm config set registry https://registry.npmmirror.com
    │
    ├── 使用 pnpm 淘宝源
    │   └── RUN pnpm config set registry https://registry.npmmirror.com
    │
    └── 使用代理(如有)
        └── RUN npm config set proxy http://proxy-server:port

问题 2:镜像体积过大

code
问题:镜像体积过大
│
├── 现象
│   ├── 镜像大小 > 500MB
│   ├── 构建速度慢
│   └── 推送/拉取耗时长
│
├── 原因
│   ├── 未使用多阶段构建
│   ├── 包含 node_modules
│   ├── 包含源代码
│   └── 使用标准镜像(非 Alpine)
│
└── 解决方案 
    ├── 使用多阶段构建
    │   └── FROM node:18-alpine AS builder
    │
    ├── 使用 Alpine 镜像
    │   └── FROM nginx:alpine
    │
    ├── 添加 .dockerignore
    │   └── 忽略 node_modules、.git 等
    │
    └── 优化依赖安装
        └── RUN pnpm install --production --frozen-lockfile

问题 3:构建时依赖缺失

code
问题:构建时依赖缺失
│
├── 现象
│   ├── Module not found: workbox-window
│   ├── Cannot find module 'xxx'
│   └── 构建失败
│
├── 原因
│   ├── 依赖未安装
│   ├── 依赖版本不兼容
│   └── devDependencies 中缺少构建依赖
│
└── 解决方案 
    ├── 安装缺失依赖
    │   └── pnpm install -D workbox-window
    │
    ├── 检查 package.json
    │   ├── 确保 devDependencies 包含构建工具
    │   └── 例如:vite、webpack、typescript 等
    │
    └── 使用 --frozen-lockfile
        └── 确保依赖版本一致

问题 4:容器启动后无法访问

code
问题:容器启动后无法访问
│
├── 现象
│   ├── 浏览器无法打开页面
│   ├── 连接被拒绝
│   └── 404 Not Found
│
├── 原因
│   ├── 端口映射错误
│   ├── Nginx 配置错误
│   ├── 静态资源路径错误
│   └── 容器未正常启动
│
└── 解决方案 
    ├── 检查容器状态
    │   └── docker ps -a
    │
    ├── 查看容器日志
    │   └── docker logs frontend-app
    │
    ├── 检查端口映射
    │   └── docker port frontend-app
    │
    ├── 进入容器检查
    │   ├── docker exec -it frontend-app sh
    │   ├── ls /usr/share/nginx/html
    │   └── cat /etc/nginx/conf.d/default.conf
    │
    └── 检查防火墙
        └── 开放对应端口

四、Vue3 项目完整容器化实战

4.1 项目文件结构

code
Vue3 项目 Docker 化文件结构:
│
├── project-front-vue3/
│   ├── src/                  # 源代码
│   ├── public/               # 静态资源
│   ├── package.json          # 依赖配置
│   ├── pnpm-lock.yaml        # 依赖锁定文件
│   ├── vite.config.ts        # Vite 配置
│   ├── tsconfig.json         # TypeScript 配置
│   ├── Dockerfile            # Docker 配置文件 
│   ├── .dockerignore         # Docker 忽略文件 
│   ├── docker-compose.yml    # Docker Compose 配置(可选)
│   └── nginx.conf            # Nginx 配置(可选)
│
└── 注意
    ├── Dockerfile 和 .dockerignore 必须在项目根目录
    ├── Dockerfile 文件名区分大小写
    └── .dockerignore 以点开头

4.2 Dockerfile 完整示例

dockerfile
# ==================== 构建阶段 ====================
# 使用 Node.js 18 Alpine 作为构建环境
FROM node:18-alpine AS builder

# 设置工作目录
WORKDIR /app

# 配置淘宝镜像源(加速下载)
RUN npm config set registry https://registry.npmmirror.com

# 安装 pnpm
RUN npm install -g pnpm

# 配置 pnpm 淘宝源
RUN pnpm config set registry https://registry.npmmirror.com

# 复制依赖配置文件(利用 Docker 缓存)
COPY package.json pnpm-lock.yaml ./

# 安装依赖
RUN pnpm install --frozen-lockfile

# 复制项目代码
COPY . .

# 构建项目
RUN pnpm run build

# ==================== 生产阶段 ====================
# 使用 Nginx Alpine 作为运行环境
FROM nginx:alpine

# 复制构建产物到 Nginx 目录
COPY --from=builder /app/dist /usr/share/nginx/html

# 复制自定义 Nginx 配置(可选)
# COPY nginx.conf /etc/nginx/conf.d/default.conf

# 暴露端口
EXPOSE 80

# 启动 Nginx(前台运行)
CMD ["nginx", "-g", "daemon off;"]

4.3 .dockerignore 完整示例

gitignore
# 依赖目录
node_modules
.pnpm-store

# 构建产物
dist
.output

# 日志文件
logs
*.log
npm-debug.log*
pnpm-debug.log*

# 环境配置(敏感信息)
.env
.env.local
.env.*.local

# 编辑器和 IDE
.idea
.vscode
*.swp
*.swo
*~

# Git
.git
.gitignore

# 测试文件
coverage
.nyc_output
**/*.test.js
**/*.spec.js
**/*.test.ts
**/*.spec.ts
cypress
cypress.config.ts

# 文档
README.md
CHANGELOG.md
LICENSE
docs

# Docker 相关
Dockerfile
docker-compose.yml
.dockerignore

# 其他
.DS_Store
Thumbs.db
*.bak
*.tmp

4.4 docker-compose.yml 完整示例

yaml
# docker-compose.yml
version: '3.8'

services:
  frontend:
    # 从当前目录构建镜像
    build:
      context: .
      dockerfile: Dockerfile
    
    # 镜像名称和标签
    image: frontend:v1.0.0
    
    # 容器名称
    container_name: frontend-app
    
    # 重启策略
    restart: always
    
    # 环境变量
    environment:
      - TZ=Asia/Shanghai
    
    # 端口映射
    ports:
      - "9000:80"
    
    # 健康检查
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    
    # 资源限制
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M
        reservations:
          cpus: '0.25'
          memory: 128M

4.5 自定义 Nginx 配置(可选)

nginx.conf(Vue SPA 路由支持):

nginx
# nginx.conf
server {
    listen 80;
    server_name localhost;
    
    # 静态资源目录
    root /usr/share/nginx/html;
    index index.html index.htm;
    
    # Gzip 压缩
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_min_length 1000;
    
    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    # Vue SPA 路由支持
    location / {
        try_files $uri $uri/ /index.html;
    }
    
    # API 代理(如需要)
    # location /api/ {
    #     proxy_pass http://backend:3000/;
    #     proxy_set_header Host $host;
    #     proxy_set_header X-Real-IP $remote_addr;
    # }
    
    # 错误页面
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

在 Dockerfile 中使用自定义 Nginx 配置:

dockerfile
# 复制自定义 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

4.6 完整部署流程

code
Vue3 项目完整部署流程:
│
├── 本地准备阶段
│   ├── 1. 确保项目可以正常构建
│   │   └── pnpm run build
│   │
│   ├── 2. 创建 Dockerfile
│   │   └── 编写多阶段构建配置
│   │
│   ├── 3. 创建 .dockerignore
│   │   └── 配置忽略文件
│   │
│   ├── 4. 创建 docker-compose.yml(可选)
│   │   └── 配置 Docker Compose
│   │
│   └── 5. 创建 nginx.conf(可选)
│       └── 配置 Nginx
│
├── 构建镜像阶段
│   ├── 1. 构建镜像
│   │   └── docker build -t frontend:v1.0.0 .
│   │
│   ├── 2. 查看镜像
│   │   └── docker images
│   │
│   └── 3. 测试镜像
│       └── docker run -d --name test -p 9000:80 frontend:v1.0.0
│
├── 本地测试阶段
│   ├── 1. 浏览器访问
│   │   └── http://localhost:9000
│   │
│   ├── 2. 检查页面显示
│   │
│   ├── 3. 检查静态资源加载
│   │
│   └── 4. 停止并删除测试容器
│       ├── docker stop test
│       └── docker rm test
│
├── 推送镜像阶段(可选)
│   ├── 1. 登录镜像仓库
│   │   └── docker login
│   │
│   ├── 2. 标记镜像
│   │   └── docker tag frontend:v1.0.0 username/frontend:v1.0.0
│   │
│   └── 3. 推送镜像
│       └── docker push username/frontend:v1.0.0
│
└── 服务器部署阶段
    ├── 1. 拉取镜像(或上传)
    │   └── docker pull username/frontend:v1.0.0
    │
    ├── 2. 创建 docker-compose.yml
    │
    ├── 3. 启动服务
    │   └── docker-compose up -d
    │
    ├── 4. 查看状态
    │   └── docker-compose ps
    │
    └── 5. 测试访问
        └── http://server-ip:9000

4.7 部署脚本示例

deploy.sh(自动化部署脚本):

bash
#!/bin/bash

# 部署脚本
set -e

# 配置变量
IMAGE_NAME="frontend"
IMAGE_TAG="v1.0.0"
CONTAINER_NAME="frontend-app"
PORT="9000"

echo "===== 开始部署 ====="

# 停止并删除旧容器
echo "停止旧容器..."
docker stop $CONTAINER_NAME 2>/dev/null || true
docker rm $CONTAINER_NAME 2>/dev/null || true

# 构建新镜像
echo "构建新镜像..."
docker build -t ${IMAGE_NAME}:${IMAGE_TAG} .

# 运行新容器
echo "运行新容器..."
docker run -d \
  --name $CONTAINER_NAME \
  -p ${PORT}:80 \
  --restart always \
  -e TZ=Asia/Shanghai \
  ${IMAGE_NAME}:${IMAGE_TAG}

# 查看状态
echo "查看容器状态..."
docker ps | grep $CONTAINER_NAME

# 清理旧镜像
echo "清理未使用的镜像..."
docker image prune -f

echo "===== 部署完成 ====="
echo "访问地址: http://localhost:${PORT}"

使用方式:

bash
# 添加执行权限
chmod +x deploy.sh

# 执行部署
./deploy.sh

五、两种部署方式对比总结

5.1 方式对比表

维度方式一:Volume 映射方式二:构建镜像
配置复杂度简单中等
环境一致性一般极好
部署速度中等
迁移便利性需要宿主机目录一键迁移
版本管理不方便清晰
CI/CD 友好一般极好
调试便利性方便需进入容器
安全性一般
推荐场景开发、测试环境生产环境

5.2 选择建议

code
部署方式选择建议:
│
├── 推荐使用方式二(构建镜像)的场景 
│   ├── 生产环境
│   ├── 多环境部署
│   ├── CI/CD 流水线
│   ├── 微服务架构
│   ├── 需要版本管理
│   └── 大型项目
│
├── 可以使用方式一(Volume 映射)的场景 
│   ├── 开发环境
│   ├── 快速测试
│   ├── 频繁修改
│   ├── 临时部署
│   └── 学习 Docker
│
└── 最佳实践
    ├── 开发环境:使用方式一(方便调试)
    ├── 测试环境:使用方式二(接近生产)
    └── 生产环境:使用方式二(稳定可靠)

六、最佳实践总结

6.1 Dockerfile 最佳实践

code
Dockerfile 最佳实践:
│
├── 1. 使用多阶段构建 
│   ├── 构建阶段:Node.js 环境
│   ├── 生产阶段:Nginx 环境
│   └── 减小镜像体积
│
├── 2. 使用 Alpine 镜像 
│   ├── node:18-alpine
│   ├── nginx:alpine
│   └── 体积小、安全
│
├── 3. 优化构建缓存 
│   ├── 优先复制 package.json
│   ├── 后复制源代码
│   └── 利用 Docker 缓存机制
│
├── 4. 使用 .dockerignore 
│   ├── 忽略 node_modules
│   ├── 忽略 .git
│   └── 忽略构建产物
│
├── 5. 配置镜像源 
│   ├── 使用淘宝镜像源
│   ├── 加速依赖下载
│   └── 提高构建速度
│
├── 6. 固定依赖版本 
│   ├── 使用 --frozen-lockfile
│   ├── 确保版本一致
│   └── 避免依赖冲突
│
├── 7. 减少镜像层数 
│   ├── 合并 RUN 命令
│   ├── 使用 && 连接
│   └── 清理临时文件
│
└── 8. 添加元数据 
    ├── LABEL maintainer
    ├── LABEL version
    └── LABEL description

6.2 Docker Compose 最佳实践

code
Docker Compose 最佳实践:
│
├── 1. 使用版本 3.x 
│   ├── version: '3.8'
│   └── 支持更多功能
│
├── 2. 明确指定镜像版本 
│   ├── image: nginx:1.25-alpine
│   ├── 不使用 latest 标签
│   └── 确保版本一致
│
├── 3. 配置重启策略 
│   ├── restart: always
│   └── 自动重启服务
│
├── 4. 设置资源限制 
│   ├── CPU 限制
│   ├── 内存限制
│   └── 防止资源耗尽
│
├── 5. 配置健康检查 
│   ├── healthcheck
│   ├── 监控服务状态
│   └── 自动重启
│
├── 6. 使用环境变量文件 
│   ├── env_file
│   ├── .env 文件
│   └── 敏感信息管理
│
└── 7. 网络配置 
    ├── 自定义网络
    ├── 服务间通信
    └── 隔离性

6.3 镜像管理最佳实践

code
镜像管理最佳实践:
│
├── 1. 版本管理 
│   ├── 使用语义化版本:v1.0.0
│   ├── latest 标签指向最新稳定版
│   ├── 保留历史版本
│   └── 及时清理过期版本
│
├── 2. 镜像仓库 
│   ├── 使用私有仓库(生产环境)
│   ├── Docker Hub(开源项目)
│   ├── 阿里云容器镜像服务
│   └── Harbor(企业级)
│
├── 3. 镜像安全 
│   ├── 定期扫描漏洞
│   ├── 使用可信镜像
│   ├── 最小化镜像内容
│   └── 不包含敏感信息
│
├── 4. 镜像优化 
│   ├── 使用 Alpine 镜像
│   ├── 多阶段构建
│   ├── 清理缓存
│   └── 压缩镜像
│
└── 5. 镜像分发 
    ├── 推送到镜像仓库
    ├── 使用 CDN 加速
    ├── 区域镜像复制
    └── 镜像签名

七、命令速查表

7.1 Docker 常用命令速查

命令说明
镜像管理
docker build -t name:tag .构建镜像
docker images查看本地镜像
docker rmi name:tag删除镜像
docker tag old new标记镜像
docker push name:tag推送镜像到仓库
docker pull name:tag从仓库拉取镜像
docker image prune -f清理未使用的镜像
容器管理
docker run -d --name app -p 9000:80 image:tag运行容器
docker ps查看运行中的容器
docker ps -a查看所有容器
docker stop container停止容器
docker start container启动容器
docker restart container重启容器
docker rm container删除容器
docker logs container查看容器日志
docker exec -it container sh进入容器
docker cp local container:path复制文件到容器
系统管理
docker info查看 Docker 信息
docker system df查看磁盘使用
docker system prune -f清理未使用资源

7.2 Docker Compose 常用命令速查

命令说明
docker-compose up -d后台启动所有服务
docker-compose -f file.yml up -d使用指定配置文件启动
docker-compose down停止并删除所有容器
docker-compose ps查看服务状态
docker-compose logs查看所有服务日志
docker-compose logs service查看指定服务日志
docker-compose restart重启所有服务
docker-compose restart service重启指定服务
docker-compose stop停止所有服务
docker-compose start启动所有服务
docker-compose build构建所有服务的镜像
docker-compose pull拉取所有服务的镜像
docker-compose exec service sh进入指定服务的容器

7.3 Dockerfile 常用指令速查

指令说明示例
FROM基础镜像FROM node:18-alpine
WORKDIR工作目录WORKDIR /app
COPY复制文件COPY . .
ADD添加文件(支持 URL)ADD file.tar.gz /tmp/
RUN运行命令RUN npm install
CMD容器启动命令CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT入口点ENTRYPOINT ["node", "app.js"]
ENV环境变量ENV NODE_ENV production
EXPOSE暴露端口EXPOSE 80
VOLUME数据卷VOLUME /data
USER用户USER node
LABEL元数据LABEL version="1.0"
ARG构建参数ARG NODE_ENV

八、学习要点总结

8.1 核心知识点

code
Docker 容器化部署核心知识点:
│
├── 基础概念 
│   ├── Docker 镜像(Image)
│   ├── Docker 容器(Container)
│   ├── Docker 仓库(Registry)
│   └── Docker Compose
│
├── 部署方式 
│   ├── 方式一:Volume 映射
│   │   ├── 简单灵活
│   │   ├── 适合开发测试
│   │   └── 需要宿主机目录
│   │
│   └── 方式二:构建镜像(推荐)
│       ├── 环境独立
│       ├── 易于迁移
│       └── 适合生产环境
│
├── Dockerfile 编写 
│   ├── 多阶段构建
│   ├── Alpine 镜像
│   ├── .dockerignore
│   ├── 构建缓存优化
│   └── 镜像体积优化
│
├── Docker Compose 配置 
│   ├── version
│   ├── services
│   ├── ports
│   ├── volumes
│   └── environment
│
└── 最佳实践 
    ├── 使用多阶段构建
    ├── 使用 Alpine 镜像
    ├── 配置 .dockerignore
    ├── 固定依赖版本
    └── 镜像版本管理

8.2 重要程度标注

知识点重要程度必须掌握
Docker 基础概念
多阶段构建
Dockerfile 编写
.dockerignore 配置
镜像体积优化
Docker Compose 配置
端口映射原理
Volume 映射
镜像版本管理
镜像仓库使用

8.3 学习路径规划

code
学习路径规划:
│
├── 第一阶段:理解概念(1 天)
│   ├── Docker 基础概念
│   ├── 镜像与容器
│   ├── Docker Compose
│   └── 容器化优势
│
├── 第二阶段:实践操作(2-3 天)
│   ├── 编写 Dockerfile
│   ├── 构建镜像
│   ├── 运行容器
│   ├── Docker Compose 配置
│   └── 完整项目容器化
│
├── 第三阶段:深入应用(持续)
│   ├── 镜像优化
│   ├── 多阶段构建进阶
│   ├── CI/CD 集成
│   ├── 镜像仓库管理
│   └── 生产环境最佳实践
│
└── 推荐资源
    ├── Docker 官方文档
    ├── Docker Hub
    ├── Vue.js 官方部署指南
    └── 实际项目练习

九、扩展阅读

9.1 CI/CD 自动化部署

code
CI/CD 自动化部署流程:
│
├── 1. 代码提交
│   └── Git Push → 触发 CI/CD
│
├── 2. 自动构建
│   ├── 安装依赖
│   ├── 运行测试
│   ├── 构建项目
│   └── 构建 Docker 镜像
│
├── 3. 镜像推送
│   ├── 推送到镜像仓库
│   └── 打上版本标签
│
├── 4. 自动部署
│   ├── 拉取新镜像
│   ├── 停止旧容器
│   └── 启动新容器
│
└── 5. 常用工具
    ├── GitHub Actions
    ├── GitLab CI/CD
    ├── Jenkins
    └── Travis CI

9.2 Docker 镜像仓库

code
Docker 镜像仓库选择:
│
├── Docker Hub(官方)
│   ├── 免费:公开仓库
│   ├── 付费:私有仓库
│   ├── 自动构建
│   └── 适合开源项目
│
├── 阿里云容器镜像服务
│   ├── 国内访问快
│   ├── 免费额度
│   ├── 安全扫描
│   └── 适合国内项目 
│
├── 腾讯云容器镜像服务
│   ├── 国内访问快
│   ├── 免费额度
│   ├── 安全扫描
│   └── 适合国内项目
│
└── Harbor(企业级)
    ├── 私有部署
    ├── 完整功能
    ├── 企业级管理
    └── 适合大型企业 

9.3 Docker 网络与安全

code
Docker 网络与安全:
│
├── 网络模式
│   ├── bridge(默认)
│   ├── host(主机模式)
│   ├── none(无网络)
│   └── 自定义网络
│
├── 安全最佳实践
│   ├── 使用官方镜像
│   ├── 定期更新镜像
│   ├── 不以 root 运行
│   ├── 扫描镜像漏洞
│   └── 限制容器资源
│
└── 日志与监控
    ├── 集中日志管理
    ├── 容器监控
    ├── 性能分析
    └── 告警机制

十、完整代码清单

10.1 Dockerfile 完整代码

dockerfile
# ==================== 构建阶段 ====================
FROM node:18-alpine AS builder

WORKDIR /app

# 配置镜像源
RUN npm config set registry https://registry.npmmirror.com && \
    npm install -g pnpm && \
    pnpm config set registry https://registry.npmmirror.com

# 复制依赖文件
COPY package.json pnpm-lock.yaml ./

# 安装依赖
RUN pnpm install --frozen-lockfile

# 复制项目代码
COPY . .

# 构建项目
RUN pnpm run build

# ==================== 生产阶段 ====================
FROM nginx:alpine

# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html

# 复制 Nginx 配置(可选)
# COPY nginx.conf /etc/nginx/conf.d/default.conf

# 暴露端口
EXPOSE 80

# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]

10.2 docker-compose.yml 完整代码

yaml
version: '3.8'

services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile
    
    image: frontend:v1.0.0
    container_name: frontend-app
    restart: always
    
    environment:
      - TZ=Asia/Shanghai
    
    ports:
      - "9000:80"
    
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M
        reservations:
          cpus: '0.25'
          memory: 128M

10.3 nginx.conf 完整代码

nginx
server {
    listen 80;
    server_name localhost;
    
    root /usr/share/nginx/html;
    index index.html index.htm;
    
    # Gzip 压缩
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_min_length 1000;
    
    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    # Vue SPA 路由支持
    location / {
        try_files $uri $uri/ /index.html;
    }
    
    # 错误页面
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

10.4 .dockerignore 完整代码

gitignore
# 依赖
node_modules
.pnpm-store

# 构建
dist
.output

# 日志
logs
*.log

# 环境配置
.env
.env.local
.env.*.local

# 编辑器
.idea
.vscode

# Git
.git
.gitignore

# 测试
coverage
**/*.test.js
**/*.spec.ts

# Docker
Dockerfile
docker-compose.yml
.dockerignore

# 其他
.DS_Store
README.md

10.5 deploy.sh 完整代码

bash
#!/bin/bash

set -e

# 配置
IMAGE_NAME="frontend"
IMAGE_TAG="v1.0.0"
CONTAINER_NAME="frontend-app"
PORT="9000"

echo "===== 开始部署 ====="

# 停止旧容器
echo "停止旧容器..."
docker stop $CONTAINER_NAME 2>/dev/null || true
docker rm $CONTAINER_NAME 2>/dev/null || true

# 构建镜像
echo "构建镜像..."
docker build -t ${IMAGE_NAME}:${IMAGE_TAG} .

# 运行容器
echo "运行容器..."
docker run -d \
  --name $CONTAINER_NAME \
  -p ${PORT}:80 \
  --restart always \
  -e TZ=Asia/Shanghai \
  ${IMAGE_NAME}:${IMAGE_TAG}

# 查看状态
docker ps | grep $CONTAINER_NAME

# 清理
docker image prune -f

echo "===== 部署完成 ====="
echo "访问: http://localhost:${PORT}"

重要提示:Docker 容器化部署是现代前端工程化的核心技能,掌握 Dockerfile 编写、多阶段构建、镜像优化、Docker Compose 配置,对实际项目部署非常重要!推荐使用多阶段构建 + Alpine 镜像,确保镜像体积小、安全性高、环境一致!

下节预告:Docker 容器化部署后端项目,深入学习 NestJS/Nuxt.js 容器化、数据库容器、多容器编排、Docker 网络配置等高级应用!

笔记已按照您的格式规范整理完成,可直接用于学习复习!