引擎下的PaaS, 第一章: kernel 命名空间

使事情简单化背后是非常繁重的工作。在dotCloud,我们将非常复杂的事务(例如部署和扩展web应用)打包进一个尽可能简单的环境中。但是我们在这样的环境中,如何进行工作呢?从kernel-level的虚拟化到监控,从高吞吐量忘了路由到分布式锁,从EBS处理到每分钟手机数百万的系统数据。。。如同一些人提到过的,弹性调度一个PaaS 就像是系统工程师的迪斯尼乐园。

本文是第一期文章,关于PaaS的架构和内部进行探索,并对dotCloud做更详细的说明。在第一段中,我们将介绍namespace,dotCloud平台用来对应用进行隔离的Linux kernel的特性。

Part 1: 命名空间(namespace)

这是我第一次接触 Linux Containers (LXC),我有一个非常错误的印象,就是LXC主要依赖于control groups(cgroup)。这是一个很容易发生的误解:当你创建一个新的container“Jose”,那么同时会产生一个同样名字的cgroup,“/cgroup/jose”。但是实际上,即使cgroup对于LXC非常有用,他们真正重要的基础架构是通过命名空间(namespace)来提供的。

NameSpace是LXC背后真正的容器。Namespace有很多种,每种都提供一个指定的资源。并且每个namespace都会创建对进程的隔离。这些隔离可以分为不同的级别。

pid namespace

这大概是对基础隔离最有效的命名空间。

每个PID namespace都有自己独立的进程编号。不同的PID namespace形成了一个等级划分:内核来持续追踪哪个namespace创建了其它的namespace。一个父namespace可以看到并操作他的子namespace;但是子namespace不能对父namespace做任何操作。由此产生如下结果:

  • 每个PID namespace有它独立的“PID 1”像进程一样被初始化;
  • 在一个namespace中的进程不能通过系统调用(例如kill或者ptrace)来影响父namespace或兄弟namespace中的进程,因为进程ID只在指定的namespace中有意义;
  • 如果一个伪文件系统(例如proc)被一个PID namespace中的进程挂载,他会只显示属于这个namespace的进程;
  • 因为不同的namespace中的进程编号是不同的,这意味着子namespace中的进程将会拥有不同的PID:一个属于自己namespace的,另一个属于父namespace的。

最后一项,说明从最顶层的PID namespace,你能看到运行在所有namespace中的全部进程,但是他们是不同的PID。当然,如果一个进程处在多于2层的namespace等级中,它也可以拥有多于2个PID。

The net namespace

在PID namespace中,你可以在多个隔离环境中启动进程(就让我们一劳永逸的称之为“容器”)。但是如果想要在每个container中,运行例如Apache这类服务,同一时间只能有一个进程监听80/tcp端口。你可以配置你的Apache实例来监听不同端口。。。或者使用net namespace。

如同名字一样,net namespace 是关于网络的命名空间。每个不同的net namespace可以拥有不同的网卡。即使lo这种支持127.0.0.1的loopback网络,在每个net namespace中也是不同的。

它可以创建成对的指定网络接口,这些接口将会出现在2个不同的net namespace中,并且允许net namespace和外部网络通信。

一个典型的container会包含自己的loopback网口,以及这样一个特殊的网口,一端命名为eth0,另一端则会在初始namespace中,显示为诸如veth42xyz0这样命名规则的网口。这是通过Enternet bridge来连接的2个网卡,或者在他们之间路由网络封包。(如果你熟悉Xen 网络模型,那么这没什么新鲜的)

每个net namespace都有自己的INADDR_ANY即0.0.0.0;所以,你的Apache进程在它的namespace中绑定到*:80,它只会监听直接发送到它所在的namespace的IP地址或网络端口 - 这允许你使用运行多个Apache实例,同时使用默认配置来监听80端口。

如果你还有疑惑,可以这样理解,每个net namespace有自己的路由表,自己的iptables链和规则。

