精子创办了一档播客节目,大家可以在 iTunes 搜索「彩排」,或访问  caipai.fm  来收听。

我录了一档叫「彩排」的播客

一个人住有一年时间了,也养成了听播客的习惯,我最喜欢的是 IPN 一档叫「太医来了」的播客,同时我也听过「内核恐慌」和「 Teahour 」这样的技术类播客,听久了也有自己录一档播客的冲动。

终于经过了很多的准备工作之后,我把这个想法付诸实践了,播客的名字叫「彩排」,你可以在 iTunes 直接搜索,也可以访问 caipai.fm 在线收听和下载。如果有任何的建议意见,可以发邮件到 feedback@caipai.fm

前三期的主题分别是「自由软件和许可证」、「番茄工作法」、「密码和互联网安全」,我本不想把它限制为一个技术类播客,但我所了解并且可以分享给大家的恐怕大部分都是技术方面的话题了。接下来的选题可能会包括: Email 、 JavaScript 、比特币、养猫等。

因为我本来不善言辞,也没有音频录制和剪辑的经验,最后效果其实不是很理想,还不能与开头提到的几档播客相提并论。但在这前三期的制作中,我的水平也在一点点提高,期待将来能越做越好吧。此外我感觉一个人讲会让听众有一种「压力」,可能还是两个人以对话的方式录效果会更好,如果你希望参与进来也欢迎和我联系。

我看「刷月饼」事件

前因后果见 知乎:阿里月饼事件;关于本文的讨论见 V2EX: 关于刷月饼事件我来唱点反调

可能发得有点晚了,是因为我不是有感于事件本身,而是看了大家的讨论一边倒地黑阿里,以至于有一些逻辑显得不是那么合理,所以我想 仅就几个细节问题 谈一谈我的想法。

这是不是一个价值观问题

我觉得这是一个价值观问题,就好像就是有人觉得「刷月饼」不妥甚至很严重,也有人认为没什么大不了。所谓价值观就是指你如何看待一件事情的对错、如何进行选择,很难说谁对谁错,但这两种人的价值观的确是不同的。公司因为价值观不同开除一个员工其实也没什么不对,对双方都有好处,如果被开除的人不觉得是自己的错,那么也很难说是对他的伤害。

下单但没有购买算不算得到了「利益」

既然下单是需要抢的,说明这个订单很可能对应着一份库存,你下单成功了意味着你得到了这样一份权利 —— 你可以在未来的一个小时里决定要不要买这个月饼,你甚至可以等有人出了一个合适的价格之后转卖这个月饼,可以说这种购买的权利就是「抢月饼」的核心利益,所以订单最后是否成交不影响刷月饼获利的这个事实。

信息安全相关职位刷月饼是否可以减轻责任

的确可能这个职位的工作之一就是去发现漏洞,但这也是在有工作安排的情况下,而且发现漏洞(活动规则设计不合理可以认为是广义的漏洞)后也不应该去利用它为自己谋利(是否算谋利已在前一小节讨论)。所谓 Geek 精神不应该被当作一个挡箭牌,在一个大的群体里还是要去遵守普适的规则,刷月饼就好像钻公司规章中的空子。打一个比方的话就好像办公室桌上有十几块月饼给大家吃,并没有限制一个人可以拿几块,但你一个人就拿了一大半,这显然不妥。

抢月饼网站设计不合理开发者是否有责任

我觉得这本来就是一个内部的活动,要考虑一个投入产出的性价比,不可能做到和对外的服务一样稳定和周全,在公司内部大家是有一个基本的信任的。因为往往一个公司的同事之间有着共同的利益和相近的价值观,没必要将方方面面都限制死,相信如果为抢月饼设计一个事无巨细、毫无漏洞的规则也不是大家希望看到的。

抢火车票和抢月饼是否是一回事

和前一点有点像,对外和对内是有分别的,从抢火车票这一点来说,你对其他买不到火车票的人是不负有任何的责任的,只要你不违反法律和协议你可以做任何事情;但在公司内则不同,大家需要有基本信任,即使没有明文的规则写明,当然你也可以不遵守这种「潜规则」,后果大概就是因为价值观不符被开除了,只要补偿给到位,开除当然也是合法的。

写在后

说实话,当我说出这些想法之后我有点怀疑人生,有点怀疑当我的意见和别人不同的时候我是否应该说出来,因为有的时候说出来会招致一些攻击,也会被一些本来是朋友的人划为异类。每当我看到这种一边倒的舆论的时候,我总会有点警惕,因为一边倒意味着既然大家的目标是一样的,即使过程有一些小差错也无所谓,当你指出这些问题的时候,就会有人说你在洗地。没错,腾讯抄袭的时候我给腾讯洗、百度搞竞价排名的时候我给百度洗。

