Terminal showing Docker container running with Mali GPU access on MediaTek Genio board
mediatekgeniodockergpuyoctomalicontainersembedded linux

Docker with GPU acceleration on MediaTek Genio

Aaron Angulo ·

Docker on MediaTek Genio lets you isolate workloads, ship reproducible application environments, and run inference pipelines alongside BSP services without polluting the root filesystem. The setup requires adding meta-virtualization to your Yocto build — it is not included in the default RITY image. GPU passthrough for Mali acceleration takes one extra step: device nodes and matching userspace libraries must be visible inside the container.

Key Insights

  • meta-virtualization is the layer to add — it provides docker-ce, containerd, and runc for Yocto scarthgap; it is not in the default RITY stack
  • Mali GPU passthrough requires two things: the /dev/mali0 device node and matching Mali userspace libraries inside the container
  • NPU (MDLA) in containers is possible but version-sensitive — the NeuroPilot runtime inside the container must match the apusys kernel driver on the host
  • SPI, I2C, and GPIO devices pass through cleanly — use --device flags or the devices: key in Docker Compose
  • Privileged mode is a shortcut, not a solution--privileged works but exposes all host devices; prefer explicit device passthrough in production

Adding Docker to a Genio Yocto image

Step 1: Add meta-virtualization to bblayers.conf

git clone https://github.com/openembedded/meta-virtualization.git \
  -b scarthgap sources/meta-virtualization

Add to conf/bblayers.conf:

BBLAYERS += " \
  ${BSPDIR}/sources/meta-virtualization \
"

Step 2: Enable virtualization DISTRO_FEATURE

In conf/local.conf or your custom distro conf:

DISTRO_FEATURES:append = " virtualization"

This flag gates the cgroup v2, namespace, and overlay filesystem support that Docker depends on. Without it, Docker starts but container creation fails with cgroup errors.

Step 3: Add Docker to IMAGE_INSTALL

IMAGE_INSTALL:append = " \
  docker-ce \
  docker-ce-cli \
  containerd \
  runc \
  python3-docker \
"

For a minimal setup using only containerd and nerdctl (lighter than full Docker CE):

IMAGE_INSTALL:append = " containerd nerdctl"

Step 4: Enable required kernel config

The Genio kernel config includes most required options, but verify these are set:

