如何在 Kubernetes 上正确部署 Blazor Server 应用程序

问题描述 投票:0回答:1

我正在尝试在本地 Kubernetes 集群中部署测试 Blazor 服务器端应用程序。我已将其配置为可以通过服务或 nginx-ingress 访问它。然而,这两种途径都有其自身的问题,导致应用程序在服务后无法正常运行。

通过服务提供时,它看起来像this。我相信这就是它应该的样子。但是,有很多错误导致我根本无法与该页面交互。 错误:

blazor.server.js:1 WebSocket connection to 'ws://172.25.217.142:30500/_blazor?id=1qrCqjxomf15Rd6QTY11rw' failed: 
(anonymous) @ blazor.server.js:1
blazor.server.js:1 [2024-01-23T20:20:31.036Z] Information: (WebSockets transport) There was an error with the transport.
blazor.server.js:1 [2024-01-23T20:20:31.036Z] Error: Failed to start the transport 'WebSockets': Error: WebSocket failed to connect. The connection could not be found on the server, either the endpoint may not be a SignalR endpoint, the connection ID is not present on the server, or there is a proxy blocking WebSockets. If you have multiple servers check that sticky sessions are enabled.
log @ blazor.server.js:1
blazor.server.js:1 [2024-01-23T20:20:31.107Z] Warning: Failed to connect via WebSockets, using the Long Polling fallback transport. This may be due to a VPN or proxy blocking the connection. To troubleshoot this, visit https://aka.ms/blazor-server-using-fallback-long-polling.
log @ blazor.server.js:1
:30500/_blazor?id=eC3fba0OdI6vu_KNZl9_Kg:1 
        
        
       Failed to load resource: the server responded with a status of 404 (Not Found)
blazor.server.js:1 Uncaught (in promise) Error: No Connection with that ID: Status code '404'
    at ut.send (blazor.server.js:1:39443)
    at async rt (blazor.server.js:1:36427)
    at async _t._sendLoop (blazor.server.js:1:61855)
:30500/_blazor?id=eC3fba0OdI6vu_KNZl9_Kg:1 
        
        
       Failed to load resource: the server responded with a status of 404 (Not Found)
blazor.server.js:1 Uncaught (in promise) Error: No Connection with that ID: Status code '404'
    at ut.send (blazor.server.js:1:39443)
    at async rt (blazor.server.js:1:36427)
    at async _t._sendLoop (blazor.server.js:1:61855)
:30500/_blazor?id=eC3fba0OdI6vu_KNZl9_Kg:1 
        
        
       Failed to load resource: the server responded with a status of 404 (Not Found)
blazor.server.js:1 Uncaught (in promise) Error: No Connection with that ID: Status code '404'
    at ut.send (blazor.server.js:1:39443)
    at async rt (blazor.server.js:1:36427)
    at async _t._sendLoop (blazor.server.js:1:61855)
:30500/_blazor?id=eC3fba0OdI6vu_KNZl9_Kg:1 
        
        
       Failed to load resource: the server responded with a status of 404 (Not Found)
blazor.server.js:1 Uncaught (in promise) Error: No Connection with that ID: Status code '404'
    at ut.send (blazor.server.js:1:39443)
    at async rt (blazor.server.js:1:36427)
    at async _t._sendLoop (blazor.server.js:1:61855)

WebSockets 似乎存在一些问题,但我不知道如何解决。

当在入口处供应时,它看起来像this。这显然是不正确的,但我只收到一个错误:

blazor.server.js:2 Uncaught SyntaxError: Unexpected token '<'

我不知道那是什么文件,因为我无法从 DevTools Console 打开它,并且无法在 DevTools Source 窗格中找到它。它似乎也不在应用程序的代码库中。

我在 Windows Hyper-V 上运行 Minikube。该应用程序是 Visual Studio 2022 中的默认服务器端 Blazor 应用程序。不过,我对默认 Dockerfile 进行了一些更改:

