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