The ipc namespace

IPC 提供信号量、消息队列和共享存储片段。

在几乎所有UNIX版本都支持的同事,这些功能也被很多人认为已经过时了,并且将会被POSIX semaphoresPOSIX
message queues
,和mmap取代。尽管如此,很多程序包括PostgreSQL依然在使用IPC。

这跟namespace有什么联系呢?每个IPC资源都有一个独一无二的32位ID。IPC实现了对资源的访问权限,尽管如此,一个应用访问指定资源的时候可能会失败,因为该资源可能已经被其它容易所使用了。

Introduce the ipc namespace: processes within a given ipc namespace cannot access (or even see at all) IPC resources living in other ipc namespaces. And now you can safely run a PostgreSQL instance in
each container without fearing IPC key collisions!

介绍一下IPC namespace:指定IPC namespace中的进程无法访问甚至无法见到其它IPC namespace中的进程。现在,你可以安全的在每个容器中,运行postgreSQL实例,而不需要担心IPC key 冲突。

The mnt namespace

你可能已经对 chroot很熟悉了,这套机制允许基于一个指定目录,对进程及其子进程创建一个沙箱。mnt namespace在其上更进了一步。如名所示,mnt namespace基于挂载点来进行处理。运行在不同的mnt namespace上的进程看也看见不同的挂载文件系统和不同的根目录。如果一个文件系统挂载到mnt
namespace中,它只能被这个namespace中的进程访问到;在其它namespace中则是不可见的。起初,这似乎很有用,它允许每个container拥有自己独立的目录,隐藏其它的container。仔细想一下,这真的有用么?如果每个container在不同的目录中,使用chroot,container C1 看不到 container C2的文件系统,对吧?是的,不过这只是副作用。

在container中检查/proc/mounts,就会显示所有container的所有挂载点。另外,这些挂载点也会被原始的namespace关联,这个namespace可以给你的系统进行一些设置,这就可能会跟你现有的应用产生冲突,如果你的应用是依赖于/proc/mounts的话。

mnt namespace使这种情况变得更加干净整洁,运行不同的container拥有自己的挂载点,只能查看自己的挂载点,他们自己的path被转换为namespace中真实的根目录。

The uts namespace

最后,uts namespace处理一个小细节:hostname可以被一组进程看到。

每个uts namespace将会被不同的hostname持有,并且改变hostname(通过系统调用 sethostname)将只会影响到运行在相同namespace中的进程。

Creating namespaces

namespace创建是通过系统调用 clone来实现的。这个系统调用支持大量的flag,允许指定“我希望创建新的进程来运行属于它自己的pid,net,ipc,mnt和utsnamespace”。在创建container 的时候,步骤如下:在新的namespace中,启动一个新的进程;创建网络接口(包括和外部通信的端口);运行初始化进程。在namespace中最后一个进程退出之后,相关的资源(IPC,网络接口等等)会被自动回收。如果,因为其他原因,你想要让这些资源继续存在,是有一个方法的。每个namespace都通过一个在/proc/$PID/ns
的文件实例化。在指定文件使用 mount --bind 命令,可以使每个namespace的文件被保留下来供以后使用。

每个namespace?不是很确切。3.4及以上内核版本中,只有IPC,net和uts namespace可以,mnt和pid namespace则不会。这在部分场景中可能是个大问题,例如接下来的场景中。

Attaching to existing namespaces

也可以通过将一个进程附加到已经存在的namespace的方式来进入这个namespace。为什么会有人想要这么做?一般来说,是用于在namespace中运行特定的命令。例如:

  • 想要在外部设置网卡,而不是依赖于container中的脚本;
  • 想要运行一些特定命令来获取container的信息:你需要从container外部监控container的运行信息,但是有时候,可能需要一些特殊的补丁工具(例如:你想执行netstat)
  • 想要在container中获得shell信息

