PI Series - How to Install Docker, Tailscale, K3s, and Cilium on a Rockchip Arm Development Board

This article was last updated on: May 17, 2026 am

Overview

I picked up a few cheap Purple PI OH development boards during the 618 sale (just over 500 RMB for 3 boards 🤑). These boards are similar to Raspberry Pi, based on the Rockchip RK3566 arm64 chip. Here’s what they look like:

Purple PI OH

I bought them to use as home servers or a home lab. The main considerations were:

  1. Cheap
  2. Highly hackable
  3. Low power consumption
  4. Minimal heat dissipation, silent operation
  5. The Arm64 ecosystem is decent enough nowadays

Here are the specs (selected highlights):

  • SOC: RockChip RK3566
  • CPU: Quad-core 64-bit Cortex-A55, up to 1.8GHz
  • Up to 8GB high-speed LPDDR4 at up to 1066Mbps (I got the 2GB version)
  • Storage: 8GB eMMC by default (optional 16GB/32GB/64GB) (I got the 16GB version)
  • 1x HDMI 2.0 supporting 4K@60Hz or 1080P@120Hz
  • 1x auto-negotiating Gigabit Ethernet port
  • WiFi and Bluetooth wireless connectivity
  • 1x USB 3.0 and 3x USB 2.0 onboard
  • Ultra-compact PCB size: 85mm × 56mm

Supported operating systems:

  • Android 11
  • Debian 10
  • Buildroot + QT
  • OpenHarmony 3.2
  • Ubuntu
  • Kylin OS

After flashing the official Debian 10 image, I found that Docker/Tailscale/K3s/Cilium couldn’t be installed. Why is that?

Root Cause Analysis

Many development board operating systems don’t have UEFI and can’t be installed directly using the ISO images from the official Debian Linux website. Instead, they use a custom-compiled Debian Linux.

The compiled Debian includes U-Boot as the bootloader, along with integrated drivers for the board’s specific chipset and interfaces.

The official custom-compiled Debian Linux only enables a small subset of kernel configuration options. However, Docker/Tailscale/K3s/Cilium all rely heavily on kernel-level features that aren’t enabled in the official Debian image. This means we need to compile the kernel ourselves following the official “Linux SDK Compilation Guide.”

Required Kernel Configurations

Kernel Configurations Required by Docker

The kernel configurations required by Docker can be verified using the check script at https://github.com/opencontainers/runc/blob/main/script/check-config.sh. Here’s an example output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# ./check_config.sh
info: reading kernel config from ./kernel/.config ...

Generally Necessary:
- cgroup hierarchy: properly mounted [/sys/fs/cgroup]
- apparmor: enabled and tools installed
- CONFIG_NAMESPACES: enabled
- CONFIG_NET_NS: enabled
- CONFIG_PID_NS: enabled
- CONFIG_IPC_NS: enabled
- CONFIG_UTS_NS: enabled
- CONFIG_CGROUPS: enabled
- CONFIG_CGROUP_CPUACCT: enabled
- CONFIG_CGROUP_DEVICE: enabled
- CONFIG_CGROUP_FREEZER: enabled
- CONFIG_CGROUP_SCHED: enabled
- CONFIG_CPUSETS: enabled
- CONFIG_MEMCG: missing
- CONFIG_KEYS: enabled
- CONFIG_VETH: missing
- CONFIG_BRIDGE: missing
- CONFIG_BRIDGE_NETFILTER: missing
- CONFIG_IP_NF_FILTER: missing
- CONFIG_IP_NF_TARGET_MASQUERADE: missing
- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE: missing
- CONFIG_NETFILTER_XT_MATCH_CONNTRACK: missing
- CONFIG_NETFILTER_XT_MATCH_IPVS: missing
- CONFIG_IP_NF_NAT: missing
- CONFIG_NF_NAT: missing
- CONFIG_POSIX_MQUEUE: missing

Optional Features:
- CONFIG_USER_NS: enabled
- CONFIG_SECCOMP: enabled
- CONFIG_SECCOMP_FILTER: enabled
- CONFIG_CGROUP_PIDS: missing
- CONFIG_MEMCG_SWAP: missing
- CONFIG_MEMCG_SWAP_ENABLED: missing
- CONFIG_BLK_CGROUP: missing
- CONFIG_BLK_DEV_THROTTLING: missing
- CONFIG_CGROUP_PERF: missing
- CONFIG_CGROUP_HUGETLB: missing
- CONFIG_NET_CLS_CGROUP: missing
- CONFIG_CGROUP_NET_PRIO: missing
- CONFIG_CFS_BANDWIDTH: enabled
- CONFIG_FAIR_GROUP_SCHED: enabled
- CONFIG_RT_GROUP_SCHED: missing
- CONFIG_IP_NF_TARGET_REDIRECT: missing
- CONFIG_IP_VS: missing
- CONFIG_IP_VS_NFCT: missing
- CONFIG_IP_VS_PROTO_TCP: missing
- CONFIG_IP_VS_PROTO_UDP: missing
- CONFIG_IP_VS_RR: missing
- CONFIG_SECURITY_SELINUX: missing
- CONFIG_SECURITY_APPARMOR: missing

