Search code examples
kubernetesmqttmosquittok3s

I cant connect to MQTT over Kubernetes (K3s on RPI Cluster)


Hey guys so ive hit a bit of a snag. I was able to successfully run my yaml files and get containers running for MQTT. The problem is when I try to connect to it, it just doesnt work. So here are my YAML Files

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    kompose.cmd: kompose convert
    kompose.version: 1.22.0 (955b78124)
  creationTimestamp: null
  labels:
    io.kompose.service: mqtt
  name: mqtt
  namespace: mqtt
spec:
  replicas: 2
  selector:
    matchLabels:
      io.kompose.service: mqtt
  strategy:
    type: Recreate
  template:
    metadata:
      annotations:
        kompose.cmd: kompose convert
        kompose.version: 1.22.0 (955b78124)
      creationTimestamp: null
      labels:
        io.kompose.service: mqtt
    spec:
      containers:
        - image: eclipse-mosquitto
          name: mqtt
          ports:
            - containerPort: 1883
            - containerPort: 9001
          resources: {}
          volumeMounts:
            - name: mosquitto-config-file
              mountPath: /mosquitto/config
            - name: mosquitto-pwfile
              mountPath: /mosquitto/config/pwfile
            - name: mqtt-data-pvc
              mountPath: /mosquitto/data
            - name: mqtt-log-pvc
              mountPath: /mosquitto/log
      restartPolicy: Always
      volumes:
        - name: mosquitto-config-file
          configMap:
            name: mosquitto-config
        - name: mosquitto-pwfile
          secret:
            secretName: mosquitto-pwfile
        - name: mqtt-data-pvc
          persistentVolumeClaim:
            claimName: mqtt-data-pvc
        - name: mqtt-log-pvc
          persistentVolumeClaim:
            claimName: mqtt-log-pvc
status: {}
---
apiVersion: v1
kind: Service
metadata:
  name: mqtt
  namespace: mqtt
spec:
  ports:
    - name: "1883"
      port: 1883
      targetPort: 1883
    - name: "9001"
      port: 9001
      targetPort: 9001
  selector:
    io.kompose.service: mqtt
status:
  loadBalancer: {}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: mosquitto-config
  namespace: mqtt
data:
  mosquitto.conf: |

    persistence true
    persistence_location /mosquitto/data
    log_dest file /mosquitto/log/mosquitto.log

    listener 1883
    protocol mqtt

    listener 9001
    protocol websockets 

    allow_anonymous false
    password_file /mosquitto/config/pwfile/pwfile
---
apiVersion: v1
kind: Secret
metadata:
  name: mosquitto-pwfile
  namespace: mqtt
type: Opaque
data:
  pwfile: |
    <BASE64 USERNAME:PW>
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mosquitto-data-pv
  namespace: mqtt
spec:
  capacity:
    storage: 100Mi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-path
  local:
    path: /home/pi/Software/mqtt/storage/mosquitto/data
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - masternode
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mqtt-data-pvc
  namespace: mqtt
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Mi
status: {}
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mosquitto-log-pv
  namespace: mqtt
spec:
  capacity:
    storage: 100Mi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-path
  local:
    path: /home/pi/Software/mqtt/storage/mosquitto/log
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - masternode
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mqtt-log-pvc
  namespace: mqtt
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Mi
status: {}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: mqtt-ingress
  namespace: mqtt
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
  rules:
  - host: mqtt.local
    http:
      paths:
        - pathType: Prefix
          path: "/"
          backend:
            service:
              name: mqtt
              port: 
                number: 1883

When I check if my containers are running they are running fine. When I check the logs it shows the following

1618785757: mosquitto version 2.0.10 starting
1618785757: Config loaded from /mosquitto/config/mosquitto.conf.
1618785757: Opening ipv4 listen socket on port 1883.
1618785757: Opening ipv6 listen socket on port 1883.
1618785757: Opening websockets listen socket on port 9001.
1618785757: mosquitto version 2.0.10 running

I try to connect on mqtt.local (as per the ingress) on port 1883 and the logs dont update and it just says connecting using my iPad app

If I go to mqtt.local on my browser the logs do update (I believe they are using websockets) and it shows the following

1618786368: Client <unknown> disconnected due to protocol error.
1618786368: New connection from 10.42.1.3:48912 on port 1883.
1618786368: Client <unknown> disconnected due to protocol error.
1618786368: New connection from 10.42.1.3:57298 on port 1883.
1618786368: Client <unknown> disconnected due to protocol error.

I'll be honest. I'm pretty stumped. Confirmed the username and password a dozen times. Open to ideas if anybody has some to share. Thanks in advance


Solution

  • Your Ingress declaration points to port 1883 which is running native MQTT over TCP.

    Ingress sets up a HTTP reverse proxy that points to the service, since MQTT is not HTTP this just won't work.

    As pointed out in the comments one option is to change the Ingress to point to port 9001 which is your WebSocket Listener on the broker

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: mqtt-ingress
      namespace: mqtt
      annotations:
        kubernetes.io/ingress.class: nginx
        nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
    spec:
      rules:
      - host: mqtt.local
        http:
          paths:
            - pathType: Prefix
              path: "/"
              backend:
                service:
                  name: mqtt
                  port: 
                    number: 9001
    

    You will then be able to connect with any MQTT clients that support MQTT over Websockets as that protocol is bootstrapped via HTTP.

    It's also worth pointing out that the Ingress reverse proxy will be exposing this route on port 80.

    The only other way to connect is to connect directly to the cluster node that is running the MQTT broker. But this will mean changing the ServiceType to NodePort or LoadBalancer and mapping an external IP address.