Skip to content

Latest commit

 

History

History
112 lines (87 loc) · 6.18 KB

File metadata and controls

112 lines (87 loc) · 6.18 KB

Native Docker on Android (Realme 3 / RMX1821)

1. Introduction and Problem Statement

Running Docker natively on Android presents several fundamental challenges due to the restrictive nature of default Android kernels and the Android filesystem.

By default, Android kernels lack critical Linux features required by the Docker engine, including:

  • Namespaces (PID, UTS, IPC, NET)
  • Cgroups (Control Groups for resource management)
  • Networking (Bridge, VETH, Netfilter/NAT)
  • Storage (OverlayFS)

Furthermore, there is a specific incompatibility regarding Kernel 4.14. Modern Android versions (Android 11) typically mount Cgroup v2. However, Kernel 4.14 lacks complete support for eBPF (Extended Berkeley Packet Filter) device cgroups. Consequently, modern container runtimes like runc fail to initialize containers, outputting bpf_prog_query(BPF_CGROUP_DEVICE) failed: invalid argument.

This repository provides a comprehensive research report, custom kernel modifications, and setup scripts to successfully bypass these limitations and run Docker natively on an Android device.

2. Research and Methodology

To achieve a fully functional Docker environment, four major modifications were implemented:

  1. Custom Kernel Compilation: The kernel configuration (RMX1821_defconfig) was heavily modified to include all necessary Docker flags, enabling namespaces, cgroups, overlayfs, and bridge networking.
  2. The Alpine Linux Chroot: The Android root filesystem (/, /var, /run) is largely read-only and uses non-standard paths. An Alpine Linux mini rootfs was deployed in a chroot environment (/data/alpine-docker) to provide a standard, read-write Linux environment for the Docker daemon.
  3. The crun Runtime: To bypass the runc eBPF requirement on Kernel 4.14, the runtime was replaced with crun, which is written in C and does not strictly require eBPF.
  4. The Cgroup v1 Hybrid Solution: Because Android already mounts certain cgroup controllers (e.g., cpu, cpuset, memory) in scattered directories (/dev/cpuctl, /dev/cpuset), mounting a standard cgroup v1 hierarchy results in a Device or resource busy error. The solution is a Hybrid Mount Script (start-docker.sh) that mounts a tmpfs over /sys/fs/cgroup, bind-mounts Android's existing controllers into it, and manually creates the missing controllers (devices, freezer, pids). This successfully simulates a clean cgroup v1 environment for Docker.

3. Compatibility and Device Support

Important

Strictly Tested Environment: This specific compiled kernel and methodology has ONLY been tested and verified on the following configuration:

  • Device: Realme 3 (Codename: RMX1821)
  • Custom ROM: Nusantara Project v3.2 (Codename: Revolution)
  • Build Type: Unofficial
  • Android Version: Android 11
  • Kernel Version: 4.14.282
  • Kernel Compatibility: The kernel source used in this research is specific to the MediaTek MT6771 (Helio P60) architecture. The compiled kernel image (boot.img) CANNOT be flashed to non-RMX1821 devices or devices running vastly different Android base versions without high risk of bootloops.
  • Methodology Compatibility: The scripts and overall userspace methodology (chroot + crun + hybrid cgroup v1) can theoretically be applied to any rooted Android device, provided the user compiles their own custom kernel with the required Docker flags.

4. Prerequisites and Required Tools

  • Hardware: Realme 3 (or other target Android device).
  • Software/Apps:
    • Root Access (Magisk / KernelSU / SuperSU).
    • Termux (for terminal access and script execution).
    • magiskboot (binary tool for unpacking and repacking Android boot images).
    • Target device's Custom Kernel Source.
    • Alpine Linux Mini Rootfs (aarch64).

5. Kernel Installation Guide

This section outlines how to flash the custom kernel modifications to the device. Ensure you have your compiled Image.gz-dtb ready.

  1. Obtain the Stock Boot Image: Extract boot.img from your current ROM/firmware.
  2. Unpack the Boot Image:
    ./magiskboot unpack boot.img
  3. Replace the Kernel: Replace the extracted kernel file with your custom compiled kernel.
    cp /path/to/compiled/Image.gz-dtb kernel
  4. Repack the Boot Image:
    ./magiskboot repack boot.img boot-custom.img
  5. Flash the Custom Boot Image: Flash the image via Fastboot or TWRP/Custom Recovery.
    fastboot flash boot boot-custom.img

6. Docker Setup Guide

Once the custom kernel is installed and running, proceed with the userspace setup.

  1. Setup the Alpine Chroot Environment: Open Termux, request root access, and run the setup script.

    su
    sh setup-chroot.sh
  2. Start the Docker Daemon: Android clears the /run and cgroup mounts upon every reboot. You must execute the startup script to re-mount the hybrid filesystems and launch the Docker daemon in the background.

    su
    sh start-docker.sh
  3. Setup Docker Alias (Optional but Recommended): Since the Docker daemon runs inside the chroot, the socket is located at /data/alpine-docker/run/docker.sock. Add this alias to your Termux shell profile for convenience:

    echo 'alias docker="/data/data/com.termux/files/usr/bin/docker -H unix:///data/alpine-docker/run/docker.sock"' >> ~/.bashrc
    source ~/.bashrc

7. Networking (Tailscale / VPN)

Exposing Docker containers on Android to a VPN network like Tailscale introduces routing complexities. Standard Docker port forwarding (-p 8080:80) often fails because Android's VpnService intercepts and routes traffic differently, bypassing standard iptables NAT rules.

The Solution: Use the Host Network. Run your containers with --network host. This instructs the container to bind directly to the Android host's network interfaces, making it natively accessible over Tailscale without relying on iptables proxying.

docker run -d --network host --name my-webserver httpd:alpine