We all know how to launch docker containers manually via the command prompt right ? If not, maybe I should write a guide on that topic as well although I am pretty sure the internet is full of such articles.
In this post we will find out how to launch multiple docker containers at once with docker compose. If you don’t have it installed, go ahead and install it following the official documentation here. If you are using a Raspberry Pi like me and you have difficulties installing it, follow my instructions here.
In order for docker compose to launch multiple containers at once, it requires a YAML configuration file and by default it looks for docker-compose.yml. You can also use the .yaml extension but I will stick to the former.
For the purpose of this post, we will start three containers on a Raspberry Pi 3B+
- openHAB, the open source home automation software
- eclipse mosquitto, an open source message broker that implements MQTT
- zigbee2MQTT, an open source Zigbee to MQTT bridge. It translates Zigbee messages to MQTT and passes them on to the broker. In our case the mosquitto server above
Here is the docker-compose.yml file but don’t run it just yet!
Hint: It is very important that you keep the indentations otherwise docker-compose will not be able to run!
version: '3.9' services: openhab: image: openhab/openhab:3.1.0 restart: unless-stopped network_mode: host container_name: openhab31 devices: - "/dev/ttyUSB0:/dev/ttyUSB0" volumes: - "/etc/localtime:/etc/localtime:ro" - "/etc/timezone:/etc/timezone:ro" - "openhab_addons:/openhab/addons" - "openhab_conf:/openhab/conf" - "openhab_userdata:/openhab/userdata" environment: OPENHAB_HTTP_PORT: "8080" OPENHAB_HTTPS_PORT: "8443" EXTRA_JAVA_OPTS: "-Duser.timezone=Europe/Berlin" mqtt: image: eclipse-mosquitto:2.0.14 container_name: mosquitto2014 restart: unless-stopped volumes: - mosquitto-conf:/mosquitto/config - mosquitto-data:/mosquitto/data - mosquitto-log:/mosquitto/log - ./mosquitto.conf:/mosquitto/config/mosquitto.conf ports: - "1883:1883" - "9001:9001" zigbee2mqtt: container_name: zigbee2mqtt restart: unless-stopped image: koenkk/zigbee2mqtt volumes: - ./zigbee2mqtt-data:/app/data - /run/udev:/run/udev:ro ports: - 8081:8080 environment: - TZ=Europe/Berlin devices: - /dev/ttyUSB0:/dev/ttyUSB0 volumes: mosquitto-conf: mosquitto-data: mosquitto-log: openhab_conf: driver: local openhab_userdata: driver: local openhab_addons: driver: local
Let me explain some parts of the above config that are not self explanatory
We pull the latest stable image of openHAB at the time of writing v3.1. You can use
to get the latest image but I prefer to have control over the version I install. If there is a newer stable image you can change the version accordingly.
We will use the network configuration of the host so essentially openHAB will have the same ip address as the Raspberry Pi
Because I will be using a USB device that acts as a Zigbee gateway I will need to pass the USB information to the container so that it can access that USB port. You can find what USB port to put but unplugging / plugging back the USB key and monitoring the output of the dmesg command. In case you also have a zwave usb stick you will most likely need the following
We also define a few named volumes in the configuration. What does this mean ? We map the folder from the host (path before the column) to the folder in the container (path after the column). That way we have access to the files located in those container folders from the host without having to access the container itself.
- "openhab_addons:/openhab/addons" - "openhab_conf:/openhab/conf" - "openhab_userdata:/openhab/userdata"
In the environment section we configure the network ports openHAB will listen to as well as the timezone to be used.
You want to see what else you can configure ? Go here and explore!
We also create several volumes here in order to be able to access some files from the host without going into the container. Do you see the last line in the volumes section for the mqtt service ?
We basically tell docker-compose to take the configuration file for the MQTT broker (mosquitto.conf) from the same folder we run the docker-compose command in the host. In my case I will run the command from /home/pi so I will need to create the configuration file in the same folder. Here are the contents of mosquitto.conf
listener 1883 allow_anonymous true persistence true persistence_location /mosquitto/data/ log_dest file /mosquitto/log/mosquitto.log
listener 1883 : the MQTT brokers listens to the default port 1883
allow_anonymous true: we don’t use authentication
persistence true: we enable persistence so that the broker stores mqtt messages it receives when the connection is not good and sends them later.
persistence_location /mosquitto/data/ : the location the broker keeps the unsent messages
log_dest file /mosquitto/log/mosquitto.log: destination and name of the log file
Just like the eclipse mosquitto container, we use a volume that maps a folder ( zigbee2mqtt-data) from the host to the container (/app/data). So go ahead and create the folder from the location you will run the docker compose command. In my case /home/pi
Inside the folder, create a file called configuration.yaml with the following contents
# Home Assistant integration (MQTT discovery) homeassistant: false # allow new devices to join permit_join: true frontend: port: 8080 # MQTT settings mqtt: # MQTT base topic for zigbee2mqtt MQTT messages base_topic: zigbee2mqtt # MQTT server URL server: 'mqtt://mqtt' # MQTT server authentication, uncomment if required: # user: my_user # password: my_password # Serial settings serial: # Location of CC2531 USB sniffer port: /dev/ttyUSB0
Make sure that port corresponds to the correct path, in my case it is /dev/ttyUSB0. As I mentioned earlier, you can unplug and plug back in the usb Zigbee gateway and monitor the output of the dmesg command to see what’s the correct path.
When the docker container starts, it will read the local configuration file from the host since we have mapped it in the volumes section.
Pay attention also in the ports section. The format is host_port:container_port. The default configuration was 8080:8080 but I could not use it. Can you guess why ?
Port 8080 is also used by openHAB which uses the same network as the host. Remember, we have defined network_mode: host in the docker-compose file for openHAB.
So for Zigbee2MQTT I use the port 8081 in the host to avoid conflicts. All messages will arrive to the host on port 8081 which will forward them to the container on port 8080.
Launch the containers!
Finally, you can launch all the containers at once with the following command
docker-compose up -d
If everything is good you will see the following
pi@raspberrypi:~/zigbee2mqtt-data $ docker-compose up -d [+] Running 3/0 ⠿ Container mosquitto2014 Running ⠿ Container zigbee2mqtt Running ⠿ Container openhab31 Running
Hint: Pay careful attention to the indentation of docker-compose.yml ! In case of doubt you can always use notepad in windows or any other indentation-friendly application. I sometimes use Visual Studio Code with indent-rainbow plugin to make sure everything is properly aligned.
Hint: You can use docker-compose logs -f to monitor the deployment of the containers