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-portal
和 teacher-portal
的 SPA 的非生产集群中,我将为 student-portal.mydomain.com
、teacher-portal.mydomain.com
创建指向 public 的 DNS 记录集群负载均衡器的IP。
在入口资源的规则中包含域名。
我发现这是最有效的方法,避免了需要单独处理每个 SPA 框架。
我们将 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-portal
和 teacher-portal
的 SPA 的非生产集群中,我将为 student-portal.mydomain.com
、teacher-portal.mydomain.com
创建指向 public 的 DNS 记录集群负载均衡器的IP。
在入口资源的规则中包含域名。
我发现这是最有效的方法,避免了需要单独处理每个 SPA 框架。