[Root] Android手機跑Docker容器和Flatpak,Sony Xperai 5 II編譯自訂kernel

🇺🇸 English version

中華民國一百一十二年二月三日晨,解衣欲睡,夜色入戶,欣然起行,編譯核心。

Android核心跟GNU/Linux有差距,因此有Root也無法跑Docker。

在XDA終於有人移植新版LineageOS後,利用其核心原始碼為基礎,給Sony Xperia 5 II(pdx206)手機編譯自訂核心,使其能以原生效能跑Docker。 Docker running on Android phone, Sony Xperia 5 II

搞那麼大功夫就為了跑Docker?但少閒人如吾者耳。

1. 前置作業

  1. 將Xperia 5 II 刷成LineageOS 20,並將其Root。

  2. 安裝Termux並初始化。

  3. 下載Moby的指令稿用於檢查核心缺少的功能

1
2
3
4
5
pkg install wget tsu
wget https://raw.githubusercontent.com/moby/moby/master/contrib/check-config.sh
chmod +x check-config.sh
sed -i '1s_.*_#!/data/data/com.termux/files/usr/bin/bash_' check-config.sh
sudo ./check-config.sh
  1. 將CONFIG顯示為紅字的項目記下來。

Generally Necessary下的項目是一定要開啟的設定檔;Optional Features為可開可不開。

保險起見還是盡量全開,但我可以告訴你的是,ZFS到現在(6.1.9)都還沒進入Linux主線核心,所以這設定檔是開不了的。

2. 修改核心

2021年曾經給紅米Note 5製作過能跑Docker的核心,但當時是使用獨立編譯核心的方式,失敗率很高。因此這次我就採用跟著原始碼樹一起編譯核心的作法。

  1. 參考此文下載50GB左右的LineageOS 20原始碼。

  2. 跳到該文的「編譯Linux核心」段落。

  3. 進入編譯環境。

1
2
source build/envsetup.sh
breakfast pdx206
  1. 修改核心設定檔,切換至~/android/lineage/kernel/sony/sm8250/目錄,以pdx206_defconfig產生.config
1
2
export ARCH=arm64
make pdx206_defconfig
  1. 進入核心設定檔選單,開始修改核心設定檔
1
make menuconfig
  1. 對照Moby指令稿顯示紅字缺少的CONFIG,將其一一開啟。用上下鍵盤移動,選中下方Exit返回上一頁(退出時記得選Save),Enter確認,空白鍵選取。

  2. 例如要找IP_VS這個CONFIG,按/,搜尋,接著它會告訴你具體位置。有些CONFIG需要先滿足Depends on寫的CONFIG條件才會出現。

  3. 按照prompt去找,像CONFIG_IP_VS位於Networking Support -> Networking options -> Network packet filtering framework (Netfilter) -> IP virtual server support

  4. 有些功能低版本核心找不到就是找不到,例如CONFIG_CGROUP_HUGETLB要Linux 4.2以上核心才有,如果該設定檔沒有列在Generally Necessary就不用太緊張。

  5. 我另外啟用了CONFIG_BINFMT_MISC設定檔,方便跑跨架構的應用程式。

  6. 根據Frederico Oliveira的文章,需要修改核心原始碼目錄下的kernel/Makefile為以下內容。可用patch程式套用,或手動改原始碼。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
diff --git a/kernel/Makefile b/kernel/Makefile
index d5c1115..2dea801 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -121,7 +121,7 @@ $(obj)/configs.o: $(obj)/config_data.h
# config_data.h contains the same information as ikconfig.h but gzipped.
# Info from config_data can be extracted from /proc/config*
targets += config_data.gz
-$(obj)/config_data.gz: arch/arm64/configs/lavender_stock-defconfig FORCE
+$(obj)/config_data.gz: $(KCONFIG_CONFIG) FORCE
    $(call if_changed,gzip)

    filechk_ikconfiggz = (echo "static const char kernel_config_data[] __used = MAGIC_START"; cat $< | scripts/basic/bin2c; echo "MAGIC_END;")
  1. 接著修改net/netfilter/xt_qtaguid.c為以下內容:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