# Check from build directory
grep -E "CGROUPS|NAMESPACES|OVERLAY_FS|VETH" \
  tmp/work/<machine>-poky-linux/linux-mtk/*/build/.config

Critical options:

ConfigRequired for
CONFIG_CGROUPS=yContainer resource limits
CONFIG_CGROUP_DEVICE=yDevice cgroup (device whitelist)
CONFIG_NAMESPACES=yProcess/network/mount isolation
CONFIG_OVERLAY_FS=yUnion filesystem for container layers
CONFIG_VETH=yVirtual Ethernet for container networking
CONFIG_BRIDGE=yDocker bridge network (docker0)

All of these are enabled in the default Genio kernel config. If you have a heavily stripped custom config, re-enable them.

Step 5: Verify Docker starts on the board

# Check Docker daemon
systemctl status docker

# Run a test container (CPU only)
docker run --rm busybox echo "Docker is working"

# Check container runtime info
docker info | grep -E "Runtime|Driver|Cgroup"

Mali GPU passthrough

The Genio Mali GPU (Mali-G57) appears as /dev/mali0 on the target. Passing it to a container requires:

  1. The device node
  2. The Mali userspace libraries (EGL, OpenCL, OpenGL ES) that match the kernel driver

Basic GPU passthrough

docker run --rm \
  --device /dev/mali0:/dev/mali0 \
  --device /dev/dri:/dev/dri \
  your-image:latest

Docker Compose

services:
  app:
    image: your-image:latest
    devices:
      - "/dev/mali0:/dev/mali0"
      - "/dev/dri:/dev/dri"
    volumes:
      - "/dev/dri:/dev/dri"

Mali libraries inside the container

The Mali userspace libraries (libmali.so, EGL, OpenGL ES, OpenCL) must be present inside the container and must match the kernel driver version. The safest approach is to build your container image from the same Genio rootfs tarball:

FROM scratch
ADD genio-rootfs.tar.gz /
# Your app layers on top

Alternatively, copy the Mali libraries from the host into the container at runtime using a volume mount:

docker run --rm \
  --device /dev/mali0:/dev/mali0 \
  -v /usr/lib/libmali.so:/usr/lib/libmali.so:ro \
  -v /usr/lib/aarch64-linux-gnu/libEGL.so:/usr/lib/aarch64-linux-gnu/libEGL.so:ro \
  your-image:latest

Version mismatch between the host driver and container userspace libraries produces MALI: mali_kbase_open: version mismatch errors in dmesg.

NPU (MDLA / NeuroPilot) in containers

NPU acceleration from within a container requires passing the APUSys device nodes:

docker run --rm \
  --device /dev/mali0:/dev/mali0 \
  --device /dev/apusys:/dev/apusys \
  --device /dev/mtk_mdla0:/dev/mtk_mdla0 \
  your-inference-image:latest python3 run_model.py

The NeuroPilot runtime (libNeuronRuntime.so) inside the container must match the apusys.ko driver version loaded on the host. Check the host driver version:

cat /sys/kernel/debug/apusys/version
# Or check the loaded module
modinfo apusys | grep version

For TFLite CPU inference (no NPU), no special devices are needed — TFLite runs entirely in userspace:

docker run --rm your-inference-image:latest python3 -c "
import tflite_runtime.interpreter as tflite
interp = tflite.Interpreter('model.tflite')
interp.allocate_tensors()
print('TFLite loaded OK')
"

Peripheral device passthrough

All peripheral devices on Genio follow the same pattern: pass the device node with --device:

# docker-compose.yml
services:
  app:
    image: your-image:latest
    devices:
      - "/dev/mali0:/dev/mali0"       # Mali GPU
      - "/dev/apusys:/dev/apusys"     # APU/NPU
      - "/dev/spidev1.0:/dev/spidev1.0" # SPI
      - "/dev/gpiochip0:/dev/gpiochip0" # GPIO
      - "/dev/i2c-0:/dev/i2c-0"       # I2C bus 0
      - "/dev/video0:/dev/video0"     # V4L2 camera

For camera pipelines using GStreamer inside a container, also mount the V4L2 and DRM devices and pass the Wayland socket if display output is needed:

docker run --rm \
  --device /dev/video0:/dev/video0 \
  --device /dev/dri:/dev/dri \
  --device /dev/mali0:/dev/mali0 \
  -v /run/user/0/wayland-0:/run/user/0/wayland-0 \
  -e WAYLAND_DISPLAY=wayland-0 \
  -e XDG_RUNTIME_DIR=/run/user/0 \
  your-gstreamer-image:latest gst-launch-1.0 v4l2src ! waylandsink

Common issues

docker: Error response from daemon: cgroups: cgroup mountpoint does not exist cgroup v2 isn’t mounted. Add to /etc/fstab: cgroup2 /sys/fs/cgroup cgroup2 defaults 0 0 and remount. Or set GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1" in the kernel command line.

MALI: mali_kbase_open: version mismatch Mali userspace version in the container doesn’t match the kernel driver. Use Mali libraries from the same BSP build.

/dev/mali0: no such file or directory inside container Forgot --device /dev/mali0. The device node must be explicitly passed — it won’t appear just because the container has root access.

apusys: failed to open device APUSys device not passed, or kernel driver not loaded. Check lsmod | grep apusys on the host first.

For the Yocto layer setup that supports Docker on Genio, see Yocto build guide for MediaTek Genio. For adding custom Yocto layers on top of the RITY stack, see building a custom Yocto meta layer for Genio.

FAQ

Does Docker work on MediaTek Genio with Yocto?

Yes. Add meta-virtualization to your Yocto layer stack, add virtualization to DISTRO_FEATURES, and include docker-ce or containerd in IMAGE_INSTALL. Docker runs on top of the Linux kernel — Genio’s kernel config includes the necessary cgroup and namespace support.

How do I pass the Mali GPU into a Docker container on Genio?

Pass /dev/mali0 as a device in your docker run command or compose file: --device /dev/mali0:/dev/mali0. Also pass /dev/dri if using DRM. The container process needs the same Mali userspace libraries as the host — use the same base rootfs or copy the Mali libs into the container image.

Can I run AI inference in a Docker container on Genio?

Yes, with limitations. TFLite CPU inference works out of the box. NPU acceleration requires passing /dev/apusys and related firmware devices, and the NeuroPilot runtime inside the container must match the kernel driver version on the host.

Which Yocto layer provides Docker for Genio?

meta-virtualization (from OpenEmbedded) provides the docker-ce, containerd, and runc recipes. Add it to bblayers.conf and add virtualization to DISTRO_FEATURES. It is compatible with the Yocto scarthgap release used by the MediaTek IoT Yocto BSP.


MediaTek Genio Expert Support

Building on MediaTek Genio?

BSP bring-up, GStreamer pipelines, NeuroPilot integration, we've shipped it. Get unblocked fast. One call to scope it, fixed bid to deliver it.

Frequently Asked Questions

Does Docker work on MediaTek Genio with Yocto?

Yes. Add meta-virtualization to your Yocto layer stack, add 'virtualization' to DISTRO_FEATURES, and include docker-ce or containerd in IMAGE_INSTALL. Docker runs on top of the Linux kernel — Genio's kernel config includes the necessary cgroup and namespace support.

How do I pass the Mali GPU into a Docker container on Genio?

Pass /dev/mali0 as a device in your docker run command or compose file: --device /dev/mali0:/dev/mali0. Also pass /dev/dri if using DRM. The container process needs the same Mali userspace libraries as the host — use the same base rootfs or copy the Mali libs into the container image.

Can I run AI inference in a Docker container on Genio?

Yes, with limitations. TFLite CPU inference works out of the box. NPU (MDLA/NeuroPilot) acceleration in containers requires passing /dev/apusys and related firmware devices. The NeuroPilot runtime inside the container must match the kernel driver version on the host.

Which Yocto layer provides Docker for Genio?

meta-virtualization (from OpenEmbedded) provides the docker-ce, containerd, and runc recipes. Add it to bblayers.conf and add 'virtualization' to DISTRO_FEATURES. It is compatible with the Yocto scarthgap release used by the MediaTek IoT Yocto BSP.

Aarón Angulo, Co-Founder & CEO at ProventusNova

Written by

Aarón Angulo

Co-Founder & CEO · ProventusNova

Obsessed with client outcomes. Aarón ensures every engagement delivers real results, on time, on scope, no exceptions.

Connect on LinkedIn