Vue 3 单页应用通常以 Vite 作为构建工具,产物是静态目录 dist。随着项目进入持续交付阶段,团队需要为每次代码合并构建镜像、运行测试、推送制品,并同步更新 Kubernetes 集群中的部署。如果这些步骤分散在多个脚本里,维护成本会快速上升。Jenkins X 基于 Tekton 和 GitOps 把这些过程抽象成仓库内的声明式配置,但把它应用到 Vue 3 工程中,需要先理解目录、Dockerfile、Helm Chart 以及流水线文件各自承担的职责。

一、Jenkins X 对 Vue 3 工程的结构要求
Jenkins X 默认会从仓库根目录寻找 Dockerfile 和 charts 目录,这两个部分是容器化与 Kubernetes 部署的基础。Vue 3 项目在本地开发时使用 Vite 开发服务器,但生产环境必须由 Nginx 之类的静态服务器托管 dist 目录。因此第一步是添加一个多阶段构建的 Dockerfile,把前端构建和运行环境拆开,避免把 node_modules 打进最终镜像。多阶段构建还能显著减小镜像体积,对云原生环境下的拉取速度很有帮助。
# 多阶段构建 Vue 3 项目 FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM nginx:1.25-alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
上面这份 Dockerfile 使用了 npm ci 而不是 npm install,因为它严格依据 package-lock.json 安装依赖,适合 CI 环境,能避免本地 node_modules 版本漂移。第二阶段复制 dist 和 Nginx 配置,不包含任何构建工具,最终镜像通常只有几十 MB。对于企业级 Vue 3 项目,还可以在第二阶段加入 nginx:1.25-alpine 的非 root 用户配置,但需要额外处理权限,这里先保持简单。
Nginx 配置中要重点处理 Vue Router 的 history 模式。如果用户直接访问 /user/profile 这样的深层路由,Nginx 会尝试在文件系统中查找对应文件,找不到就返回 404。正确做法是使用 try_files 回退到 index.html,由前端路由接管。下面是一个适合 Vue 3 的 nginx.conf 示例:
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
除了 Dockerfile 和 Nginx,Jenkins X 还需要 Helm Chart 来描述应用在 Kubernetes 中的资源。通常会在仓库下创建 charts/myapp 目录,包含 Chart.yaml、values.yaml 和 templates 目录。Vue 3 应用属于无状态服务,只需要 Deployment 和 Service 即可,如果集群已经安装了 ingress-nginx,还可以加一个 Ingress 资源暴露预览 URL。Helm values 中要定义镜像仓库、tag、副本数和服务端口,具体值由流水线在构建时动态注入。
# charts/myapp/values.yaml
replicaCount: 2
image:
repository: gcr.io/my-project/vue-app
tag: latest
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
hosts:
- host: vue-app-preview.ipipp.com
paths:
- path: /
实际使用中,Values 文件不会写死镜像 tag,而是由 Jenkins X 构建流水线通过 --set image.tag=... 或环境变量覆盖。预览环境可以使用独立的 values-preview.yaml,将副本数降为 1,并关闭某些非必要资源以节省集群预算。
二、编写流水线文件驱动构建与部署
Jenkins X 可以使用 Lighthouse 根据仓库中的 .lighthouse 配置自动生成 Tekton Pipeline,也可以保留传统 Jenkinsfile 做更细粒度的控制。对于 Vue 3 项目,构建步骤涉及依赖安装、单元测试、生产构建、镜像打包和 GitOps 更新,使用 Jenkinsfile 会更容易理解每一步的作用。下面是一份针对 Vue 3 的声明式流水线示例:
pipeline {
agent any
environment {
IMAGE = 'gcr.io/my-project/vue-app'
VITE_API_BASE_URL = 'https://api.ipipp.com'
}
stages {
stage('Install') {
steps {
sh 'npm ci'
}
}
stage('Test') {
steps {
sh 'npm run test:unit'
sh 'npm run lint'
}
}
stage('Build') {
steps {
sh 'npm run build'
}
}
stage('Package') {
steps {
sh "docker build -t ${IMAGE}:${env.BUILD_NUMBER} ."
sh "docker push ${IMAGE}:${env.BUILD_NUMBER}"
}
}
stage('Update GitOps') {
steps {
sh "jx step post build --image ${IMAGE}:${env.BUILD_NUMBER}"
}
}
}
}
这份流水线把 Vite 的环境变量 VITE_API_BASE_URL 放到了 environment 块里,因为 Vite 在构建时会把以 VITE_ 开头的变量写入产物。如果 vue 组件中使用了 import.meta.env.VITE_API_BASE_URL,必须在执行 npm run build 之前注入该变量。生产环境和预览环境通常需要不同的 API 地址,因此可以把 environment 改为参数化配置,或者根据分支名动态设置。
流水线的最后一步执行 jx step post build,这一步并不是直接操作 Kubernetes 集群,而是把新镜像的 tag 写入独立的 GitOps 环境仓库。Jenkins X 会在集群中运行 jx-git-operator,监听环境仓库的变更并自动同步到集群。这样做的好处是部署历史全部留在 Git 提交记录里,回滚只需要 revert 一次提交。对于 Vue 3 项目来说,GitOps 仓库中的 Deployment 文件 image 字段会被自动更新,例如:
# 环境仓库中的 deployment.yaml
spec:
template:
spec:
containers:
- name: vue-app
image: gcr.io/my-project/vue-app:1.2.3
ports:
- containerPort: 80
在项目仓库的根目录还需要添加 jx-requirements.yml 文件,声明环境仓库地址、 ingress 配置和集群信息。这个文件是 Jenkins X 安装和升级时识别项目上下文的关键,缺失会导致 jx step post build 无法找到对应的 GitOps 仓库。一个最小化的配置如下:
# jx-requirements.yml cluster: provider: gke environmentGitOwner: my-org project: my-project environments: - key: dev - key: staging - key: production
三、预览环境与自动发布
预览环境是 Jenkins X 最大的效率提升点之一。每当开发者提交 Pull Request,Lighthouse 会触发一次 Preview Pipeline,构建出该 PR 独有的镜像并部署到一个独立命名空间,评论中会生成预览 URL。对 Vue 3 前端来说,预览环境可以连接测试环境的 API,让产品、测试和开发在合并前直接验证界面和交互。要实现这个效果,需要在 charts 目录下增加 preview 子 chart,并用 jx preview 命令或 Lighthouse 的 preview 配置自动创建。
创建 preview chart 时,可以为预览环境设置独立的 Values,例如将副本数设为 1,关闭自动扩缩容,同时注入 PR 特定的 API 地址。下面是一个 preview values 的片段:
# charts/preview/values.yaml
replicaCount: 1
image:
repository: gcr.io/my-project/vue-app
tag: PR-123
service:
type: ClusterIP
port: 80
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
hosts:
- host: vue-app-pr-123.preview.ipipp.com
paths:
- path: /
env:
- name: VITE_API_BASE_URL
value: https://api-test.ipipp.com
上述 Values 中的 tag: PR-123 和 host 名通常不是手写死的,而是由 Jenkins X 的 preview pipeline 通过模板参数动态生成。Lighthouse 会把 PULL_NUMBER 和 PULL_BASE_REF 等环境变量传给构建,Jenkinsfile 或 Tekton 任务可以利用它们构造 tag 和 ingress host。Vue 3 应用本身不需要为预览环境做代码改动,只要保证接口地址通过环境变量注入即可。
生产发布流程则依赖 main 分支的 push 事件。当代码合并到 main,Lighthouse 触发 Release Pipeline,执行测试、构建镜像、打 tag、更新 GitOps 环境仓库的 staging 条目。如果 staging 验证通过,可以手动或自动 promote 到 production 环境。这个 promote 动作在 Jenkins X 中通常是一个 jx promote 命令,或者通过点击 UI 触发。对于 Vue 3 项目,生产发布的重点往往是静态资源的 CDN 缓存策略,因此在 release pipeline 里可以增加一步把 dist 上传到对象存储或 CDN,同时让 Kubernetes 中的 Nginx 只负责 index.html 和回源。
stage('Promote to Production') {
when {
branch 'main'
}
steps {
sh 'jx promote --env production --version ${env.BUILD_NUMBER}'
}
}
如果不想在 Jenkinsfile 中维护 promote 逻辑,也可以使用 Jenkins X 自带的 Release Controller,它会在 main 分支自动创建 GitHub Release 并触发下游环境更新。无论哪种方式,Vue 3 前端应用在 Kubernetes 中的滚动更新会由 Deployment 默认策略完成,Nginx 会平滑切换新旧 Pod,用户无感知。
四、常见问题与优化建议
第一个常见问题是 Vue Router 使用 history 模式时,预览环境或生产环境的深层链接刷新出现 404。这在前面的 Nginx 配置中已经通过 try_files $uri $uri/ /index.html; 解决,但如果你的应用部署在子路径下,还需要在 Vue Router 中设置 createWebHistory(import.meta.env.BASE_URL),并且 Nginx 的 location 块也要相应调整。另一个相关问题是静态资源 404,这通常是因为 Vite 的 base 配置与 ingress 路径不一致,需要检查 vite.config.js 中的 base 字段。
Vite 环境变量是构建时注入的,这意味着你不能在运行时修改 VITE_API_BASE_URL 而不重新构建镜像。对于需要频繁切换 API 地址的预览环境,可以考虑把 API 地址放在一个运行时加载的 config.js 文件中,由 Nginx 在启动时通过环境变量替换,或者由前端在应用初始化时请求一个 /config.json 接口。这样镜像只构建一次,不同环境通过挂载不同 config 文件区分,能减少镜像仓库的存储占用和构建次数。
镜像构建速度方面,Vue 3 项目依赖通常较多,如果每次流水线都从零开始 npm ci 会非常耗时。可以使用 Docker BuildKit 的缓存挂载,将 node_modules 缓存到构建节点本地,而不是写进镜像层。下面是一个改进后的 Dockerfile 片段:
# syntax=docker/dockerfile:1.4 FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN --mount=type=cache,target=/root/.npm npm ci COPY . . RUN npm run build
这个配置需要 Jenkins X 的 Tekton 任务使用支持 BuildKit 的容器运行时,或使用 kaniko 并开启缓存参数。如果集群没有 BuildKit 支持,也可以退而求其次使用 npm ci --prefer-offline 并配置 npm 缓存目录,效果不如挂载缓存但实现更简单。
调试流水线时,可以先用 jx get build logs 查看最近一次构建输出,如果构建失败发生在 npm 步骤,大部分是依赖版本或 lock 文件不一致。另一个常用命令是 jx get applications 查看当前部署的应用状态。对于预览环境,如果 ingress 地址无法访问,可以先检查 kubectl get ingress -n jx-preview-xxx 是否分配了地址,再检查 Nginx ingress 控制器的日志。Vue 3 项目本身构建产物是静态文件,只要镜像成功启动,问题多半出在路由或环境变量上。