kubernetesmqttmosquitto

Run eclipse-mosquitto MQTT broker docker image and custom paho-mqtt Python clients inside minikube Kubernetes cluster


I want to run an MQTT broker and two clients inside a Kubernetes cluster and be able to send messages back and forth.

Therefore I wanted to use the eclipse-mosquitto Docker image and two custom clients that use the paho-mqtt Python library:

import paho.mqtt.client as mqtt
import time

broker_address = "localhost"
port = 1883
client_id = "client1"
counter = 0

def on_message(client, userdata, message):
    global counter
    counter += 1
    print(f"Client 1 received: {message.payload.decode()} - counter: {counter}")
    time.sleep(1)
    client.publish("test/topic", f"Client 1: {counter}")

client = mqtt.Client(client_id)
client.on_message = on_message
client.connect(broker_address, port=port)
client.subscribe("test/topic")
client.loop_start()

while True:
    client.publish("test/topic", f"Client 1: {counter}")

This works perfectly fine in Docker when putting all of them on the same Docker network. The broker container is named mosquitto-broker which can then be found by the clients. They subscribe to a topic and publish messages on it.

However, recreating the same use-case on a Kubernetes cluster seems to require a different approach, since K8s has an own networking ecosystem and the broker_address will be different. Since my docker images mqtt_client_1 and mqtt_client_2 are local, I set the imagePullPolicy to Never.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mqtt-deployment
  labels:
    app: mqtt
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mqtt
  template:
    metadata:
      labels:
        app: mqtt
    spec:
      containers:
        - name: eclipse-mosquitto
          image: eclipse-mosquitto
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 1883
          volumeMounts:
            - name: mosquitto-config
              mountPath: /mosquitto/config/mosquitto.conf
              subPath: mosquitto.conf
        - name: mqtt-client1
          image: mqtt_client_1
          imagePullPolicy: Never
          command:
            - python
            - /app/client1.py
        - name: mqtt-client2
          image: mqtt_client_2
          imagePullPolicy: Never
          command:
            - python
            - /app/client2.py
      volumes:
        - name: mosquitto-config
          configMap:
            name: mosquitto-config

I also use a configmap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mosquitto-config
data:
  mosquitto.conf: |-
    listener 1883
    allow_anonymous true

However, the client pod exits with Name or service not known when trying to connect on the broker_address and port. How can I make client and server communicate via MQTT on the same network?


Solution

  • You will need to include a kubernetes Service description that points to the Deployment.

    The name of the service will then be the hostname you use in the client code to connect to the broker.

    e.g.

    apiVersion: v1
    kind: Service
    metadata:
      name: mqtt-broker
    spec:
      selector:
        app: mqtt
      ports:
        - name: mqtt-native
          targetPort: 1883
          port: 1883
    

    You would use mqtt-broker as the hostname (or mqtt-broker.<namespace> for cross namespace accesss)