作为一个既懂前端又懂服务器的工程师,最值钱的能力是把”代码”和”部署”打通。本文落地一条完整的 CI/CD 流水线:提交代码后自动 lint、测试、构建,打包成 Docker 镜像推送到仓库,再在服务器上用 Nginx 容器提供访问。整条链路跑通,就是实打实的工程化加分项。
一、为什么需要 CI/CD
没有 CI/CD 的项目常见痛点:
- 每次发版手动
npm run build、手动scp上传,容易漏文件、传错环境; - 代码合并前没人跑测试,问题到线上才暴露;
- 回滚靠”找上次的压缩包”,没有版本记录。
CI/CD 的价值一句话:把”人工容易出错”的环节全部自动化,让每一次提交都经过相同的、可复现的流水线。持续集成(CI)保证质量,持续交付/部署(CD)保证快速上线。
二、整体架构
开发者 push 代码
│
▼
GitHub Actions(CI)
├── lint + unit test(质量门禁)
├── npm run build(构建产物)
└── docker build + push(制作并推送镜像)
│
▼
服务器(CD)
└── docker pull + docker run(Nginx 容器提供服务)
三、前端配置:Dockerfile + Nginx
前端项目要能容器化,需要处理 SPA 的前端路由回退问题(否则刷新子页面 404,这是我在《vue-cli 项目在 nginx 下子页面刷新404》里讲过的经典坑)。
# 多阶段构建:先用 node 构建,再用 nginx 运行(镜像小)
# 阶段1:构建
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 阶段2:运行
FROM nginx:1.27-alpine
# SPA 路由回退 + gzip 的 nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
# nginx.conf —— 解决 SPA 刷新 404,并开启 gzip 压缩
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_types text/plain text/css application/javascript application/json;
# 关键:所有找不到的文件回退到 index.html(前端路由)
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源长缓存
location /assets/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
用
npm ci而不是npm install:它会严格按照package-lock.json安装,保证 CI 环境与本地一致,且更快更可靠。
四、CI 流水线:GitHub Actions
在仓库创建 .github/workflows/deploy.yml:
name: CI/CD
on:
push:
branches: [ main ]
workflow_dispatch: # 支持手动触发
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 安装依赖
run: npm ci
- name: 代码规范检查
run: npm run lint
- name: 单元测试
run: npm run test
- name: 构建
run: npm run build
- name: 构建并推送 Docker 镜像
run: |
docker build -t my-app:$ .
echo "$" | docker login -u "$" --password-stdin
docker push my-app:$
- name: 服务器部署(SSH 执行脚本)
uses: appleboy/ssh-action@v1
with:
host: $
username: $
key: $
script: |
docker pull my-app:$
docker stop my-app || true
docker rm my-app || true
docker run -d --name my-app -p 8080:80 my-app:$
敏感信息用 Secrets:
REGISTRY_USER、SERVER_SSH_KEY等一律存到仓库 Settings → Secrets,绝不能写进代码。这也是运维安全意识的一个加分体现。
五、回滚与灰度
有了镜像版本(用 commit sha 或 tag 标记),回滚就非常简单:
# 一键回滚到上一个版本
docker stop my-app && docker rm my-app
docker run -d --name my-app -p 8080:80 my-app:<旧版本sha>
更进阶的是蓝绿部署(两套环境切换)或金丝雀发布(灰度放量),配合 Nginx 的 upstream 负载均衡——这正好接上我之前写的《Nginx 负载均衡》文章。
六、总结:这条链路的面试价值
为什么这条流水线值得写进你的项目经历?
- 体现”全链路”思维:不是只会写前端,而是理解代码如何走到线上;
- 体现质量意识:lint + 单测作为质量门禁,防止烂代码合并;
- 体现运维能力:Docker 镜像、Nginx 配置、SSH 部署,正好是你擅长的领域;
- 体现可维护性:版本化、可回滚、自动化,这是团队协作和大项目最看重的。
面试讲项目时,能用一句话概括:”我搭建了一条从代码提交到 Docker 容器部署的全自动流水线,每次提交都会自动过 lint、单测、构建,并滚动发布到服务器,出问题能秒级回滚。”——这句话的含金量,远超”我会写 Vue 页面”。
结合我博客里的《Docker 常用命令》《Centos 安装 docker-compose》《Nginx 负载均衡》《基于 Docker 搭建 frp 内网穿透》等文章,你已经具备从开发到部署的完整知识闭环。
