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: docker run --name some-nginx -d -p 8080:80 some-content-nginx
Flatpak:
  - --socket=x11
  - --socket=wayland
  - --device=dri
  - --share=network
  - --socket=pulseaudio
  - --talk-name=ca.desrt.dconf
  - --talk-name=org.freedesktop.FileManager1
  - --talk-name=org.freedesktop.portal.Fcitx
  - --talk-name=org.freedesktop.Notifications
  - --talk-name=com.deepin.filemanager.filedialog

上面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: docker run --name my-custom-nginx-container -v /host/path/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
Flatpak:
  - --filesystem=xdg-run/dconf
  - --filesystem=~/.config/dconf:ro
  - --filesystem=home

上面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的技术方案获得支持.
但是毋庸置疑的是, 容器化的流行改变了应用和服务的发布模式, 也将越来越影响应用和服务的技术实现, 进一步改变整个软件行业的规则.

1 条思考于 “Docker & Flatpak

发表评论

电子邮件地址不会被公开。 必填项已用*标注