回到讨论本身,我简单补充几点:

  • 如果有公司真的会因为「价值观」而开除一名员工,我觉得是值得尊敬的,因为这家公司会在意在一起工作的同事是什么样的人,只有这样才能构建出一种凝聚力。当然,这在大公司是很难做到一碗水端平的,也很难说这是否是阿里开除几名员工的真正原因。
  • 很多人比较在意最后两点中的「双重标准」,我觉得这是一个很正常的事情,对家人、对同事,和对陌生人我们是有不同的要求和期待的,在公司抢月饼要比在陌生人间抢火车票有更多的道德约束我觉得也是合理的。

Docker 与容器化技术实践

这篇文章由我 7 月末在 Connext 2016 进行的一次技术分享整理而来。

RP 主机

我在高一的时候开始尝试搭建自己的网站,当时市面上的「虚拟主机」基本上只提供 PHP 环境,限制也比较多。于是我在 Linode 以每月 20 美元的价格买了一台 Linux VPS 用来搭建网站,但当时我的零花钱无法负担这个开销,于是尝试性地公开出售服务器资源,为此我编写了一套叫 RootPanel 的虚拟主机管理系统。

和其他虚拟主机不同的是,RP 主机的用户可以有非常大的权限 —— 可以登录 SSH, 运行 Node.js、Python 之类的程序;而 RootPanel 则通过 Web 的界面允许用户使用 MySQL、MongoDB 数据库,并且通过 Nginx 共享 80 端口,RootPanel 会检查用户的请求是否符合权限要求,然后去与 Nginx 这些系统服务交互。

当时 Docker 还没有出现,我用了一些比较「传统」的方式来隔离 RP 主机上用户的权限:

  • 文件系统:Unix users(文件权限)、quota-tools(磁盘空间)
  • CPU 和内存:自行编写脚本来调整进程优先级(CPU 超限时)和杀进程(内存超限时)
  • 进程和网络:因为 Unix 本身的权限,无权向其他进程发送信号

在运行 Web 服务时,后端程序(例如 PHP-FPM、Python 的 uwsgi、Node.js 应用进程)本身由用户运行,以 Unix Socket 的方式提供服务(Unix Socket 会遵守 Unix 的文件权限机制),然后可以在 RootPanel 的 Web 界面上配置从域名到 Unix Socket 的映射(RootPanel 会检查你配置的 Unix Socket 是否在你的 home 目录中等),由 Nginx 完成反向代理,实现共享 80 端口。

Redis 和 Memache 这种轻量级数据库也是由用户自行运行的,通过 Unix Socket 提供服务来避免被其他用户访问到。出于性能考虑,所有用户会共同使用同一个 MySQL 和 MongoDB,用户可以在 RootPanel 的 Web 上创建和管理数据库,RootPanel 会为每个用户分配一个用户名和密码,使用这些数据库本身的用户机制进行权限控制。

当然 RP 主机现在已经被关掉了,详见 RP 主机和 GreenShadow 关闭计划

「隔离」和「资源控制」

到后来 2014 年初的时候我发现了 Docker, 它是一个基于 Linux 的轻量级虚拟化技术,可以以非常低的成本来创建与主机隔离的、可以独立进行资源控制的「容器」。

在前面 RP 主机的例子中,我们虽然一定程度地解决了这两个问题,但并不完美。隔离方面 RP 主机只做到了权限的隔离,但用户依然可以看到其他用户和它们的进程、网络链接;资源控制方面,CPU 和内存都依赖于脚本进行控制,控制的粒度和准确性显然不如利用内核本身的特性。

Docker 使用 Linux 2.6 提供的 namespaces 特性来隔离容器之间的文件系统(mount namespace)、主机名(UTS namespace)、进程(PID & IPC namespace)、网络(network namespace)、用户(user namespace)。使容器中的进程只能看到与自己有关的系统资源,完全感觉不到主机上其他的容器的存在。

Docker 还使用了 Linux 2.6 提供的 cgroups 特性来统计和限制容器的系统资源,包括 CPU(cpuset & cpu & cpuacct cgroup)、内存(memory cgroup)、磁盘 IO(blkio cgroup)等。在资源控制方面,因为是由内核执行的,因此可以进行非常细粒度的控制,例如在 CPU 上,既可以为容器设置权重,也可以直接设置最大使用率。

联合文件系统

在解决了隔离和资源控制之后,我们可以允许容器自由地修改容器内的文件系统,每个容器可以使用不同的发行版、运行不同版本的系统服务。但为了允许容器去自定义它们的文件系统,我们必须要为每个容器挂载一个单独的根目录,这样将会占用大量的磁盘空间。

为了解决这个问题,Docker 基于「联合文件系统(AUFS、OverlayFS)」实现了一个「镜像」的功能。联合文件系统是一种可以将不同的目录,以分层「叠加」的方式挂载为一个文件系统的文件系统。Docker 会将不同容器间共同的部分作为一个共用的只读层(例如发行版就是一个层),然后为每个容器再叠加一个可写的层,容器对文件系统的修改会写入到这个可写的层,而不是共享的层,在容器运行结束后,这个可写的层也可以固化为一个只读的层,被其他容器复用(这就是 docker build 的过程)。

