DynamicDevices / ming-original

Balena.io/Docker-compose repo for a containerised #MING (Mosquitto, InfluxDB, NodeRed, Grafana) stack
33 stars 20 forks source link

Networking question #34

Closed wb441 closed 1 year ago

wb441 commented 1 year ago

Hi,

This is actually a question on networking in a docker environment, so don't hesitate to tell me if I should post this somewhere else :)

I deployed the MING stack to a Balena fleet of 1 device. I added another application, Zigbee2mqtt. This application can't seem to reach the Mosquitto container.

Now, I tried to find out more how the networking works in this implementation. I read about host networking, a default bridge and a custom bridge. I assume the MING-implementation works with the default bridge. So, my questions:

TIA

ajlennon commented 1 year ago

Hi there,

Excellent questions. Yes so in essence you can tell the container to use "host networking" which as far as I can tell means container and host networking are then the same thing.

The alternative is to EXPOSE an internal port inside the container as an exernal port on the host (which don't have to be the same thing)

Now we do this in the docker-compose.xml file here so I would have thought this should work for you.

The bridge was some old experimental work we did to use a Python script to take MQTT data and put it into the InfluxDB database. We use Node-Red for that nowadays.

What I would also say is that I've been looking at Traefik which is a nice way to handle this. Using the Traefik block we can map a URL on a specific port to another internal port, thus we can have internal multiple container services on a single public URL. This is the way I'm going with this stuff in future

For details see here

Now this doesn't help you with your Mosquitto issue of course. Can you just confirm for me that on the host something is listening on 1883, and inside the container Mosquitto is too?

wb441 commented 1 year ago

Thank you for your reply. From what I read, with host networking, port exposing definitions are ignored, therefore, I assumed the docker implementation would create a default bridge giving each container an IP address on the default bridge. Is this the case?

With regards to exposing ports/listening on 1883, I left the original configuration as is in the docker-compose.yml:

version: '2'
volumes:
    influxdb-data:
    nodered-data:
    grafana-data:
    jupyterlab-data:
    homeassistant-data:
    rhasspy-data:
    z2m-data:
services:
  nodered:
    restart: always
    build: ./nodered
    volumes:
      - 'nodered-data:/data'
    ports:
      - "1880:1880"
  influxdb:
    restart: always
    build: ./influxdb
    environment:
      - INFLUXDB_DB=ming_default
    volumes:
      - 'influxdb-data:/var/lib/influxdb'
    ports:
      - "8086:8086"
  grafana:
    restart: always
    build: ./grafana
    environment:
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
    ports:
      - "3000:3000"
    volumes:
      - 'grafana-data:/var/lib/grafana'
    depends_on:
      - influxdb
  mosquitto:
    restart: always
    build: ./mosquitto
    ports:
      - "1883:1883"
      - "1884:1884"
  jupyterlab:
    restart: always
    build: ./jupyterlab
    ports:
      - "8888:8888"
    volumes:
      - 'jupyterlab-data:/data'
  homeassistant:
    restart: always
    build: ./homeassistant
    ports:
      - "8123:8123" 
    volumes:
      - 'homeassistant-data:/config'
  rhasspy:
    restart: always
    build: ./rhasspy
    ports:
      - "12101:12101"
    volumes:
      - 'rhasspy-data:/profiles'
    devices:
      - "/dev/snd:/dev/snd"
    command: --user-profiles /profiles --profile en
  ap:
    build: ./ap
    restart: always
    network_mode: host
    privileged: true
    labels:
      io.balena.features.dbus: '1'
      io.balena.features.firmware: '1'
  z2m:
    build: ./z2m
    restart: always
    volumes:
      - 'z2m-data:/app/data'
    ports:
      - "8080:8080"
    devices:
      - "/dev/ttyUSB0:/dev/ttyUSB0"    
    environment:
      - TZ=Europe/Berlin
#  bridge:
#    restart: always
#    build: ./bridge
#    depends_on:
#     - influxdb
#     - mosquitto

Next, I will post the internal configuration of Zigbee2mqtt, because that's where the address to the MQTT broker = mosquitto container is defined.

The Traefik implementation looks really interesting, thank you for that pointer! I'm looking forward to implement it!

ajlennon commented 1 year ago

From what I read, with host networking, port exposing definitions are ignored, therefore, I assumed the docker implementation would create a default bridge giving each container an IP address on the default bridge. Is this the case?

This is not my understanding. Maybe I am mistaken but I think this should work. Where are you reading this. tbh I don't worry about individual container IP addresses on a bridge as I just use port exposure or Traefik

ajlennon commented 1 year ago

I think you may need to be using 127.0.0.1:1883 say, which would maybe mean that if you are testing this from another board then it wouldn't work?

wb441 commented 1 year ago

Apparently, what is in there resolves to that, but isn't reachable:

Zigbee2MQTT:error 2022-10-31 19:42:22: MQTT failed to connect: connect ECONNREFUSED 127.0.0.1:1883

Mosquitto seems to be listening on 1883:

 mosquitto  1667241896: mosquitto version 1.6.7 starting
 mosquitto  1667241896: Config loaded from /mosquitto/config/mosquitto.conf.
 mosquitto  1667241896: Opening ipv4 listen socket on port 1883.
 mosquitto  1667241896: Opening ipv6 listen socket on port 1883.
 mosquitto  1667241896: Opening websockets listen socket on port 1884.
 mosquitto  1667241896: mosquitto version 1.6.7 starting
 mosquitto  1667241896: Config loaded from /mosquitto/config/mosquitto.conf.
 mosquitto  1667241896: Opening ipv4 listen socket on port 1883.
 mosquitto  1667241896: Opening ipv6 listen socket on port 1883.
 mosquitto  1667241896: Opening websockets listen socket on port 1884.`

I can connect to the broker with a client (MQTT.fx) from another device.

wb441 commented 1 year ago

I added network_mode: host to the definition of zigbee2mqtt in the docker-compose.yml, pushed it to the fleet and now it works... Your hunch was right!

wb441 commented 1 year ago

Further comment for anyone who might stumble onto this. Upon creating the zigbee2mqtt container, balena does some funny things to the mapped volumes:

  1. It prefixes a number to the directory name. In my case: /var/lib/docker/volumes/1947843_z2m-data
  2. The subfolder datais now changed to _data

The configuration.yaml file lives inside this subfolder. image

I removed the network_mode host from docker-compose.yml, pushed the build to the fleet. Once up and running I changed the configuration.yaml for zigbee2mqtt, so that is lists the following server for mqtt: image

...following a hint from this page of zigbee2mqtt: image

In the end, the default bridge has an ip address which can indeed be used to adress the local docker network!

Finally, I added frontend: true as to enable the fronted page for zigbee2mqtt on port 8080.

All set!