Skip to main content

ChromeOS 裸跑 Docker

· 7 min read

如果你拥有一个运行良好的 ChromeOS,如果你在寻找在没有任何容器或虚拟机的帮助下运行 docker 的方法,那就是这篇教程。 注意:即使你通过本教程的方法成功启动了 dockerd 和容器,也并不代表它会如你预期的一样运行,我强烈建议你使用 Debian 等一般发行版运行 dockerd 本文以 brunch 安装的 ChromeOS 为例,希望本文更多的是为你提供思路而非方法。

Q&A

  • 本文讨论的环境是什么:ChromeOS 及其衍生版本的系统命令行(即通过 crosh 进入的命令行),而非 crostini、crouton 等通过不同技术实现的容器环境。
  • 为什么需要在这种环境中运行 dockerd:好问题
  • 什么原因使我们需要额外的操作:原因有很多,比如没有包管理器,没有 systemd,没有内核支持,必须使用 root 用户运行,过多的文件系统限制等
  • 为什么你说 dockerd 而不是 docker:因为我们实际需要启动的是 docker daemon 而不是 docker cli

增加内核支持

开启内核选项

很遗憾在教程开头就抛出一个无法解决的问题:如果你的 cros 不是通过 brunch 安装的,也不是某些特定的衍生版本,那么你很有可能需要自行编译内核。 docker 所使用的容器技术依赖于内核的 namespace 和 cgroup 支持,docker 官方文档也写明了对于内核的要求:

  1. 64 位操作系统
  2. 内核版本高于 3.10
  3. 系统已经正确挂载 cgroupfs

ChromeOS 无法满足第三条要求,解决这个问题的方法有以下几种

  1. 使用 brunch 安装 ChromeOS,因为 brunch 替换了系统的内核并且开发者已经启用了相应的内核编译选项
  2. 使用某些满足要求的衍生版本,这里不再打广告
  3. 自行编译替换内核,在编译时开启相应的编译选项

事实上这些方法都是为了在内核中开启相应功能,我并不建议你自行编译内核,而如果你有能力自行编译内核应该不需要再阅读这篇文章。

使用 cgroup v2

经过我的测试,使用 cgroup v1 时无法正常启动 dockerd,所以我们需要改为 cgroup v2,编辑引导配置,在内核启动参数中增加cgroup_no_v1=all,再次引导后 ChromeOS 将不会挂载 cgroupfs。 在启动 dockerd 前挂载 cgroup 即可:

sudo mount -t cgroup2 none /sys/fs/cgroup/

你可以将这个命令写在开机脚本中或者启动 dockerd 的脚本中。

补足工具链

docker 官方文档中关于安装要求的另一部分就是工具链:

  • iptables 不低于 1.4
  • git 不低于 1.7
  • ps
  • xz 不低于 4.9

你可以选择安装Chromebrewbrunch toolchain或其他方法补足工具链

fake systemctl

这一步并非必须,但它对于我来说是一个很重要的步骤,如果你和我一样习惯于使用 systemd,那么你会喜欢这一节的,或者你也可以直接跳到下一节。

Linux 中有三个初始化系统最为有名:SysVinit、UpStart、Systemd。初始化系统作为系统的 1 号进程拥有运行时的不可替代性。ChromeOS 使用的是 UpStart,自行替换的可能性非常小,但 docker 仅支持 systemd,这导致我们无法方便地管理 dockerd。

docker-systemctl-replacement这个项目原本是为了解决 docker 容器中无法使用 systemctl 的问题(原因很简单,docker 容器与宿主共享进程号,无论哪个容器的 1 号进程都是宿主的初始化系统),核心文件是由 python 编写的systemctl3.pyjournalctl3.py,将这两个文件下载下来并重命名放入/usr/bin即可,他们实现了部分常用参数,足够用来管理 dockerd。(你可能需要修改文件中第一行的 python 可执行文件路径)

当然,fake systemctl 并非只有这唯一的实现,类似的实现均可满足我们的需要。

docker 安装并验证

由于没有包管理器,我选择通过直接下载二进制文件的方式安装 docker,从下载站点下载最新的二进制包解压并放入/usr/bin即可。

你可以通过直接运行 dockerd 或者上一节提到的 systemctl 启动 dockerd

sudo dockerd &
# or
sudo systemctl start docker
# then
sudo docker run hello-world

如果你的 dockerd 正常启动了,那么本文到这里就结束了。而如果你使用了我上一节提到的项目,你大概会遇到问题,因为docker-systemctl-replacement并没有提供对 sock 文件的支持,所以docker.service+docker.sock的配置无法使用,你可以在moby 项目中找到旧的配置模板