--- orig/net/netfilter/xt_qtaguid.c     2020-05-12 12:13:14.000000000 +0300
+++ my/net/netfilter/xt_qtaguid.c       2019-09-15 23:56:45.000000000 +0300
@@ -737,7 +737,7 @@
{
        struct proc_iface_stat_fmt_info *p = m->private;
        struct iface_stat *iface_entry;
-       struct rtnl_link_stats64 dev_stats, *stats;
+       struct rtnl_link_stats64 *stats;
        struct rtnl_link_stats64 no_dev_stats = {0};
@@ -745,13 +745,8 @@
        current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
        iface_entry = list_entry(v, struct iface_stat, list);
+       stats = &no_dev_stats;
-       if (iface_entry->active) {
-               stats = dev_get_stats(iface_entry->net_dev,
-                                     &dev_stats);
-       } else {
-               stats = &no_dev_stats;
-       }
        /*
         * If the meaning of the data changes, then update the fmtX
         * string.
  1. 修改完成後,用.config取代原本的pdx206_defconfig。下一步make clean後.config會被刪除。
1
cp .config arch/arm64/configs/pdx206_defconfig
  1. 編譯核心
1
2
make clean
mka bootimage
  1. 輸出的boot.img位於~/android/lineage/out/target/product/pdx206/。如果需要多次重複編譯,可以只刪這裡的檔案。

  2. Docker需要Root權限才能跑,所以要將boot.img傳到手機,開啟Magisk選取修補boot.img,再將修補後的magisk-boot.img傳回電腦。

  3. 使用fastboot將修補好的magisk-boot.img刷到手機。我另外將編譯好的成品放到了Github

1
fastboot flash boot magisk-boot.img

3. 執行Docker容器

開機後顯示:「你的裝置發生內部問題」是正常現象。

  1. 開啟Termux,手動掛載cgroup
1
sudo mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup
  1. 這次編譯的時候也順便開啟了binfmt設定檔,也許chroot的時候會用到,將其啟用:
1
2
3
su
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
echo 1 > /proc/sys/fs/binfmt_misc/status
  1. 再次執行Moby指令稿:sudo ./check-config.sh,查看CONFIG是否都變成綠字。

  2. 安裝Docker與Docker compose。目前Termux還沒收podman,也許可以用chroot或proot安裝?

1
2
pkg install root-repo
pkg install docker docker-compose
  1. 啟動Docker daemon
1
sudo dockerd --iptables=false
  1. 從螢幕左側滑進來,按New Session開啟新終端機。測試Hello World:
1
sudo docker run hello-world
  1. 應該會看到如下輸出

  2. 如果映像檔需要使用--init引數,那麼得編譯安裝tini

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
cd $TMPDIR/docker-build
wget https://github.com/krallin/tini/archive/v0.19.0.tar.gz
tar xf v0.19.0.tar.gz
cd tini-0.19.0
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$PREFIX ..
make -j8
make install
ln -s $PREFIX/bin/tini-static $PREFIX/bin/docker-init

測試成功之後,就可以在手機跑Docker容器了!可以嘗試跑Linux容器、伺服器服務、轉檔工具等等,也可以跑圖形界面再裝Box86 + Wine

如果映像檔只支援x86架構,在編譯binfmt後參考此篇解決。

目前Termux的Docker還有些缺陷,例如無法使用itptables、只能使用host網路(加上--net=host --dns=8.8.8.8引數)、docker-compose無法使用等問題。

關閉Docker前務必在Docker daemon的終端機按CTRL+C取消執行。

4. 安裝Flatpak應用程式

Docker需要的cgroups同時也能用來跑Flatpak應用程式。Flatpak是跨發行版的打包套件格式,可以輕鬆解決依賴問題。

chroot環境只要做些修改就可以跑Flatpak APP。

Flatpak apps running on Android phone

  1. Termux沒有收Flatpak套件,因此要先設定chroot Ubuntu環境。

  2. 修改登入Ubuntu的指令稿,在最前面加入掛載自身目錄的指令,防止出現Failed to make / slave: Invalid argument的bug。

1
2
3
4
5
# 加入至頁首
busybox mount --bind /data/local/tmp/chrootubuntu /data/local/tmp/chrootubuntu

# 加入至末尾
busybox umount /data/local/tmp/chrootubuntu
  1. 登入Ubuntu,安裝Flatpak,然後登出Ubuntu,手機重開機。
1
2
3
sudo apt install flatpak
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
exit
  1. 重新登入chroot Ubuntu,便可安裝Flaptak的應用程式,例如ffmpeg:
1
flatpak install org.freedesktop.Platform
  1. 執行Flatpak應用程式前要先啟動dbus:
1
2
mkdir /run/dbus
dbus-daemon --system
  1. 執行Flatpak應用程式可加上--devel看除錯輸出。
1
flatpak run --devel --command=ffmpeg org.freedesktop.Platform -version

參考資料


感謝您的閱讀。歡迎分享Ivon的部落格(ivonblog.com)的文章,引用或轉載請註明文章網址,並遵守創用CC-姓名標示-非商業性-禁止改作 4.0 國際授權條款。如需商業使用請來信告之。

written by human, not by AI

如果本網站文章對您有幫助,歡迎請我喝杯珍珠奶茶。

留言板

點選按鈕,選擇您覺得方便的留言系統。要討論程式碼請用Giscus,匿名討論請用Disqus。

這是Giscus留言板,需要登入Github帳號才能留言。支援markdown語法,方便您張貼程式碼,若要上傳圖片請貼Imgur連結。您的留言會在Github Discussions向所有人公開。

這是Disqus留言板,您可能會看到Disqus投放的廣告。無論有無登入皆可留言。此處留言只有本站參與者看得到。若您選擇以訪客身份匿名留言,就不會收到後續回覆通知。