Home > OS >  How to connect the docker fast api with mqtt broker?
How to connect the docker fast api with mqtt broker?

Time:02-21

Without docker, I could connect my fastapi app with mqtt broker. However with docker, I cannot connect my fastapi app with the docker mqtt broker. I get the error -

{"log":"    ', '.join(str(exc) for exc in exceptions)))\n","stream":"stderr","time":"2022-02-21T04:42:21.137558005Z"}
{"log":"OSError: Multiple exceptions: [Errno 111] Connect call failed ('127.0.0.1', 1883), [Errno 99] Cannot assign requested address\n","stream":"stderr","time":"2022-02-21T04:42:21.137562299Z"}
{"log":"\n","stream":"stderr","time":"2022-02-21T04:42:21.137566492Z"}
{"log":"ERROR:    Application startup failed. Exiting.\n","stream":"stderr","time":"2022-02-21T04:42:21.137570669Z"}

Here is my main.app

from fastapi import FastAPI
from fastapi_mqtt import FastMQTT, MQTTConfig
from pydantic import BaseModel
from ipaddress import IPv4Address
import jsonpickle

app = FastAPI()


class Nmap(BaseModel):
    host: IPv4Address
    portRange: str

    class Config:
        schema_extra = {
            "example" : {
                "host": "10.0.2.15",
                 "portRange": "22-80",
                 "description": "Scan the port from 22 to 80 of the ip address 10.0.2.15"
            }
        }



mqtt_config = MQTTConfig()

mqtt = FastMQTT(config=mqtt_config)

mqtt.init_app(app)

@mqtt.on_connect()
def connect(client, flags, rc, properties):
    mqtt.client.subscribe("/mqtt/toModel/#") # subscribing mqtt topic wildcard- multi-level
    print("connected: ", client, flags, rc, properties)

@mqtt.on_message()
async def message(client, topic, payload, qos, properties):
    print("received message: ", topic, jsonpickle.decode(payload.decode()), qos, properties)
    return 0 


@mqtt.on_disconnect()
def disconnect(client, packet, exc=None):
    print("Disconnected")

@mqtt.on_subscribe()
def subscribe(client, mid, qos, properties):
    print("subscribed", client, mid, qos, properties)

@app.get("/")
async def func():
    mqtt.client.publish("/mqtt", "Hello from fastApi") 
    return {"result": True, "message": "Published"}

@app.post("/scan/{host}")
async def scan_host_port(nmap_details : Nmap):
    results = {"got_val" : nmap_details}
    print(type(nmap_details))
    mqtt.client.publish("/mqtt/fromModel/nmap", jsonpickle.encode(nmap_details)) 
    return results

Here is my app docker file -

FROM python:3.7

WORKDIR /code 


COPY ./requirements.txt /code/requirements.txt


RUN pip install -r /code/requirements.txt


COPY ./app /code/app

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

For MQTT, I am using -

docker-compose.yml

version: "3"
services:
 mqtt:
      image: toke/mosquitto
      network_mode: bridge
      container_name: mqtt
      expose:
        - 1883
      ports:
        - 1883:1883
      restart: unless-stopped

I am sure it is something with my docker but I don't know how to deploy it.My understanding is that docker is designed to run a single process. So one process for broker, another docker to simply run my fast api and another docker for nginx

CodePudding user response:

127.0.0.1 always points to the TCP/IP stack the current code is bound to.

Every Docker container has it's own TCP/IP stack. So if you try to connect to 127.0.0.1 from the python container there will be no MQTT broker running on port 1883 of it's own TCP/IP stack.

You should have both containers in the same docker compose file using the same network (containers can be bound to multiple networks if needed) and you can then replace the IP address with three service name of the broker e.g. mqtt

CodePudding user response:

version: '3.5'

services:
 mqtt:
      image: toke/mosquitto
      container_name: mqtt
      expose:
        - 1883
      ports:
        - 1883:1883
      restart: unless-stopped

      networks:
        - my_network

 fast:
     container_name: fast
     expose:
        - 8000
     networks:
       - my_network
    
     ports:
        - 8000:8000
     restart: unless-stopped
     build:
      context: .
      dockerfile: Dockerfile

     depends_on:
        - mqtt

networks:
  my_network:
    driver: bridge
  • Related