Docker & Flatpak
目前最流行的技术莫过于Docker,Docker和Docker衍生的东西用到了很多很酷的技术,目前deepin应用软件发布转变成flatpak,这些看似风牛马不相及的技术方案,实际都使用了一个共同的底层技术——Namespace,假如没有namespace支持,这些技术实现都将成为空中楼阁。一句话总结,无论是Docker、sysmted-nspawn还是flatpak,都是在namespace基础上,针对不同的场景,生出的不同的解决方案。换一句话来说,它们都是namespace的孩子,龙生九子,各有不同罢了。
简介
Linux Namespace是Linux提供的一种内核级别环境隔离的方法。不知道你是否还记得很早以前的Unix有一个叫chroot的系统调用,chroot提供了一种简单的隔离模式:chroot内部的文件系统无法访问外部的内容。Linux Namespace在chroot基础上,提供了对UTS、IPC、mount、PID、network、User等的隔离机制。
举个例子,我们都知道,Linux下的超级父亲进程的PID是1,所以,同chroot一样,如果我们可以把用户的进程空间jail到某个进程分支下,并像chroot那样让其下面的进程 看到的那个超级父进程的PID为1,于是就可以达到资源隔离的效果了(不同的PID namespace中的进程无法看到彼此), 也正是这种隔离方式,才使得通过pid获取窗口名称的方式变得完全不可行。
简介到此,更多namespace的操作可以参考官方手册及网上的文档,下面主要介绍的是docker和flatpak在需要资源隔离的情况下,往往具体的业务需求又有共享的需求,在具体的应用中,他们都是如何进行资源限制,又是如何“打洞”突破这种限制的。
进程间通信
传统unix编程中,进程间通信有Socket、共享内存、管道、信号和消息队列等方式,在Linux namespace隔离下,除了Socket还能够工作以外,其他的方式都被完全隔离而无法使用。事实上, docker和flatpak都只使用了Socket这种方式用来做不同“容器”之间进程间通信。
上面docker通过端口绑定将内部端口(8080)映射到主机端口(80),容器外应用可以通过80端口来与容器内部的nignx通信。而flatpak更加大量使用socket作为通信手段,其中的x11/wayland/pulseaudio/dbus都是flatpak使用这些系统上已有的socket,通过绑定挂载的方式, 实现了图形绘制和音频传输, 假设xserver和pulseaudio没有提供socket通信的情况,flatpak就只能像--device=dri这种方式直接操作硬件了。
device=dri: 这种方式是直接将/dev/drm/card0直接bind挂载到了flatpak内部, 从而vdpau等可以通过drm操作显卡实现硬件加速
一切皆Socket!
话虽些许夸张,但是事实也是,无论是docker还是flatpak,几乎都是用的socket。作为运维支撑docker,次世代应用发布flatpak,他们的蓬勃发展都将未来的应用通讯向网络编程靠齐,进而改变linux技术实现发展方向。
文件共享
初学Linux一定听说过这句话 — “一切皆文件”,Unix通过将所有设备都抽象成文件,屏蔽了硬件的区别,提供统一的接口给用户。虽然类型各不相同,但是对其提供的却是同一套操作界面。更进一步,对文件的操作也可以跨文件系统执行。
但是,namespace中文件系统隔离,使得容器之间运行在不同的root文件系统上,我们的进程只能访问到自己所在文件系统的文件,无法访问到其他容器的文件,这时我们应该怎么办呢?
其实,解决思路很简单很粗暴,我们在准备容器的文件系统时,把那些我们需要访问的文件或者文件夹Bind到容器就好了。
上面docker通过将/host/path/nginx.conf挂载到/etc/ngnix/nginx.conf,容器内nginx读取/etc/nginix/nginx.conf配置,事实上我们往往是编辑/host/path/nginx.conf来改变/etc/nginx/nginx.conf,这种方式我们就可以将容器的配置迁移到系统,实现了配置或者存储的分离,而无须破坏docker容器的不可变特性。
而flatpak基本也是一样的套路,比如--filesystem=home就是flatpak自己包装了一下,将当前用户的家目录挂载到容器内部,说起来有点拗口,这样处理可以容器内部的应用也可以像操作家目录一样操作host的家目录,虽然应用一行代码不用改动, 但是我们应当明白他们之间的深层次差异。
难以打碎的“镣铐”
无论通过socket还是绑定挂载文件的方式,都需要在容器准备过程中完成,一旦容器启动再想通过socket或者联合挂载等方式访问容器外的资源就变得异常困难了。
另一个方面,这种资源限制也使得应用对系统的访问得到控制,从而在来自不可信任的第三方发布应用行为得到部分规制,从而使得去中心化的软件部署得以推广。
更进一步, flatpak针对dbus服务可被全局访问的问题,使用了proxy代理的方式对dbus规则进行过滤,确保容器应用在通过dbus跨进程通信得到管控。
无论是docker还是flatpak,一个重大优势是它的隔离性和安全性。因为容器将应用和运行平台隔离开了,应用以及它周边的东西都会变得安全。同时,不同的团队可以在一台设备上同时运行不同的应用——对于传统应用来说这是不可以的, 同时同一系统运行不同版本的应用也变得可行。
话又说回来,个人愚见正是docker或者flatpak使用的底层技术不具有太高的技术门槛,使得docker的母公司以及各类docker类公司的发展受限,面对投资人的压力,Docker公司正在戴着镣铐跳舞,无论舆论如何炒作容器化交付等概念,我们都要理性的看到容器是未来,但是docker不一定是未来。
总结
进程间通信和文件共享的解决方案,应当来说解决了不同容器间资源共享的大部分问题。
我们平心而论,这些解决方案都不能称作完美,甚至有点dirty。事实上,这种工程学的解决方式,在戴着镣铐跳舞的同时,镣铐却往往会被误认为是工具或者特性,比如docker容器大规范部署的潮流中,无法通过socket通信的应用或者服务很难容器化,这些服务用户量增长受限甚至出现萎缩。又如虚拟机或者终端模拟器这类应用,目前也无法在flatpak的技术方案获得支持。
但是毋庸置疑的是,容器化的流行改变了应用和服务的发布模式,也将越来越影响应用和服务的技术实现,进一步改变整个软件行业的规则。
【相关链接】