为Nginx Ingress配置WebSocket服务

对于依赖WebSocket长连接的实时应用,为避免Nginx Ingress默认超时导致连接中断,可通过配置超时注解保证连接稳定。

核心示例

Nginx Ingress 的默认超时设置专为短连接设计,在暴露WebSocket等长连接应用(如在线游戏、实时数据看板)时,可能导致连接意外中断。为确保连接稳定,必须通过Ingress注解(Annotations)调整超时参数以支持 WebSocket 服务。

  • nginx.ingress.kubernetes.io/proxy-read-timeout:设置Ingress从后端服务读取响应的超时时间(默认值60秒)。此超时是指两次成功读取操作之间的最大间隔时间,而非完成整个响应传输的总时间。推荐设置成1小时或更长。

  • nginx.ingress.kubernetes.io/proxy-send-timeout:设置Ingress向后端服务发送请求的超时时间(默认值60秒)。此超时是指两次成功写入操作之间的最大间隔时间,而非完成整个请求传输的总时间。推荐设置成1小时或更长。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" 
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
  name: ws
spec:
  ingressClassName: nginx
  #...

部署WebSocket示例应用

在集群内部署一个WebSocket回声服务,具体示例代码可参考websocket-echo-server

控制台

  1. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 无状态

  2. 无状态页面,单击使用YAML创建资源,然后将以下内容复制到模板区域,单击创建

    示例应用YAML

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: ws
      name: websocket-server
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ws
      template:
        metadata:
          labels:
            app: ws
        spec:
          containers:
          - image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/websocket-echo-server:latest
            imagePullPolicy: IfNotPresent
            name: echo
            env:
             - name: BIND_PORT
               value: "3000"
            ports:
            - containerPort: 3000
              protocol: TCP
            resources:
              limits:
                cpu: 1000m
                memory: 1000Mi
              requests:
                cpu: 100m
                memory: 100Mi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: ws
      name: websocket-server
      namespace: default
    spec:
      ports:
      - name: ws
        port: 3000
        protocol: TCP
        targetPort: 3000
      selector:
        app: ws
      type: ClusterIP
  3. 在弹窗中找到目标无状态应用,单击查看,确认Pod状态为Running。 

kubectl

  1. 获取集群KubeConfig并通过kubectl工具连接集群

  2. 将以下YAML内容保存为websocket.yaml文件。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: ws
      name: websocket-server
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ws
      template:
        metadata:
          labels:
            app: ws
        spec:
          containers:
          - image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/websocket-echo-server:latest
            imagePullPolicy: IfNotPresent
            name: echo
            env:
             - name: BIND_PORT
               value: "3000"
            ports:
            - containerPort: 3000
              protocol: TCP
            resources:
              limits:
                cpu: 1000m
                memory: 1000Mi
              requests:
                cpu: 100m
                memory: 100Mi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: ws
      name: websocket-server
      namespace: default
    spec:
      ports:
      - name: ws
        port: 3000
        protocol: TCP
        targetPort: 3000
      selector:
        app: ws
      type: ClusterIP
  3. 部署WebSocket应用,并创建服务(Service)。

    kubectl apply -f websocket.yaml
  4. 确认目标应用Pod状态为Running

    kubectl get pod | grep websocket-server

配置Ingress暴露服务