#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["WebApp.csproj", "WebApp/"]
RUN dotnet restore "./WebApp/./WebApp.csproj"
COPY . .
WORKDIR "/src/WebApp"
RUN dotnet build "./WebApp.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./WebApp.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApp.dll"]

有什么线索可以解释导致这两个问题的原因吗?

编辑:这是我的 Kubernetes .yaml 文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: blazor
  labels:
    app: blazor
spec:
  replicas: 3
  selector:
    matchLabels:
      app: blazor
  template:
    metadata:
      labels:
        app: blazor
    spec:
      containers:
      - name: blazor
        image: registry/...
        ports:
        - containerPort: 80
      imagePullSecrets:  
      - name: test-webapp

apiVersion: v1
kind: Service
metadata:
  labels:
    app: blazor
  name: blazor
  namespace: default
spec:
  ports:
  - nodePort: 30500
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: blazor
  type: NodePort
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blazor-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "affinity"
    nginx.ingress.kubernetes.io/session-cookie-expires: "14400"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "14400"
spec:
  rules:
    - host: blazor.test
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: blazor
                port:
                  number: 80
kubernetes blazor-server-side minikube nginx-ingress
1个回答
0
投票

我们这里有 2 个问题

  • 入口路线
  • SignalR 与负载均衡器

入口路线

nginx.ingress.kubernetes.io/rewrite-target: /$1

然后重写有

$1
,大概意思是放在第一位
capturing group
,但是它是什么?嗯,只有添加
nginx.ingress.kubernetes.io/use-regex
时才能使用它,所以它没有任何意义,当发送请求获取像
/styles.css
这样的文件时,它最终会在 Blazor 应用程序中得到类似
/$1styles.css
的内容从您的应用程序角度来看,其他任何内容都无效。

你可以举个例子

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blazor-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "affinity"
    nginx.ingress.kubernetes.io/session-cookie-expires: "14400"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "14400"
spec:
  rules:
    - host: blazor.test
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: blazor
                port:
                  number: 80

一切都应该有效,但是将

/
(
path: /
) 重写为
/
(
rewrite-target: /
) 以我们乞求的方式结束,因此删除带有
rewrite-target
的行具有完全相同的效果。

使用正则表达式的另一个示例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blazor-ingress
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "affinity"
    nginx.ingress.kubernetes.io/session-cookie-expires: "14400"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "14400"
spec:
  rules:
    - host: blazor.test
      http:
        paths:
          - path: /(.*)
            pathType: Prefix
            backend:
              service:
                name: blazor
                port:
                  number: 80

在这种情况下,在

path
中,我们有
/(.*)
,还有一个
capturing group
,什么是
(.*)
(要使路径
/
正常工作,你必须有
*
而不是
+
),然后
rewrite 
出现,它显示
/$1
,因为我们启用了正则表达式来代替
$1
,将使用存储在第一个捕获组中的值。

SignalR 与负载均衡器

SignalR 与 Blazor 后端建立连接需要发送 2 个请求

  • 洽谈
  • 连接

第一个请求将在响应中发送

connectionToken
,然后该令牌将用于连接,因此,如果您有多个副本,则有可能(随着副本数量的增加)这两个请求将有两个不同一。为了解决这个问题,微软建议使用一些额外的注释来强制入口始终使用基于cookie的相同副本,因此
Negotiate
Connect
将始终命中相同的副本,并且不会出现问题(还有一些关于的GitHub问题)它.

要回答为什么它不能与

NodePort
一起使用的问题,因为我们已经知道它发送两个请求,它们必须命中同一个副本,但是服务
NodePort
没有像
nginx.ingress.kubernetes.io/affinity
这样的功能来强制将请求发送到始终使用相同的副本,并且没有解决方案期望仅使用一个副本(或者至少我不知道)。

© www.soinside.com 2019 - 2024. All rights reserved.