Attaching a process to existing namespaces requires two things:

把进程附加到namespace需要2个条件:

  • setns 系统调用(只在kernel 3.0中,旧版本中需要Patch);
  • namespace必须在 /proc/$PID/ns 中

我们在之前的段落中提到过的文件和只能在/proc/$PID/ns看到的ipc,net,utsnamespace。那我们如何附加一个已经存在的mnt和pidnamespace呢?我们不能——除非修改内核。

合并必要的patch可能会相当棘手,并且解释如何解决AUFS和GRSEC的冲突也机会需要一整篇博客。如果你想要运行一个有很多patch的kernel,以下是一些workaround。

  • 你可以在container中运行sshd, 并且为将要执行的命令预先授权。这是最简单的解决方案之一,但是如果sshd崩溃,或停止运行(人为或者意外),你将会被锁在container之外。同样,如果你想要尽量多的压缩内存使用,你可能想要摆脱sshd。如果后者是你主要的考虑问题之一,你应该运行一个低消耗的SSH服务器,例如dropbear,或者你可以从
    inetd 或类似服务中,启动一个ssh server。
  • 如果你想要运行一些比ssh简单的程序(或者如果你想要运行和ssh不同的东西,来避免和ssh客户端配置交互),你可以开个后门。例如在初始化container的时候,运行
    socat TCP-LISTEN:222,fork,reuseaddr EXEC:/bin/bash,stderr (保证222/tcp端口在防火墙配置正确)。
  • 一个更好的方案是在运行init进程的时候,嵌入“control channel“。在改变跟目录的时候,init进程会在container根目录之外的路径上,设置UNIX socket。当根目录改变的时候,它将会继续持有这个文件描述符——因此保留这个control socket。

How dotCloud uses namespaces

在早期,dotCloud Platform 使用LXC。

非常早的时候,我们部署了patch过的kernel,运行我们把特定进程附加到已经存在的namespace中——因为我们发现这是非常方便并且可靠的部署、控制和编排方式。随着平台逐步进化,和初始”container“逐步剥离,我们依然使用namespace来隔离应用。

原文链接:http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part

时间: 2024-11-08 07:16:35

引擎下的PaaS, 第一章: kernel 命名空间的相关文章

libgdx游戏引擎3D开发教程-第一章-基础教程

开卷语:我最近才开始学习游戏编程,因为想做个网游玩,所以前几天找了不少引擎来看,于是不出意料的选中了libgdx,值得感谢的是libgdx的文档很多很全,所以没有走多少弯路就成功的配置好了环境.基础教程很完善,好多大神都已经写的很详细了,但是3D方面的很少见,所以我正好要学,索性直接翻译过来,大家共同进步.注意:教程基本是从Wiki上翻译过来,外加自己的小部分理解,所以一般来说应该没什么问题,如有错误请多多指教. =========================================

《MySQL技术内幕InnoDB存储引擎》读书笔记 第一章

