SPA 应用程序(Vue、React、Angular)在 Kubernetes 上的 Nginx 入口控制器后面无法正常工作

SPA applications (Vue, React, Angular) not working properly behind Nginx ingress controller on Kubernetes

我们将 AKS(Azure Kubernetes 服务)用于托管 Kubernetes 集群,在很大程度上我们对该平台带来的好处感到满意,但我们也面临一些问题。

在 AKS 上,如果您托管 LoadBalancer 类型的服务,它会自动创建一个新的动态 IP 地址(Azure 资源)并将其分配给该服务。如果你想加入白名单,这不是最佳选择,而且根本没有意义,因此我们切换到 Nginx 入口控制器(没有特别的理由选择 Nginx)。我们有很多应用程序 - APIs、SPA、整个集群的 1 个入口控制器和每个环境单独的集群 - QA/Sta/Prod 等。所以我们需要以某种方式管理路由,并且入口路径参数感觉喜欢的路要走。示例:

http://region.azurecloud.com/students/

http://region.azurecloud.com/courses/

其中学生课程是入口路径然后你可以添加 /api/student 例如访问特定的 API。结果将是 http://region.azurecloud.com/students/api/student/1 这并不完美,但现在可以完成工作。

入口是这样的:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: students-api-ingress
  namespace: university
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: https://region.azurecloud.com
      http:
        paths:
          - backend:
              serviceName: students-api-service
              servicePort: 8001
            path: /students(/|$)(.*)

然而,这在 React、Vue 或 Angular 等 SPA 应用程序中效果不佳。无论技术如何,我们都面临着同样的问题。它们在 docker 中托管在 Nginx 后面,所以 Dockerfile 是这样的:

# build environment
FROM node:12.2.0-alpine as build
WORKDIR /app
COPY package*.json /app/
RUN npm install --silent
COPY . /app
RUN npm run build

# production environment
FROM nginx:1.16.0-alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

这里是 nginx.conf 文件:

server {
  listen 80;

  location / {
    root /usr/share/nginx/html;
    try_files $uri $uri/ /index.html =404;
    index  index.html index.htm;

  error_page 500 502 503 504  /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }

    if ($request_method = 'OPTIONS') {
          add_header 'Access-Control-Allow-Origin: $http_origin');
          add_header 'Access-Control-Allow-Origin: GET, POST, DELETE, PUT, PATCH, OPTIONS');
          add_header 'Access-Control-Allow-Credentials: true');
          add_header 'Vary: Origin');

      }

       add_header 'Access-Control-Allow-Origin' "$http_origin" always;
       add_header 'Access-Control-Allow-Credentials' 'true' always;
       add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE, OPTIONS' always;
       add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
  }

  include /etc/nginx/extra-conf.d/*.conf;
}

当应用程序访问 .js 文件或图像等资产时,就会出现问题。它以 ingress.host/asset.name 格式创建 url,例如 http://region.azurecloud.com/2342424ewfwer.js instead of including the ingress path as well which would look http://region.azurecloud.com/spa/2342424ewfwer.js 结果是所有资产都出现 404 未找到错误。

如果入口路径只是设置为 / 没有任何重写注释,应用程序可以正常工作,但这是一个问题,因为你不能有多个应用程序使用基础入口主机。一种解决方案是为每个 SPA 应用程序使用单独的入口控制器,但这让我们回到了负载均衡器的最初问题 - 为每个 SPA 应用程序使用单独的负载均衡器和 IP 地址,这是我们在这里想要避免的。

我想我不是唯一一个在 Kubernetes 上的 nginx 入口控制器后面托管 SPA 应用程序的人,但我设法找到的所有类似主题几乎无处可去,没有明确的解决方案应该做什么或建议不起作用为了我们。我想知道问题出在哪里 - nginx 网络服务器或入口控制器,入口控制器通常是管理 Kubernetes 上的应用程序路由的方式。如果有任何帮助或建议,我将不胜感激。

谢谢, R

我通常处理 SPA 的方法是为每个 SPA 使用不同的主机名。例如,在具有两个名为 student-portalteacher-portal 的 SPA 的非生产集群中,我将为 student-portal.mydomain.comteacher-portal.mydomain.com 创建指向 public 的 DNS 记录集群负载均衡器的IP。

在入口资源的规则中包含域名。

我发现这是最有效的方法,避免了需要单独处理每个 SPA 框架。