K8s集群部署Vue.js应用时history模式下非首页刷新/直接访问出现404错误的技术求助
看起来你的核心问题是Vue Router history模式下,刷新子页面或直接访问子路径时出现404,这是因为服务器没有配置路径回退到index.html的规则。结合你的配置文件,我发现几个关键错误,下面一步步帮你修正:
1. 冗余容器与路径不匹配(Deployment的核心问题)
你在Deployment里部署了两个容器(vue-nginx和vue),还用emptyDir共享静态文件——这完全没必要!你的Dockerfile已经把Vue构建产物打包到Nginx镜像里了,额外的vue容器属于冗余设计,还会导致文件路径混乱。
同时,你的ConfigMap里的Nginx配置监听8080端口,但Service的targetPort是80,容器端口和服务端口不匹配,请求根本无法正确到达后端Nginx的规则处理逻辑。
修正后的Deployment
只保留一个容器,使用你构建好的Vue-Nginx镜像:
apiVersion: apps/v1 kind: Deployment metadata: name: "my-deployment" spec: replicas: 1 selector: matchLabels: app: "my-app" template: metadata: labels: app: "my-app" spec: containers: - name: "vue-nginx" image: XXX/my_image:latest # 替换为你实际的镜像地址 ports: - containerPort: 80 imagePullPolicy: "Always" imagePullSecrets: - name: registry-secret restartPolicy: Always
2. Nginx配置路径与端口错误(ConfigMap/Dockerfile问题)
你的ConfigMap里的default.conf存在两个关键错误:
root /var/www/app:但你的Dockerfile把Vue构建产物放到了/usr/share/nginx/html,路径完全不匹配listen 8080 default:和容器、服务的80端口不一致
更简单的方案:直接在Dockerfile中嵌入正确配置
不需要使用ConfigMap,直接在构建镜像时加入符合Vue history模式的Nginx配置,这样更可靠:
第一步:在本地项目根目录创建nginx/default.conf
server { listen 80; root /usr/share/nginx/html; index index.html; # 核心规则:所有不存在的路径回退到index.html,支持Vue Router history模式 location / { try_files $uri $uri/ /index.html; } # 可选:给静态资源添加缓存,优化加载速度 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } }
第二步:修改Dockerfile
# 构建环境 FROM node:12.2.0-alpine as build WORKDIR /app ENV PATH /app/node_modules/.bin:$PATH COPY ./[项目文件夹]/ . RUN npm config set unsafe-perm true RUN npm install --silent RUN npm install @vue/cli@3.7.0 -g RUN npm run build # 生产环境 FROM nginx:1.16.0-alpine # 加入Vue history模式需要的Nginx配置 COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf # 复制构建好的静态文件到Nginx默认目录 COPY --from=build /app/dist /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
3. Ingress配置简化优化
你的Ingress配置用了/.*正则路径,其实没必要这么复杂。只要设置path: /并指定pathType: Prefix,就能让所有路径都转发到后端服务,再由后端Nginx处理回退逻辑。
修正后的Ingress.yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: foo-ingress-lb annotations: kubernetes.io/ingress.class: "nginx" kubernetes.io/tls-acme: "true" cert-manager.io/issuer: letsencrypt-prod # 移除不必要的正则注解 spec: tls: - hosts: - www.foo.com secretName: tls-secret rules: - host: www.foo.com http: paths: - path: / pathType: Prefix backend: service: name: my-service port: number: 80
验证步骤(确保问题解决)
本地测试镜像:先在本地运行镜像,确认历史模式正常工作
docker build -t vue-app . docker run -p 8080:80 vue-app访问
http://localhost:8080/your-sub-page,刷新页面看是否还会404。K8s容器内验证配置:部署后进入容器检查Nginx配置和静态文件
kubectl exec -it <你的Pod名称> -- cat /etc/nginx/conf.d/default.conf kubectl exec -it <你的Pod名称> -- ls /usr/share/nginx/html检查Ingress规则:确认Ingress已经正确生效
kubectl describe ingress foo-ingress-lb
内容的提问来源于stack exchange,提问作者Brice Le Roux