So the required kernel config options are:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# Docker Generally Necessary
CONFIG_NAMESPACES=y
CONFIG_NET_NS=y
CONFIG_PID_NS=y
CONFIG_IPC_NS=y
CONFIG_UTS_NS=y
CONFIG_CGROUPS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_SCHED=y
CONFIG_CPUSETS=y
CONFIG_MEMCG=y
CONFIG_KEYS=y
CONFIG_VETH=y
CONFIG_BRIDGE=y
CONFIG_BRIDGE_NETFILTER=y
CONFIG_IP_NF_FILTER=y
CONFIG_IP_NF_TARGET_MASQUERADE=y
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
CONFIG_NETFILTER_XT_MATCH_IPVS=y
CONFIG_IP_NF_NAT=y
CONFIG_NF_NAT=y
CONFIG_POSIX_MQUEUE=y

# Optional Features:=y
CONFIG_USER_NS=y
CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y
CONFIG_CGROUP_PIDS=y
CONFIG_MEMCG_SWAP=y
CONFIG_MEMCG_SWAP_ENABLED=y
CONFIG_BLK_CGROUP=y
CONFIG_BLK_DEV_THROTTLING=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_NET_CLS_CGROUP=y
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_IP_VS=y
CONFIG_IP_VS_NFCT=y
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
CONFIG_IP_VS_RR=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_APPARMOR=y

Kernel Configurations Required by Tailscale

Tailscale is designed for broad compatibility and primarily uses userspace implementations. It can run via a SOCKS5 proxy without any kernel configuration. For normal operation, it only depends on a single kernel option:

1
2
# Tailscale
CONFIG_TUN=y

If you’re using WireGuard or other software with heavier kernel dependencies, please look up their specific kernel configuration requirements.

Kernel Configurations Required by K3s

K3s has a well-designed CLI that can directly check kernel configuration requirements. Here’s the output from my compiled Debian 10:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
$ k3s check-config

Verifying binaries in /var/lib/rancher/k3s/data/ef31d9f1b153134534c2b9664540479f3071940e08ee95dd2877e102a31d235e/bin:
- sha256sum: good
- aux/ip6tables: symlink to xtables-legacy-multi
- aux/ip6tables-restore: symlink to xtables-legacy-multi
- aux/ip6tables-save: symlink to xtables-legacy-multi
- aux/iptables: symlink to xtables-legacy-multi
- aux/iptables-restore: symlink to xtables-legacy-multi
- aux/iptables-save: symlink to xtables-legacy-multi
- links: good

System:
- /var/lib/rancher/k3s/data/ef31d9f1b153134534c2b9664540479f3071940e08ee95dd2877e102a31d235e/bin/aux iptables v1.8.8 (legacy): ok
- swap: disabled
- routes: ok

Limits:
- /proc/sys/kernel/keys/root_maxkeys: 1000000

modprobe: ERROR: ../libkmod/libkmod.c:586 kmod_search_moddep() could not open moddep file '/lib/modules/4.19.232/modules.dep.bin'
modprobe: FATAL: Module configs not found in directory /lib/modules/4.19.232
info: reading kernel config from /proc/config.gz ...

Generally Necessary:
- cgroup hierarchy: cgroups Hybrid mounted, cpuset|memory controllers status: good
- CONFIG_NAMESPACES: enabled
- CONFIG_NET_NS: enabled
- CONFIG_PID_NS: enabled
- CONFIG_IPC_NS: enabled
- CONFIG_UTS_NS: enabled
- CONFIG_CGROUPS: enabled
- CONFIG_CGROUP_PIDS: enabled
- CONFIG_CGROUP_CPUACCT: enabled
- CONFIG_CGROUP_DEVICE: enabled
- CONFIG_CGROUP_FREEZER: enabled
- CONFIG_CGROUP_SCHED: enabled
- CONFIG_CPUSETS: enabled
- CONFIG_MEMCG: enabled
- CONFIG_KEYS: enabled
- CONFIG_VETH: enabled
- CONFIG_BRIDGE: enabled
- CONFIG_BRIDGE_NETFILTER: enabled
- CONFIG_IP_NF_FILTER: enabled
- CONFIG_IP_NF_TARGET_MASQUERADE: enabled
- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE: enabled
- CONFIG_NETFILTER_XT_MATCH_CONNTRACK: enabled
- CONFIG_NETFILTER_XT_MATCH_IPVS: enabled
- CONFIG_NETFILTER_XT_MATCH_COMMENT: enabled
- CONFIG_NETFILTER_XT_MATCH_MULTIPORT: enabled
- CONFIG_IP_NF_NAT: enabled
- CONFIG_NF_NAT: enabled
- CONFIG_POSIX_MQUEUE: enabled

