docker-android:把 Android 模拟器压缩进容器,跑成一项服务

Android
Docker
开源
CI
自动化测试
KVM
2026/9/30
·

阅读时间: 大约 9 分钟

docker-android:把 Android 模拟器压缩进容器,跑成一项服务

容器内 headless 启动的 Android 模拟器主屏幕(sdk_gphone64_x86_64)

在 CI 流水线里跑 Android 自动化测试,长期是个”重量活”:Android SDK、平台工具、系统镜像、模拟器加起来动辄十几 GB,还要处理 KVM 权限、ADB 连接、黑屏无头显示等一堆环境问题。HQarroum 开源的 docker-android(MIT 协议,当前版本 1.1.0)想解决的就是这件事——它把一个最小化的、可通过网络远程控制的 Android 模拟器打包成 Docker 镜像,定位是”running the Android emulator as a service”。本文基于官方 README,分析它的体积取舍、加速方式与真实使用边界。

一、背景:为什么要在容器里跑安卓

传统上,Android 模拟器依赖本地图形栈与 KVM,开发者要么在本机 Android Studio 里点按钮启动,要么在自建的 CI 虚拟机里手工铺一套 SDK。这带来三个痛点:镜像体积大、环境难复现、难以并行扩缩。docker-android 的思路是把”启动一个干净的安卓环境”标准化成一行 docker run,让它像起一个数据库容器一样简单,特别适合 CI farm(无头测试集群)与未来的移动端 Agent 自动化场景。

二、是什么:极简的 Alpine 镜像

官方对镜像内容的描述非常克制:只包含三样东西——Android 模拟器本身、一个用于从容器外远程接入的 ADB server,以及带 libvirt 支持的 QEMU。基础系统是 Alpine Linux,并内置 Java Runtime Environment 11。它不预装多余的 IDE 或桌面环境。

其特性清单(官方)包括:

  • 基于 Alpine、捆绑 Android 模拟器并支持 KVM;
  • 可自定义 Android 版本(API level)、设备类型与镜像类型(Google APIs / PlayStore);
  • 在容器网卡上内置模拟器与 ADB 的端口转发;
  • 模拟器镜像每次重启都会被擦除(全新状态);
  • 默认 headless 运行,适合 CI;兼容 scrcpy 远程投屏控制屏幕。

三、技术机制:KVM 加速 + ADB/scrcpy 远程控制

容器要跑得动安卓模拟器,关键是把宿主机的 KVM 设备透传进去。官方给出的标准启动命令是:

docker run -it --rm --device /dev/kvm -p 5555:5555 android-emulator

--device /dev/kvm 把内核虚拟化模块挂进容器,QEMU 借此做硬件加速,否则模拟器会退回极慢的纯软件模拟。容器内的 ADB server 会自动监听所有网卡,宿主机执行 adb connect 127.0.0.1:5555 即可连上;之后再用 scrcpy 就能在本地实时看到并操作这台”跑在容器里的手机”。默认设备预设是 Pixel(1080×1920)。官方还提供了 CUDA GPU 加速变体,以及带 Google Play Store 的变体(后者需要自行在 ./keys 目录放入与客户端匹配的 adbkey,通过 adb keygen adbkey 生成)。

容器内模拟器的"关于模拟设备"页:设备名 sdk_gphone64_x86_64

四、关键数据:体积是它最大的卖点

README 里最有信息量的是一张构建变体体积对照表,这也是整个项目”size-optimized”主张的直接证据:

构建变体未压缩体积压缩后体积
API 33 + 模拟器5.84 GB1.97 GB
API 32 + 模拟器5.89 GB1.93 GB
API 28 + 模拟器4.29 GB1.46 GB
不含 SDK 与模拟器414 MB138 MB

可以看到:真正的体积大头是 Android SDK 与系统镜像本身,API 级别越高镜像越大(API 33 压缩后约 1.97 GB,比 API 28 的 1.46 GB 大约 35%)。官方还允许把 SDK 与模拟器从镜像中剥离(build 变体仅 138 MB 压缩后),再通过卷挂载外部 SDK,避免每次重建都重新下载。资源要求方面,官方明确建议跑 API 33 时分配 4 GB 内存、至少 8 GB 磁盘。

五、口径与方法批判:它”小”是有前提的

读这张体积表时要注意几个官方自己写明、但容易被忽略的前提:

  1. “最小”是相对的:1.46 GB(API 28)仍是个不小的镜像,所谓”精简”是相对于完整 Android Studio 开发环境而言,不是相对于一个普通 Web 容器。
  2. KVM 不是开箱即用:必须 --device /dev/kvm 透传,这要求宿主机 CPU 支持虚拟化、内核开启 KVM,且当前 CI 节点有权限访问 /dev/kvm。很多托管 CI(尤其是无嵌套虚拟化的共享 runner)默认拿不到 KVM,届时性能会断崖式下跌。
  3. 重启即擦除是特性也是约束:每次重启 AVD 都被清空,这对”每次测试干净环境”是优点,但意味着你不能把它当成一台持久保留数据的手机——需要保留数据时必须显式把 /data 挂成卷(-v ~/android_avd:/data)。
  4. PlayStore 变体需要额外密钥配置,不能 docker run 一条命令直接用上。

六、优势与局限

优势:

  1. 标准化、可复制:一条命令拉起带 KVM 加速的安卓环境,消除”在我机器上能跑”的环境漂移;
  2. headless 友好:专为无头 CI farm 设计,配合 ADB/scrcpy 可远程观察与操控;
  3. 体积可控、可裁剪:从完整模拟器到 138 MB 的无 SDK 变体,按场景取舍;
  4. 为移动端自动化 Agent 铺路:干净、可大规模并行、每次重置的安卓实例,正是 UI 自动化 Agent 需要的执行环境。

局限:

  1. 强依赖宿主机 KVM:无嵌套虚拟化的托管 CI 上跑不动或极慢;
  2. 项目成熟度一般:仓库版本号停在 1.1.0、仍有开放 Issue,镜像未发布到 Docker Hub 的官方托管标签说明以本地 build 为主,运维成本要自己担;
  3. 不提供持久状态:默认重启即清空,需要自己设计数据卷与快照;
  4. x86_64 镜像为主:截图中设备名是 sdk_gphone64_x86_64,跑的是 x86_64 系统镜像;若你的应用包含仅 ARM 的原生库,还需额外处理 ARM 翻译层,不在本镜像默认范围内。

七、谁该关注

  • Android 应用团队:想在 CI 里跑 Espresso/UI Automator 而不想维护笨重的模拟器 VM;
  • 移动端自动化/RPA 开发者:需要大量、可随时销毁重建的干净安卓实例来做批量操作;
  • 探索移动端 Agent 的团队:容器化安卓是构建”安全、可大规模启动”的手机自动化沙箱的一条现实路径。

如果你的 CI 节点拿不到 KVM、又必须测 ARM 原生库,那 docker-android 并不能替你解决底层问题——它解决的是”把安卓模拟器打包好、标准化启动”这一层,宿主机虚拟化能力仍要自己先备好。

参考来源