下载工作台
前端框架精通

生产部署:Docker、Nginx 与 CI/CD

试读上半部分 · 解锁后可读全文

第 15 章 · 生产部署:Docker、Nginx 与 CI/CD

本章目标:用 多阶段 Dockerfile 构建 Vue/React SPA;配置 docker-compose + Nginx 反向代理;掌握运行时 环境变量注入健康检查;编写 GitHub Actions / Gitea CI 流水线;理解 蓝绿/滚动发布(对接小紫云计算);在 frontend-web ch15 静态部署基础上深化容器化与自动化。

学时建议:4~5 小时

前置frontend-web ch15(Vite 构建与静态托管)、本模块 ch14(CI 跑测试)。


15.1 从 ch15 静态部署到容器化

阶段frontend-web ch15本章 frontend-framework ch15
构建npm run builddist/同上,在 Docker builder 阶段
托管对象存储 / 静态 CDNNginx 容器
配置手动上传CI 自动 build + push 镜像
多环境多套 bucket镜像 tag + 环境变量
回滚换静态文件版本换镜像 tag / 蓝绿切换
开发者 push
    │
    ▼
CI:lint → test → build → docker push
    │
    ▼
小紫云 / K8s:滚动更新 Deployment
    │
    ▼
Nginx Ingress → 商户后台 SPA
行业案例 · 贤紫优选商城:商户后台 2025 年从小紫云「单节点 Nginx + 手工 SCP」升级为 Git 触发 CI → Harbor 镜像 → K8s RollingUpdate,发布从 40 分钟降至 8 分钟,回滚一键 kubectl rollout undo

15.2 多阶段 Dockerfile(Vue SPA)

# Dockerfile — academy-admin-vue
# syntax=docker/dockerfile:1

# ── Stage 1: 依赖 ──
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

# ── Stage 2: 构建 ──
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# 构建时注入 API 地址(也可用运行时注入,见 15.5)
ARG VITE_API_BASE_URL=https://api.xianzi.shop/v1
ENV VITE_API_BASE_URL=$VITE_API_BASE_URL
RUN npm run build

# ── Stage 3: 运行 ──
FROM nginx:1.27-alpine AS runner
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget -qO- http://127.0.0.1/health || exit 1
阶段镜像体积贡献说明
deps不进入最终镜像node_modules
builder不进入最终镜像产出 dist
runner~45MB仅 Nginx + 静态文件
docker build -t xianzi/academy-admin-vue:1.0.0 .
docker run -p 8080:80 xianzi/academy-admin-vue:1.0.0

15.3 React SPA Dockerfile(差异点)

与 Vue 相同三阶段;构建命令同为 npm run build,产出目录均为 dist/(Vite 默认)。

# 若使用 Create React App,产出为 build/
# COPY --from=builder /app/build /usr/share/nginx/html

.dockerignore(Vue/React 共用):

node_modules
dist
.git
coverage
*.md
.env.local

15.4 Nginx 配置:SPA 路由与健康检查

# docker/nginx.conf
server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;

    # 健康检查端点(配合 Docker HEALTHCHECK 与 K8s probe)
    location = /health {
        access_log off;
        default_type text/plain;
        return 200 'ok';
    }

    # 静态资源长缓存(Vite 带 hash)
    location /assets/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # SPA history 模式:非文件请求回退 index.html
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 可选:反向代理 API(生产也可由 Ingress 分流)
    location /api/ {
        proxy_pass http://backend:8000/api/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    gzip on;
    gzip_types text/css application/javascript application/json;
}
配置作用
try_files ... /index.htmlVue Router / React Router history 模式必需
/assets/ 长缓存利用 Vite 文件名 hash
location /api/同源代理,免 CORS(与 ch13 对照)

15.5 docker-compose 本地联调

# docker-compose.yml
services:
  admin-web:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        VITE_API_BASE_URL: http://localhost:8000/api/v1
    ports:
      - '8080:80'
    depends_on:
      backend:
        condition: service_healthy
    networks:
      - xianzi-net

  backend:
    image: xianzi/mall-api:dev
    ports:
      - '8000:8000'
    environment:
      DATABASE_URL: postgres://...
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:8000/health']
      interval: 10s
      timeout: 3s
      retries: 5
    networks:
      - xianzi-net

networks:
  xianzi-net:
docker compose up --build
# 访问 http://localhost:8080

15.6 环境变量注入策略

方式时机适用
构建时 ARG VITE_*docker build常量 API 域名,简单
运行时 env.js容器启动 entrypoint 写文件同一镜像多环境
K8s ConfigMapPod 挂载小紫云标准做法

15.6.1 运行时注入(推荐多环境)

# docker/entrypoint.sh
#!/bin/sh
cat <<EOF > /usr/share/nginx/html/env-config.js
window.__ENV__ = {
  API_BASE_URL: "${API_BASE_URL:-/api/v1}",
  APP_NAME: "${APP_NAME:-贤紫商户后台}"
};
EOF
exec nginx -g 'daemon off;'
<!-- index.html -->
<script src="/env-config.js"></script>
// config/env.ts
export const env = {
  apiBase: (window as any).__ENV__?.API_BASE_URL ?? import.meta.env.VITE_API_BASE_URL,
}

注意VITE_ 变量在 npm run build 时被打包替换;运行时方案需读 window.__ENV__


以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。