Optional Features:
- CONFIG_USER_NS: enabled
- CONFIG_SECCOMP: enabled
- CONFIG_BLK_CGROUP: enabled
- CONFIG_BLK_DEV_THROTTLING: enabled
- CONFIG_CGROUP_PERF: enabled
- CONFIG_CGROUP_HUGETLB: enabled
- CONFIG_NET_CLS_CGROUP: enabled
- CONFIG_CGROUP_NET_PRIO: enabled
- CONFIG_CFS_BANDWIDTH: enabled
- CONFIG_FAIR_GROUP_SCHED: enabled
- CONFIG_RT_GROUP_SCHED: enabled
- CONFIG_IP_NF_TARGET_REDIRECT: enabled
- CONFIG_IP_SET: enabled
- CONFIG_IP_VS: enabled
- CONFIG_IP_VS_NFCT: enabled
- CONFIG_IP_VS_PROTO_TCP: enabled
- CONFIG_IP_VS_PROTO_UDP: enabled
- CONFIG_IP_VS_RR: enabled
- CONFIG_EXT4_FS: enabled
- CONFIG_EXT4_FS_POSIX_ACL: enabled
- CONFIG_EXT4_FS_SECURITY: enabled
- Network Drivers:
- "overlay":
- CONFIG_VXLAN: enabled
Optional (for encrypted networks):
- CONFIG_CRYPTO: enabled
- CONFIG_CRYPTO_AEAD: enabled
- CONFIG_CRYPTO_GCM: enabled
- CONFIG_CRYPTO_SEQIV: enabled
- CONFIG_CRYPTO_GHASH: enabled
- CONFIG_XFRM: enabled
- CONFIG_XFRM_USER: enabled
- CONFIG_XFRM_ALGO: enabled
- CONFIG_INET_ESP: enabled
- CONFIG_INET_XFRM_MODE_TRANSPORT: enabled
- Storage Drivers:
- "overlay":
- CONFIG_OVERLAY_FS: enabled

STATUS: pass

Based on the output above, the kernel configurations required by K3s are:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# K3s Generally Necessary:
CONFIG_NAMESPACES=y
CONFIG_NET_NS=y
CONFIG_PID_NS=y
CONFIG_IPC_NS=y
CONFIG_UTS_NS=y
CONFIG_CGROUPS=y
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_SCHED=y
CONFIG_CPUSETS=y
CONFIG_MEMCG=y
CONFIG_KEYS=y
CONFIG_VETH=y
CONFIG_BRIDGE=y
CONFIG_BRIDGE_NETFILTER=y
CONFIG_IP_NF_FILTER=y
CONFIG_IP_NF_TARGET_MASQUERADE=y
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
CONFIG_NETFILTER_XT_MATCH_IPVS=y
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_IP_NF_NAT=y
CONFIG_NF_NAT=y
CONFIG_POSIX_MQUEUE=y

# Optional Features:
CONFIG_USER_NS=y
CONFIG_SECCOMP=y
CONFIG_BLK_CGROUP=y
CONFIG_BLK_DEV_THROTTLING=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_NET_CLS_CGROUP=y
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_IP_SET=y
CONFIG_IP_VS=y
CONFIG_IP_VS_NFCT=y
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
CONFIG_IP_VS_RR=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
# Network Drivers
CONFIG_VXLAN=y
# Optional (for encrypted networks):
CONFIG_CRYPTO=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_GHASH=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=y
CONFIG_XFRM_ALGO=y
CONFIG_INET_ESP=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
# Storage Drivers
CONFIG_OVERLAY_FS=y

Compared to Docker, K3s mainly adds the following kernel requirements:

  • Overlay networking
  • Overlay storage

Kernel Configurations Required by Cilium

