前言
之前的文章(香橙派5plus上跑雲手機方案一 redroid(帶硬體加速))在Ubuntu的docker裡執行安卓,這裡說下怎麼在安卓手機下執行docker,測試也可以跑Ubuntu。
想在手機上執行docker想的不是一天兩天了,其實很久之前就有這個想法了,只是奈何安卓核心一直編譯不透過。現在覺得過了那麼久,技術應該有點提升了,覺得我又行了,所以又來試試。
測試用的手機是從閒魚淘的一個一加七Pro(12+256G),使用的系統是Lineageos19.1,後面放出我執行的刷機包和編譯的boot檔案,你直接刷進手機應該就能執行了。
檢查核心配置
首先檢查下當前的安卓核心確實哪些執行docker需要的核心配置
先下載https://raw.githubusercontent.com/moby/moby/master/contrib/check-config.sh
推送到手機的/data/local/tmp
下: adb push check-config.sh /data/local/tmp/check-config.sh
然後使用adb root
切換到root(需要再開發者模式裡開啟允許root除錯),接著執行sh /data/local/tmp/check-config.sh
檢視。缺少的其實挺多
編譯核心
要想在手機上原生執行docker,修改核心引數重新編譯核心這個是繞不過去的,所以先開始編譯核心。lineage的核心編譯比較簡單,如果下載系統原始碼來編譯的話基本沒什麼坑,這裡就不多說了。有興趣的可以看之前的文章:
- 為一加七Pro(LineageOs17.1 4.14核心版本)編譯KernelSu
- wsl2-ubuntu20編譯Lineage17(Android10)
執行docker也需要root許可權,所以會將kernelsu一起編譯進去,這裡也不贅述了。
修改核心引數
先說一下修改核心引數的流程:
cd kernel/oneplus/sm8150
進到對應的核心原始碼根目錄
export ARCH=arm64
指定核心編譯的平臺,不指定預設是x86
export SUBARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make vendor/sm8150-perf_defconfig
透過這個檔案生成.config
make menuconfig
啟動核心編輯選單
make savedefconfig
儲存.config
檔案為defconfig
,至於這個和手動修改有什麼區別就沒細究了,反正都推薦用這個
mv defconfig arch/arm64/configs/vendor/sm8150-perf_defconfig
覆蓋原先的核心配置檔案,建議先備份一下原先的檔案
rm .config
make可能有一個錯誤提示/bin/sh: 1: aarch64-linux-gnu-gcc: not found
,透過搜尋看到這個問答[1]說應該是缺少包:sudo apt-get install gcc-aarch64-linux-gnu
配置
這裡為了方便直接抄別人的核心配置放到.config
檔案裡: https://yzddmr6.com/posts/android-run-docker/
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_NETFILTER_XT_MARK=y
CONFIG_IP_NF_NAT=y
CONFIG_NF_NAT=y
CONFIG_POSIX_MQUEUE=y
CONFIG_NF_NAT_IPV4=y
CONFIG_NF_NAT_NEEDED=y
CONFIG_CGROUP_BPF=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_IOSCHED_CFQ=y
CONFIG_CFQ_GROUP_IOSCHED=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
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_VXLAN=y
CONFIG_BRIDGE_VLAN_FILTERING=y
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
CONFIG_IPVLAN=y
CONFIG_MACVLAN=y
CONFIG_DUMMY=y
CONFIG_NF_NAT_FTP=y
CONFIG_NF_CONNTRACK_FTP=y
CONFIG_NF_NAT_TFTP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_AUFS_FS=y
CONFIG_BTRFS_FS=y
CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_THIN_PROVISIONING=y
CONFIG_OVERLAY_FS=y
然後使用make menuconfig
在介面上一個一個檢視配置的開啟情況,發現CONFIG_BRIDGE_VLAN_FILTERING
沒有開啟,檢視了下是因為依賴項VLAN_8021Q
沒有開啟
而CONFIG_IPVLAN
則是依賴項NET_L3_MASTER_DEV
沒開啟
所以在配置檔案裡再加上這兩個配置, 再執行make menuconfig
儲存
CONFIG_VLAN_8021Q=y
CONFIG_BRIDGE_VLAN_FILTERING=y
CONFIG_NET_L3_MASTER_DEV=y
CONFIG_IPVLAN=y
CONFIG_CGROUP_HUGETLB
依賴於HUGETLB_PAGE
,但是將這個配置直接加到.config
不生效,介面上也不顯示具體的開啟路徑
問了下gpt說是在File systems
-> Pseudo filesystems
-> HugeTLB file system support
,在介面上啟用,再在配置檔案里加上CONFIG_CGROUP_HUGETLB
,再開啟介面看到就是啟用狀態。
準備工作都做完了,然後按照上面的命令儲存為defconfig在覆蓋原先的核心配置就可以開始編譯了
開始編譯
這裡需要到lineage原始碼根目錄,而不是在核心原始碼根目錄
source build/envsetup.sh
breakfast guacamole
make bootimage
接著就會出現一個折磨我兩週的錯誤:
aarch64-linux-gnu-ld is not allowed to be used. See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.
雖然他給了一個連結讓我們從裡面看更多資訊,連結裡也給瞭解決方法:
但是試了也是沒用,
用谷歌搜尋也搜不出什麼有效的方法,這兩天突然想能不能修改它提到的build/soong/ui/build/paths/config.go
檔案,問了下gpt,它說在config.go裡的Configuration里加一行"aarch64-linux-gnu-ld": Allowed,
就可以
試了下確實是可以,有時候gpt就很好用。我開始還以為是將ld
改成Allowed,因為前面明顯是字首。然後等待幾分鐘就編譯完成了
將生成的boot.img在fastboot模式下用fastboot flash boot boot.img
輸入手機後啟動手機。
檢測結果
編譯完的核心還有三個地方是紅色(missing)
第一處經測試不是核心引數的問題,需要執行一次這行命令:sudo mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup
,下面兩個無法解決,因為是非必須項,先不管它了。
補丁
有的提到還需要對net/netfilter/xt_qtaguid.c
做補丁,但我這個核心程式碼裡沒有這個檔案就跳過了。
補充
為了避免核心引數有遺漏,我們把https://github.com/lateautumn233/android_kernel_docker
裡的提到的核心引數也加到.config
裡,再重新編譯一次。
執行docker
目前看到的執行docker有兩種方式:
- termux
- 直接執行二進位制檔案
這裡我選擇第一種,第一種更成熟一點,很多東西都已經幫我們做好了。
termux
# The main termux repository, with cloudflare cache
deb https://packages-cf.termux.dev/apt/termux-main/ stable main
# The main termux repository, without cloudflare cache
# deb https://packages.termux.dev/apt/termux-main/ stable main
證書錯誤
使用apt安裝包時出現下面的證書無效。
Certificate verification failed: The certificate is NOT trusted. The certificate chain uses not yet valid certificate.
發現是手機的系統時間不對,沒有在證書的有效時間內,修改下系統時間就好了。這個我是安裝了一個via
瀏覽器去訪問百度,也跳出了證書不安全的提示,然後點選證書進去就看到證書有效時間是2023-12到2024-12的範圍,而手機的時間是2022,就猜測是時間不對。
換apt源
https://mirrors.tuna.tsinghua.edu.cn/help/termux/
將下面的內容先儲存為a.sh
,然後用adb push a.sh /data/local/tmp/a.sh
sed -i 's@^\(deb.*stable main\)$@#\1\ndeb https://mirrors.tuna.tsinghua.edu.cn/termux/apt/termux-main stable main@' $PREFIX/etc/apt/sources.list
apt update && apt upgrade
接著在termux終端輸入sh /data/local/tmp/a.sh
就好了。
遠端
apt install openssh
sshd
啟動ssh服務
whoami
檢視當前使用者
passwd
設定密碼
當然也可以透過公私鑰的方式配置免密登入,這裡我先用密碼了。安裝openssh的時候看提示應該就已經生成了公鑰,目錄是$PREFIX/etc/shh
,然後就和linux免密登入一樣了。
$PREFIX
這個變數是termux定義的,它類似於linux的根目錄,比如linux的/etc
目錄在termux裡就是指$PREFIX/etc
,這在後面的docker換源時會用到。
sshd啟動的預設埠是8022,我的使用者名稱是u0_a140
,在cmd下使用ssh -p 8022 u0_a140@192.168.31.248
就能連線了,也可以使用xshell這些工具連線。
切換pkg源
輸入termux-change-repo
,選擇第二個按空格回車,會藍色畫面一會(應該還是網路原因,很慢),等待出現源選擇,然後空格勾選阿里的源
先掛載cgroup
需要安裝pkg install sudo
,並且用kernelsu給termux root許可權,不清楚和下面的root-repo包有什麼區別
sudo mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup
這個每次重啟都需要執行一遍
執行docker
pkg install root-repo && pkg install docker
安裝root和docker
這時候需要先配置一下docker源,不然拉取不了映象
pkg install vim
mkdir -p /data/data/com.termux/files/usr/etc/docker
vim /data/data/com.termux/files/usr/etc/docker/daemon.json
將下面的內容加到這個檔案裡,記得前面要加個英文逗號
"registry-mirrors": [
"https://hub.uuuadc.top",
"https://docker.anyhub.us.kg",
"https://dockerhub.jobcher.com",
"https://dockerhub.icu",
"https://docker.ckyl.me",
"https://docker.awsl9527.cn"
]
sudo dockerd --iptables=false
執行docker服務
sudo docker run hello-world
這時候啟動docker容器會報錯,
docker: Error response from daemon: failed to create task for container: failed to start shim: start failed: io.containerd.runc.v2: create new shim socket: listen unix /data/data/com.termux/files/usr/var/run/containerd/s/fca432b16f1e32bdfce67923b7e94f3ab7f741783e5032a938bd6869d8b6d3af: bind: invalid argument: exit status 1: unknown.
這裡並不清楚什麼原因,但偶然記得之前在酷安上看到一個東西,過去翻了翻[2],說是要降級containerd
包的版本。先檢視下containerd
包的版本:
然後下載帖子裡這個包,用adb傳到手機上(xftp也可以),然後使用dpkg -i containerd_1.6.21-1_aarch64.deb
安裝
接著檢視版本apt show containerd -a
就看到已經安裝上了
然後重新啟動sudo dockerd --iptables=false
,在跑hello-world
容器就正常了
試了下跑python也可以,那說明可以在手機跑爬蟲了:
Ubuntu映象也是可以的:
刷機包和boot
https://github.com/kanadeblisst00/docker-in-guacamole
引用連結
- [1]
https://stackoverflow.com/questions/28565640/build-kernel-with-aarch64-linux-gnu-gcc
- [2]
https://www.coolapk.com/feed/51581431?shareKey=MmRlNTgxOTVmNjliNjY5M2QwMGU~&shareUid=4285440&shareFrom=com.coolapk.market_14.2.3
參考連結
https://gist.github.com/FreddieOliveira/efe850df7ff3951cb62d74bd770dce27
https://ivonblog.com/posts/run-docker-natively-on-android/
https://yzddmr6.com/posts/android-run-docker/
本文由部落格一文多發平臺 OpenWrite 釋出!