Mysql体系结构和存储引擎 1.1 定义数据库和实例 数据库:物理操作系统文件或其他形式文件类型的集合.    数据库文件可以使frm,MYD,MYI,ibd结尾的文件. 实例:MySQL数据库由后台线程以及一个共享内存区组成.    数据库实例才是真正用于操作数据库文件的. 实例与数据库的关系通常是一一对应的,在集群情况下可能存在一个数据库被多个数据实例使用的情况. MySQL被设计为一个单进程多线程架构的数据库,这点与SQL Server比较类似,但与Oracle多进程的架构有所不同(Or

(linux shell)第一章--小试牛刀(下)

文章来源: (linux shell)第一章--小试牛刀(下) 1.6 数组和关联数组 1.6.1 预备知识 Bash同一时候支持普通数组和关联数组.普通数组仅仅能使用整数作为数组索引,而关联数组能够使用字符串作为数组索引.关联数组在非常多操作中相当实用. 1.6.2 实战演练 定义数组的方法有非常多,能够在单行中使用一列值来定义一个数组: array_var=(1,2,3,4,5,6)   #这些值将会存储在以0为起始索引的连续位置上 另外.还能够将数组定义成一组索引-值: array_var

第一章 Codec Engine概要

本文翻译自TI的手册,该手册是学习GPP+DSP开发的金典文档,希望对各位入门有所帮助,有理解不当之处望请赐教. Codec Engine Application Developer User's Guide Literature Number: SPRUE67D Codec Engine 应用开发使用手册原文参见: http://blog.csdn.net/dyzok88/article/details/42154487 后期会更新<第二章 Codec Engine安装和设置>. // 正文

【翻译习作】 Windows Workflow Foundation程序开发-第一章03

1.2.2.Visual Studio 2005扩展包 微软也为Windows Workflow开发者提供了Visual Studio 2005扩展包.扩展包将许多功能集成到Visual Studio里,其中就包括一个用于编制工作流的可视化设计器.下面就是可视化设计器的截屏图. 这个设计器的窗口式样与我们所熟悉的Windows和Web表单设计器保持一致.Toolbox(工具箱)窗口中列出了可以拖放到设计器台面上的所有活动.我们也可以把自定义的活动添加到Toolbox中去.一旦把一个活动放置到设计

第一章 Android系统的编译和移植实例

第一章 Android系统的编译和移植实例 这一章节主要介绍了Android系统的编译和移植技术,作为建立在Linux内核的基础上的Android操作系统,它的编译和移植不论在过程还是技术方面都和嵌入式Linux非常相似. 首先要准备一套可以正常运行Linux系统的一套开发版,需要在其移植Android系统,并能够正常运行. 移植的主要过程为: 1.下载Android Linux 内核 2.安装交叉工具链 3.移植Android Linux 内核支持的平台 4.安装Android SDK 5.获

第一部分 基础篇 第一章 走进MongoDB

声明:该文章主要来自<MongoDB实战>一书内容,主要想通过该书学习MongoDB的相应知识,加深理解,故写在自己的博文当中,作为记录在最后的章节中,会有一个自己集合MongoDB数据库应用的JavaEE的web应用. 第一章 走进MongoDB MongoDB是一个高性能.开源.无模式的文档型数据库,是当前NoSQL数据库产品中最热门的一种,它在许多场景下可用于替代关系型数据库或者键/值存储方式,MongoDB使用C++开发,MongoDB的官网是地址是:http://www.mongod

第一章《3D理论初步》

?? 小伙伴们,你们好! 经历了两年多的Cocos2d-x的学习与开发,我相信你们都已经成长为一名合格的Cocos2d-x程序员.但是,千万不要觉得这样就可以万事无忧了!3D时代已经来临,3D手游的产品越来越多,怎么办?使用Unity3D?嗯,是啊,Unity3D看起来不错的样子,不过,你是愿意放弃长期习惯的VC++的开发方式?你是否愿意放弃开源引擎自由掌控代码的感觉?你是否愿意从此站在引擎底层之外,只是做一个使用者? 如果你想快速的基于现有的Cocos2d-x经验或项目来增加3D部分功能,或者

《LINUX内核设计的艺术》第一章从开机家电到执行main函数之前的过程 学习笔记之一

从开机加电到实行main函数之前的过程 分为三步,目的是实现从启动盘加载操作系统程序,完成实现main函数的准备工作 启动BLOS,准备是模式下的中断向量表和中断服务程序 从启动盘加载操作系统程序到内存.加载操作系统程序就是靠第一步实现的 为实现32位的main函数做过度工作 1.1启动blos,准备实模式下的中断向量表和中断服务程序 由blos来加载软件操作系统的任务 1.1.1         BLOS的启动原理 0XFFFF0 由硬件来启动,CPU硬件设计逻辑设计为加电瞬间就强行将CS的值