The kernel configurations required by Cilium can be found here: System Requirements — Cilium 1.13.4 documentation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# Cilium Base Requirements
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_NET_CLS_BPF=y
CONFIG_BPF_JIT=y
CONFIG_NET_CLS_ACT=y
CONFIG_NET_SCH_INGRESS=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CGROUPS=y
CONFIG_CGROUP_BPF=y
CONFIG_PERF_EVENTS=y
# Optional: Iptables-based Masquerading
CONFIG_NETFILTER_XT_SET=m
CONFIG_IP_SET=m
CONFIG_IP_SET_HASH_IP=m
# Optional: L7 and FQDN Policies
CONFIG_NETFILTER_XT_TARGET_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_CT=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_SOCKET=m
# Optional: IPSec
CONFIG_XFRM=y
CONFIG_XFRM_OFFLOAD=y
CONFIG_XFRM_STATISTICS=y
CONFIG_XFRM_ALGO=m
CONFIG_XFRM_USER=m
CONFIG_INET{,6}_ESP=m
CONFIG_INET{,6}_IPCOMP=m
CONFIG_INET{,6}_XFRM_TUNNEL=m
CONFIG_INET{,6}_TUNNEL=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_CRYPTO_AEAD=m
CONFIG_CRYPTO_AEAD2=m
CONFIG_CRYPTO_GCM=m
CONFIG_CRYPTO_SEQIV=m
CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_HMAC=m
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_AES=m
# Optional: Bandwidth Manager
CONFIG_NET_SCH_FQ=m

Additionally, Cilium has strict kernel version requirements — some Cilium features depend on newer kernel versions. Please refer to the official documentation for details.

Modifying Kernel Configuration and Compiling

The Linux SDK is generally provided by the official vendor. The directory structure for Rockchip-based Linux SDKs is fairly consistent. I’ll use Purple Pi OH as an example here. If you have a similar need with a different Rockchip board, you should be able to find the corresponding directory quickly.

The kernel configuration file is typically located at: xxxxxxx/kernel/arch/arm64/configs/xxxxx_linux_defconfig

Append the kernel configuration options listed above to the end of this file (make sure to deduplicate), then save.

Then simply compile:

1
./build.sh kernel

After compilation, a boot.img image will be generated in the ./rockdev directory.

Then use the Rockchip flashing tool RKDevTool.exe to flash just the boot.img.

│ Compiling is really resource-intensive — it takes a lot of time, CPU, and disk space 😂

Potential Issues

Partition Size Exceeded

During compilation, I encountered an error about the recovery partition exceeding its size limit:

1
2
rk356x_linux_sdk/buildroot/output/rockchip_rk356x_recovery/images/recovery.img's size exceed parameter.txt's limit!
ERROR: Running build_firmware failed!

The fix is to modify the partition size by editing the corresponding parameter.txt file. After modification, perform a full rebuild:

1
./build.sh

Then re-flash the entire firmware.

Docker Fails to Start After Installation

Following the official documentation: Install Docker Engine on Debian | Docker Documentation, Docker failed to start after installation.

The official docs clearly state that the latest version requires:

│ Debian Bookworm 12 (stable)
│ Debian Bullseye 11 (oldstable)

This is likely a compatibility issue with Debian 10. However, there’s a workaround.

The specific error was related to nftables.

The solution:

1
2
3
4
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives --set ebtables /usr/sbin/ebtables-legacy

After a reboot, Docker runs normally.

Conclusion

After spending a weekend tinkering with the Rockchip arm64 development board, I can finally run Docker, K3s, Tailscale, and Cilium on a board with just 2GB of RAM. 🎉🎉🎉

As I mentioned before, Arm development boards have these advantages:

  1. Cheap
  2. Highly hackable
  3. Low power consumption
  4. Minimal heat dissipation, silent operation
  5. The Arm64 ecosystem is decent enough nowadays

However, compared to x86, the ecosystem for these Arm boards is still quite lacking — no BIOS/UEFI, and installing the software mentioned above requires tweaking kernel parameters, compiling, and flashing. It’s exhausting…

x86 also has these advantages:

  1. Cheap
  2. Highly hackable

But the x86 ecosystem is so much more mature — it’s far less hassle.

Compared to x86, Arm’s real strengths are low power consumption and minimal heat. But now Intel chips like the N100, with a TDP of just 6W, are also very power-efficient and can be passively cooled for silent operation. Arm’s advantages are dwindling…

So here’s my recommendation: if you want a hassle-free, silent, low-power setup, go with an x86 mini PC first; if you want to tinker and still want silent, low-power operation, go with various Arm Pi boards or TV boxes; if you don’t care about power consumption or noise and want high specs, try a used x86 server. 😂😂😂

That’s all.

📚️ References


PI Series - How to Install Docker, Tailscale, K3s, and Cilium on a Rockchip Arm Development Board
https://e-whisper.com/posts/50964/
Author
east4ming
Posted on
July 19, 2023
Licensed under