在 Android 上使用 Docker

Posted on Dec 8, 2023

前置环境搭建

系统

ArchLinux

我使用的是 ArchLinux,工具链什么的搭建起来比较简单,我这里使用的是 gcc,clang 的话可以自己找一下教程

1
yay -S aarch64-linux-gnu-gcc aarch64-linux-gnu-binutils aarch64-linux-gnu-glibc aarch64-linux-gnu-linux-api-headers

可能还需要安装一些别的工具,比如 makebc等,如果发现缺失了,自己装上就好了。

手机

手机需要 root,需要能解 BL 锁,因为我们需要修改内核,需要自行编译内核

我使用的是 2017 年发布的 OnePlus 5T,高通骁龙835,一代神U,这不比树莓派强多了(

内核

这个简单,我们随便上 xda 或者国内手机社区论坛什么的找一下 rom,甚至是 lineage 的支持设备列表中寻找(不全),一般会给出内核的 git 仓库,就算没有,用官方的仓库也是 ok 的。

我这里选用了这个 rom

[ROM][OSS][13][September] ONEPLUS 5T [dumpling] Project Elixir…

Untitled

点进红框的地方,clone 下来就 ok 了

但是这个 rom 给的内核源码有点问题(换了个内核),坑了我一天,这个后面再说

AnyKernel3

我们编译内核得到的产物是 Image.gz-dtb ,无法直接通过 recovery 刷入到手机中,所以需要一个工具转一下格式,这里选择的是 Anykernel3

https://github.com/osm0sis/AnyKernel3

我们将其 clone 下来,修改以下其中的 anykernel.sh

1
2
3
do.devicecheck=0 # 不检查设备型号
block=/dev/block/bootdevice/by-name/boot;
is_slot_device=0; # 这个看你手机是否为 AB 分区

Termux

下载 termux,然后安装到手机里备用

https://github.com/termux/termux-app

编译

开始编译

OK,一切准备就绪,我们可以着手编译内核了,我这里建议先编译一份完不加修改内核的刷入手机,确保开源的内核是“可用的”。

首先,我们先去内核目录下的 arch/arm64/configs/ 下找到设备的 defconfig (32位设备去arch/arm/configs 下找),

1
2
3
4
5
6
7
8
export ARCH=arm64 # 目标架构
export SUBARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu- # 工具链前缀
export CROSS_COMPILE_ARM32=arm-none-eabi- # 32 位工具链前缀,有些需要有些不需要
rm -rf out
make mrproper # mrproper 可以理解为 make clean
make O=out oneplus5_defconfig
make O=out -j24

啪一下非常的顺利啊,非常顺利的报错了

Untitled

仔细看了眼,全都是 -Werror 报的

我们可以去添加编译选项,添加什么 -Wno-duplicate-decl-specifier -Wno-address 之类的,看见报啥就加啥,但是这样有点多了

直接一步到位,把 -Wall 改成 -w ,一劳永逸

Untitled

当出现

Untitled

就代表编译成功了

合成可刷入的内核

你可能注意到了,我们的编译参数里有一个 O=out,代表我们将编译的中间产物和最终产物都放到了 out 目录中去,当然这个参数也可以不加,没有什么影响

在源码目录下的 out/arch/arm64/boot/ 中找到 Image.gz-dtb,将它复制到我们前面 clone 下来的 Anykernel3 目录下,执行

1
2
3
4
5
6
zip -r kernel.zip \
anykernel.sh \
Image.gz-dtb \
LICENSE \
META-INF \
tools

得到了 kernel.zip,就可以拿着它往手机里面刷了

如果一切都是 ok 的,手机也能正常开机

检查缺失的配置

启动 termux,运行

1
2
3
4
5
6
pkg install tsu
pkg install wget
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

得到的结果差不多长这样,当然了没有修改的会有很多的 missing,我这个是修改好了的

Untitled

得到了结果,我们就可以顺着这些红色的 config 去修改我们内核的配置了,一般来说,Generally Necessary 是必须要全部变绿的

开启 docker 配置

方法1

回到源码目录执行

1
make O=out menuconfig

按下键盘上的 ‘/’ 键,就是那个问号,然后照着红字一个一个搜

Untitled

Untitled

按数字 1,然后按下空格打开它就行了

有些不能直接打开,因为它可能依赖一些别的开关,注意一下下面的条件,有些是 n 的,复制它再搜索一下,把依赖打开就行了

方法2

直接修改 arch/arm64/configs/oneplus5_defconfig,往文件后面追加这些 config 就 ok 了

修改完之后,执行

1
make O=out -j24

等待编译结束,得到 image.gz-dtb ,重复之前的操作即可

番外

这里就要吐槽一下,我一开始是用的这个内核编译的,也是基于这个内核改的 config

GitHub - MudabbirulSaad/kernel_oneplus_msm8998

结果在编译的时候一直给我报 cfs_rq->runtime_remaining 的错,说 cfg_rq 里没有 runtime_remaining 这个成员,我寻思这肯定是我的问题,不知道哪里弄错了,于是搜了半天关键字发现就是没有这个东西,我就把 CONFIG_CFS_BANDWIDTH 关掉,就可以编译通过了。

我想的是先开机再查问题,却是在开机 logo 之后重启进了 recovery,于是我又二分改了改配置发现是 CONFIG_MEMCG 导致的,我关掉了它就可以开机了。

但是这样我用不了呀,我又把 CONFIG_MEMCG 开回来,通过 adb logcat 看log有没有报错

前几行就告诉我 lmk 启动失败找不到规则什么的,我也不太懂,于是就去翻了下 github 的提交记录,发现了这么一笔提交

Untitled

猜想可能和这个有关,我给改回左边,重新编译,这次成功启动了!!!!

可是在 检查缺失的配置 的时候,发现我开的配置一!个!都!没!绿!

我想想算了,然后去换了个内核,用的是这个

GitHub - TheNoFace/kernel_oneplus_msm8998

这次很顺利,改完 makefile,刷进去能开机,改配置刷进去,也能开机,可以说是非常的顺利

使用 docker

打开 Termux

1
pkg install docker

等待完成

1
2
3
4
sudo mount -t tmpfs -o mode=755 tmpfs /sys/fs/cgroup
sudo mkdir -p /sys/fs/cgroup/devices
sudo mount -t cgroup -o devices cgroup /sys/fs/cgroup/devices
sudo dockerd --iptables=false

Untitled

开启另一个终端

1
sudo docker run --rm hello-world 

Untitled

成功运行~我们的任务达成了,现在可以干自己想干的事情了

其它问题

关掉 CONFIG_ANDROID_PARANOID_NETWORK

echo “nameserver 1.1.1.1” > /etc/resolv.conf

还有一些问题,比如网络,挂载目录,可以看下面的 ref.

Ref

https://gist.github.com/FreddieOliveira/efe850df7ff3951cb62d74bd770dce27