0

I am trying to get websockets to work on GKE. Seems very trivial, but I am failing to get this to work, I just continuously keep getting 400 at Nginx Ingress.

The manifest is like this:

apiVersion: v1
kind: Namespace
metadata:
  name: my-test
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-ws-backend
  namespace: my-test
  labels:
    app: my-ws-backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-ws-backend
  template:
    metadata:
      labels:
        app: my-ws-backend
    spec:
      containers:
        - name: backend
          image: ksdn117/web-socket-test
          imagePullPolicy: Always
          ports:
            - containerPort: 8010
          env:
            - name: NODE_ENV
              value: production
            - name: DEBUG
              value: socket*
---
apiVersion: v1
kind: Service
metadata:
  name: my-ws-backend
  namespace: my-test
spec:
  selector:
    app: my-ws-backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8010
  sessionAffinity: ClientIP
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ws-ingress
  namespace: my-test
  annotations:
    nginx.ingress.kubernetes.io/proxy-buffering: "off"
    nginx.ingress.kubernetes.io/upgrade-insecure-requests: "true"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
      proxy_set_header Host $host;
    nginx.ingress.kubernetes.io/server-snippet: |
      error_log /var/log/nginx/error.log debug;
    cert-manager.io/cluster-issuer: letsencrypt-prod-nginx
spec:
  ingressClassName: nginx
  rules:
    - host: ws-my-test.myhost.com
      http:
        paths:
          - path: /socket.io
            pathType: Prefix
            backend:
              service:
                name: my-ws-backend
                port:
                  number: 80
  tls:
    - hosts:
        - ws-my-test.myhost.com
      secretName: ws-my-test-cert

I tried hitting the endpoint with wscat and a simplistic Node.js script shown below to test. What am I missing?

const { io } = require('socket.io-client');

const socket = io('wss://ws-my-test.myhost.com', {
  transports: ['websocket'],
  reconnection: false,
});

socket.on('connect', () => {
  console.log('Connected!');
  socket.disconnect();
});

socket.on('connect_error', (err) => {
  console.error('Connection error:', err);
});

1 Answer 1

0

Got this working in the end, these are the annotations in my Ingress

cert-manager.io/cluster-issuer: letsencrypt-prod-nginx
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/proxy-buffering: "off"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"

I think the problem was including duplicates as my annotations below:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;

which were not required, and caused the header to have duplicate values set in the header, that caused rejection of the request with status 400.

Ingress-NGINX controller already comes preconfigured with the required Upgrade/Connection headers set, so not needed to set them again.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.