【笔记】没有docker没有root怎么build image?

这个问题其实还是比较有意思的,这几天又遇到一定要在没有root的机器上不能装docker的情况下build container的image…

几年前尝试过把docker image转化成一个img文件再加上linux kernel binary让虚拟机可以跑这个image。这次看了看,哦,听说Google那边有repo可以在k8s里直接build image,这么神奇?名字是kaniko,于是就去看了下使用方法:

FROM gcr.io/kaniko-project/executor:debug

COPY . /workspace/src
RUN /kaniko/executor \
   --context /workspace/src \
   --dockerfile /workspace/src/Dockerfile \
   --destination dockerrepo.example.com/image-name:version

这样运行完了,image就build出来并且push好了,是不是很简单。
它不就是执行了一个executor么?那现在没有docker,我可以运行它来帮我build image么?
我们docker save这个 executor 的image以后,发现里面主要就2个文件夹,一个是kaniko一个是busybox。那说明executor是static-linked呀,这就是说复制到任意一台linux机器上基本都能跑啊!

二话不说,找了一台机器,把dump出来的kaniko文件夹复制上去,然后开始运行。报错是理所当然的——kaniko的executor会告诉你这不是一个container环境。然后-h发现它有一个--force的flag,那还是赶紧加上运行。本来并没有看过kaniko的工作原理,直接壮着胆子就在机器上用root权限运行起了executor。当!很快executor就又报错了,说没有apt命令…我Dockerfile里的base image是ubuntu,那没有apt命令是几个意思?

这回真的得看看kaniko的源代码了。哪里错了我grep哪里。发现kaniko在pkg/constants.go里写死了几个path,其中有一个是ignore list,指向/proc/self/mountinfo。于是把这些hard code的path从const里拉出来变成var,然后可以通过env var赋值,下载golang编译。能自己指定ROOTDIR了,然后就报mountinfo no such file的错误,于是直接touch一个空文件给它,这下好了,executor终于往后走了。

过了一会,报错说什么网络连接timeout,连接53端口有问题…啥?DNS有问题?我的机器应该没问题呀?于是直接打开 /etc/resolv.conf 确认,发现nameserver 1.1.1.1,难道是我DNS原来设置就有问题么?于是改成知道的一个server IP,继续跑。前面的网络连接过了,后面又来timeout了,再去看/etc/resolv.conf发现它又变成nameserver 1.1.1.1了。oh,no,kaniko原来是直接把image下载下来然后覆盖root…回味着ignore list然后让executor进入trace模式打log,发现原来它是这样的原理:

  • 下载base image,将image的内容填充覆盖到/;跳过ignore list里的
  • 每次RUN都是直接运行当前环境的程序,然后结尾的时候列出当前/下的所有文件,和上一步的比对,看看哪些文件作了增改删;把这些改变记录再layer里
  • 最终得到一个一个layer的snapshot,拼成一个image的,如果设置了--no-push,可以将image通过--tarPath保存成.tar文件。

好了,知道了原理,也知道了我的这台机器即将报废,只要我一退出ssh估计就再也进不来了…

为了让它最后发光发热,我琢磨着不是有一个叫chroot的东西可以改root folder么,改掉了root folder是不是它就只能把东西覆盖到一个指定文件夹了?不过chroot好像需要root权限才能运行…有没有更高级的能再user mode运行的呢?啊,就是它了,proot。进入它的github,发现需要2个主要的dependencies,一个是libarchive,一个是talloc,下载默认编译,出来一个proot可以用了,尝试了一下,哇,可以用了,只要proot -r /path/to/fake/root -0 /kaniko/executor ...就能完美执行executor了。于是开开心心退出ssh让这台VM报废了。

之后我换了一台机器,弄了一个非root用户,把proot静态编译了一遍,这样executor和proot基本上kernel支持的所有linux就都能跑了。跑了一些用户的build case,发现了一些问题,比如在Dockerfile里RUN python就会挂,说什么random init error,这一看就是/dev的问题啊;好在proot给出了解决方案,-b 就能把/dev下需要的设备mount到非root下的dev文件夹里的,比如-b /dev/null:/dev/null -b /dev/urandom:/dev/urandom

这下应该没有什么问题了,后面就是用户遇到什么问题帮他们解决什么问题了,没有docker没有root照样build image…

后记:其实现在的去docker去clone技术已经成熟,在security需求旺盛的当下工具也是无穷的多…比如这个udocker可以login pull create然后一行一行run command,最后save成tar就可以load到docker里了,虽然没有中间层了,但是也是一种方式,没有docker没有root的日子我fake root~

你可能感兴趣的:(cloud,Platform,docker,build,kaniko,proot,非root)