将应用封装为镜像

Docker 的容器实际上都是从 Docker 镜像创建出来的,可以说镜像是容器的模板,这个概念类似于进程是由可执行文件创建出来的,但镜像不仅仅包含可执行文件,而是包含了一个程序允许所需要的所有环境。

我们可以通过 Dockerfile 来创建镜像,Dockerfile 中包含了若干指令,这些指令会在容器中被执行,而这些指令对文件系统的修改,会作为构建出的镜像中的一个「层」。

Docker 镜像让应用的「交付」变得简单了,在理想的情况下,Dockerfile 中包含了构建应用所需要的运行环境的指令,而镜像则是一次构建的结果,Docker 为镜像提供了二进制级别的兼容性,镜像可以被传输到其他 Linux 主机上直接运行,交付一个应用就像发送一个可执行文件那么简单。基于我们前面提到的联合文件系统,Docker 镜像在传输时只会传输新的层,如果不同的镜像基于同一个基础的镜像(层)来构建,那么并不会产生额外的传输和存储开销。

无状态的容器

在一个服务器端系统中,包含了大量业务逻辑、需要频繁修改的「应用进程」是最不稳定的部分,它可能会出错、会崩溃重启、会占用大量的计算资源,因此我们必须要能够快速地对包含应用的容器进行调整。为了做到这一点,一个得到了广泛认同的实践就是将应用实现为「无状态」的,即不在内存中持久性地保存数据,而是将这些状态存储到专门的数据库(Redis 等)中,这些数据库会有自己的分布式解决方案,而不必我们操心。

这样我们便可以随时停止和启动一个应用容器,而不必担心数据丢失或状态不同步,同时无状态的应用对容器数量也毫不关心,我们可以根据业务的负载情况随时调整容器数量进而增加业务的负载能力,应用也不关心这些进程运行在哪台服务器上(Docker 的镜像为容器提供了一致的运行环境),只要前端的负载均衡(Nginx)可以发现它即可,因此我们还需要一种「服务发现」的机制让负载均衡服务能够感知到新容器的加入和已有容器的退出。

分布式的容器调度

在一个公有云的场景中,我们往往需要管理运行在几十台服务器上的几千个容器,物理设备总是可能出现故障的,随着集群规模的增长,出现故障的频率将会越来越高,我们必须能够自动地发现和恢复这些故障,我们将这种程序称为「集群管理器」,它需要关注的问题包括:

  • 容器崩溃:应用进程因错误或内存超限退出,可以简单通过设置 Docker 的重启策略来解决。
  • 容器僵死:负载均衡器应该能够将应用容器无响应的情况通知给集群管理器来重启容器。
  • 服务器崩溃或失联:集群管理需要将崩溃的服务器上的容器移动到其他的服务器并从负载均衡中移除。

在一些计划中的维护任务也需要保证服务不中断:

  • 部署新版本:应逐个启动新版本的容器并加入负载均衡,确认新容器工作正常后再将旧容器从负载均衡中移除并停止。
  • 调度到资源充足的服务器:集群管理器应该能够感知到各个服务器的负载情况,将负载较高的服务器的容器移动到负载较低的服务器。

集群管理器需要决定将容器部署到哪台服务器,需要考虑的因素包括:

  • 服务器实际负载。
  • 有时容器会声明自己需要多少资源,虽然实际并没有占用这么多,但一段时间之后可能会有变化。
  • 将容器分散到不同的服务器以应对单个服务器失效。

集群管理器还应该能够应对自身或所依赖的服务失效的情况,通过反复地重试保证实际运行的容器与计划中的一致。

在集群管理器方面社区已经有了很多成熟的解决方案,例如 Docker Swarm、Kubernetes、Marathon,作为私有云来说都基本够用,但在公有云的场景下经常还是需要自己开发一部分功能来和现有系统(例如计费)整合的。

小结

因为随着需要处理的数据量越来越大,我们必须将系统设计成分布式的,这需要我们将计算资源进行一个抽象,不去考虑有关运行环境的细节问题,所以虚拟化是一个大的趋势。基于 Docker 的容器是虚拟化解决方案中的一种,也是目前受到了非常多关注的一种,这大概是因为内核级别的虚拟化有着非常好的性能,同时 Docker 作为一个开源的产品也有着非常活跃的社区。我今天主要介绍的是我在部署环节对 Docker 的实践,但 Docker 的应用并不止于此,在开发和测试环节同样有 Docker 的身影。

参考链接

12367

精子生于 1995.11.25, 20 岁,英文 ID jysperm.

订阅推送

通过邮件订阅精子的博客日志、产品和项目的最新动态,精子承诺每一封邮件都会认真撰写,且每周不会超过一封。有想和精子说的话可以直接回复邮件。

该博客使用基于  Hexo  的  simpleblock  主题。博客内容使用  CC BY-NC-SA 3.0  授权发布。最后生成于 2016-09-20.