Ingress设置代理发送超时时间代理读取超时时间规则。

  1. 登录容器服务管理控制台,单击目标集群名称,在集群详情页左侧导航栏选择组件管理

  2. 在搜索框输入Nginx Ingress Controller并定位组件,然后在目标组件卡片单击安装

    v1.2之前版本的组件已不再维护,请升级Nginx Ingress Controller组件至最新版。
  3. 配置Ingress路由转发及超时注解。

    控制台

    1. 在左侧导航栏,选择网络 > 路由。选择default命名空间,单击创建 Ingress

    2. 添加以下Ingress配置,单击确定

      • 网关类型:选择Nginx Ingress

      • 名称ws

      • 域名test.example.com

      • 路径映射路径/匹配规则默认(ImplementationSpecific)服务名称websocket-server端口3000

      • 注解:名称:nginx.ingress.kubernetes.io/proxy-read-timeout,值:3600,名称:nginx.ingress.kubernetes.io/proxy-send-timeout,值:3600

    3. 路由列表页,查看新建的Ingress,获取访问端点地址。

      Nginx Ingress配置生效大约需要10秒,可稍后单击刷新按钮获取端点信息。若长时间未更新端点信息,可单击路由名称,进入事件页签,进行异常问题排查

    kubectl

    1. 将以下YAML内容保存为websocket-ingress.yaml,然后执行kubectl apply -f websocket-ingress.yaml命令。

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        annotations:
          nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"  # 代理读取超时时间:3600秒
          nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"  # 代理发送超时时间:3600秒
        name: ws
        namespace: default
      spec:
        ingressClassName: nginx
        rules:
        - host: test.example.com           # 服务的访问域名
          http:
            paths:
            - backend:
                service:
                  name: websocket-server   # 上一步中创建的Service名称
                  port:
                    number: 3000           # 上一步中创建的Service暴露端口
              path: /
              pathType: ImplementationSpecific
    2. 获取访问端点地址。Ingress IP分配会有延迟,若无输出结果,可等待10秒后重试。

      ADDRESS=$(kubectl get ingress ws -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
      echo $ADDRESS

访问WebSocket服务

  1. 为便于测试,以下提供本地域名映射方法。

    • macOS / Linuxsudo vi /etc/hosts

    • Windows: 以管理员身份打开记事本,然后打开 C:\Windows\System32\drivers\etc\hosts

    将以下地址替换为实际访问端点地址,在文件末尾添加以下域名映射记录并保存。

    47.102.XX.XX test.example.com
  2. 安装websocat工具,使用WS(WebSocket)协议或WSS(WebSocket Secure)协议访问服务。

    WS协议

    使用WS协议访问WebSocket服务。

    websocat ws://test.example.com

    连接成功后,程序会持续等待输入。可输入任意文本并按回车。如果服务正常,发送的内容将在下一行被原样输出。

    2

    WSS协议

    使用WSS协议访问服务时,需额外为Nginx Ingress Controller开启HTTPS访问。

    1. 购买或生成SSL证书。

    2. (可选)若已从阿里云购买证书,需下载SSL证书文件到本地。

    3. 创建Secret,存储证书及私钥。

      控制台

      1. 登录容器服务管理控制台,在左侧导航栏选择集群列表

      2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择配置管理 > 保密字典

      3. 保密字典页面,选择default命名空间后,单击左侧创建,在弹出面板中配置新的保密字典。配置完成后,单击确定

        • 名称nginx-ingress-tls

        • 类型TLS证书

        • 证书:证书文件(.crt.pem)中的完整内容

        • 密钥:私钥文件(.key)中的完整内容

      kubectl

      将以下<PUBLIC_CERT> <PRIVATE_KEY>替换成实际的证书文件(.crt.pem)路径和私钥文件(.key)路径,然后执行命令将证书和私钥存储为Secret。

      # --key 参数指定私钥文件,--cert 参数指定证书文件
      kubectl create secret tls nginx-ingress-tls --cert <PUBLIC_CERT> --key <PRIVATE_KEY>
    4. 更新Ingress,引用上一步创建的Secret。

      控制台

      1. 在左侧导航栏,选择网络 > 路由。选择default命名空间,单击目标Ingress右侧操作列的更新

      2. 添加以下Ingress配置,单击确定

        • TLS配置:开启。域名test.example.com保密字典nginx-ingress-tls

      kubectl

      ws路由添加TLS配置。

      • 域名test.example.com

      • 证书Secretnginx-ingress-tls

      kubectl patch ingress ws -p '{"spec":{"tls":[{"hosts":["test.example.com"],"secretName":"nginx-ingress-tls"}]}}'
    5. 基于WSS协议连接WebSocket服务。

      当服务采用自签名证书时,需使用 -k 参数以跳过证书验证。若服务采用受信任CA签发的证书,无需额外参数。
      websocat wss://test.example.com

      连接成功后,程序会持续等待输入。可输入任意文本并按回车。如果服务正常,发送的内容将在下一行被原样输出。

      4

常见问题

如何生成自签名证书?

执行以下命令可生成一个域名为test.example.com、有效期为365天的自签名证书(ws.crt)和私钥(ws.key)。

openssl req -x509 -newkey rsa:2048 -keyout ws.key -out ws.crt -days 365 -nodes \
  -subj "/CN=test.example.com" \
  -addext "subjectAltName=DNS:test.example.com"
重要

自签名证书缺乏权威 CA 认证,浏览器及各类客户端默认不予信任,用户访问时将触发安全警告,请勿在生产环境中使用。

SSL证书和TLS证书的区别?

SSL (Secure Sockets Layer) 为早期的加密协议,现已被更安全的TLS (Transport Layer Security) 协议取代。

在行业术语中,“SSL证书”已成为一个习惯性描述,其更准确的名称应为“TLS证书”。

相关文档