Introduction
EMQX is an open-source MQTT message server developed on the Erlang/OTP platform, widely used in the Internet of Things (IoT) field for message transmission and control between devices and servers. This document is based on the NXP i.MX8M Plus ARM processor platform, deploying and testing EMQX by integrating a Docker environment into the Yocto Linux BSP.
The platform demonstrated in this article is from the Toradex Verdin i.MX8MP embedded platform.
Preparation
The Verdin i.MX8MP ARM core version is paired with the Dahlia carrier board and connected to a debug serial port for testing.
Verdin i.MX8MP Yocto Linux Compilation and Deployment
First, refer to the instructions here to create the Yocto/Openembedded compilation framework. The current latest version corresponds to the Toradex Yocto Linux BSP 7.x version of the scarthgap-7.x.y branch.
Add the meta-virtualization layer that includes Docker support.
### add meta-virtualization ###
$ cd <OE_ROOT_PATH>/layers
$ git clone -b scarthgap git://git.yoctoproject.org/meta-virtualization
### add meta-clang layer for PySide6 ###
$ git clone -b kirkstone https://github.com/kraj/meta-clang.git
Create a customized layer meta-customer-demos to add additional modifications and configurations required for Docker. First, add the layer configuration file.
$ mkdir -p ../oe_core/layers/meta-customer-demos/conf
$ cd .../oe_core/layers/meta-customer-demos/conf
### create layer.conf file ###
# We have a conf and classes directory, append to BBPATH
BBPATH .= ":${LAYERDIR}"
# We have recipes-* directories, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "customer-demos"
BBFILE_PATTERN_customer-demos = "^${LAYERDIR}/"
BBFILE_PRIORITY_customer-demos = "24"
# Let us add layer-specific bbappends which are only applied when that
# layer is included in our configuration
BBFILES += "${@' '.join('${LAYERDIR}/%s/recipes*/*/*.bbappend' % layer \
for layer in BBFILE_COLLECTIONS.split())}"
# Add layer-specific bb files too
BBFILES += "${@' '.join('${LAYERDIR}/%s/recipes*/*/*.bb' % layer \
for layer in BBFILE_COLLECTIONS.split())}"
LAYERDEPENDS_customer-demos = " \
core \
yocto \
openembedded-layer gnome-layer multimedia-layer networking-layer \
"
LAYERSERIES_COMPAT_customer-demos = "hardknott honister kirkstone scarthgap"
Add a Docker bbappend file under the customized layer meta-customer-demos to configure Docker to start automatically.
$ cd .../oe_core/layers/meta-customer-demos/
$ mkdir -p recipes-containers/docker
$ cd recipes-containers/docker
### create docker-moby_git.bbappend file ###
FILES:${PN} += "${sysconfdir}/systemd/system/docker.service"
SYSTEMD_SERVICE:${PN} = "docker.service"
SYSTEMD_AUTO_ENABLE:${PN} = "enable"
The Docker daemon requires additional network-related Kernel Modules such as IPSec/Netfilter/NF_table, so the following additional Linux Kernel configurations are needed.
$ cd .../oe_core/layers/meta-customer-demos/
$ mkdir -p recipes-kernel/linux/
$ cd recipes-kernel/linux
### create linux-toradex%.bbappend file ###
SRCREV_meta-custom = "1e293f75e7e5569f0d86d752fbf4180dd3fac6eb"
SRCREV_meta-custom:use-head-next = "${AUTOREV}"
KMETABRANCH = "scarthgap-7.x.y"
KMETAVIRTUALITION = "kernel-meta-custom"
KMETAREPOSITORY="github.com/toradex/toradex-kernel-cache.git"
KMETAPROTOCOL="https"
SRC_URI += "git://${KMETAREPOSITORY};protocol=${KMETAPROTOCOL};type=kmeta;name=meta-custom;branch=${KMETABRANCH};destsuffix=${KMETAVIRTUALITION}"
## Compose additional .scc file including docker requirement and include it to our build.
KERNEL_FEATURES += "bsp/${MACHINE}-${LINUX_KERNEL_TYPE}-torizon.scc"
The final complete file structure of the meta-customer-demos layer is as follows:
meta-customer-demos
├── conf
│ └── layer.conf
├── recipes-containers
│ └── docker
│ └── docker-moby_git.bbappend
└── recipes-kernel
└── linux
└── linux-toradex%.bbappend
Modify the bblayers.conf and local.conf files.
### modify bblayer.conf ###
--- a/build/conf/bblayers.conf
+++ b/build/conf/bblayers.conf
@@ -34,7 +34,7 @@
${TOPDIR}/../layers/meta-openembedded/meta-python \
${TOPDIR}/../layers/meta-freescale-distro \
${TOPDIR}/../layers/meta-toradex-demos \
+ ${TOPDIR}/../layers/meta-virtualization \
+ ${TOPDIR}/../layers/meta-customer-demos \
\
\
${TOPDIR}/../layers/meta-toradex-distro \
### add below to local.conf ###
# enable meta-virtualization
DISTRO_FEATURES:append = " virtualization"
# enable docker support
IMAGE_INSTALL:append = " docker docker-compose"
# add Freescale EULA
ACCEPT_FSL_EULA = "1"
Compile the Yocto Linux image.
### compile Reference-Multimedia image ###
$ MACHINE="verdin-imx8mp" bitbake tdx-reference-multimedia-image
Deployment of the Yocto Linux image.
Refer to the instructions here to update and deploy the compiled image to the module using the Toradex Easy Installer.
EMQX Deployment Testing
For more information and introduction about EMQX, please refer to the following link:https://docs.emqx.com/en/emqx/latest/getting-started/getting-started.html
On the Verdin i.MX8MP device, confirm that the Docker daemon is successfully running with the following command:
root@verdin-imx8mp-06849028:~# systemctl is-enabled docker.service
enabled
root@verdin-imx8mp-06849028:~# systemctl status docker.service
* docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: enabled)
Active: active (running) since Fri 2025-03-28 01:54:37 UTC; 5h 16min ago
TriggeredBy: * docker.socket
Docs: https://docs.docker.com
Main PID: 685 (dockerd)
Tasks: 19
Memory: 99.6M (peak: 146.5M)
CPU: 14.376s
CGroup: /system.slice/docker.service
`-685 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
...
Mar 28 01:54:37 verdin-imx8mp-06849028 dockerd[685]: time="2025-03-28T01:54:37.583078000Z" level=info msg="Daemon has completed initialization"
Mar 28 01:54:37 verdin-imx8mp-06849028 dockerd[685]: time="2025-03-28T01:54:37.684308375Z" level=info msg="API listen on /run/docker.sock"
Mar 28 01:54:37 verdin-imx8mp-06849028 systemd[1]: Started Docker Application Container Engine.
Refer to the instructions here to install and run the EMQX ARM64 Docker Image using the following commands. This article adopts the offline method; if network conditions permit, the online method can also be used.
### download
$ wget https://www.emqx.com/en/downloads/broker/5.8.6/emqx-5.8.6-docker-arm64.tar.gz
### install
$ docker load < emqx-5.8.6-docker-arm64.tar.gz
###
$ docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:5.8.6
At this point, on the development host, you can view the running EMQX console page through the browser at the following URL. The default login information is admin/public, which can be changed later.
http://<verdin_imx8mp_ip_address>:18083/
After entering the client, first connect to the Verdin i.MX8MP core node device.
Then subscribe to the default topic “testtopic”.
Finally, after modifying the payload content, click publish, and you can see that the core node can receive data normally.
Conclusion
This article demonstrates the deployment and operation of the EMQX MQTT message server in a Docker environment based on the NXP i.MX8MP processor.