文章归档

Namespaces系列4:user namespace

User namespaces are have been introduced as early as Linux 3.5 and are considered as stable starting with Linux 4.3.

1. 简介

user namespace是最近才出现在内核主干里的,主要是为了隔离安全相关的标识和属性,例如 user IDs and group IDs (see credentials(7)), the root directory, keys (see keyctl(2)), and capabilities等等。但是从内核实现上来看,user namespace只是简单的提供了一种uid/gid映射机制,capabilities虽然与user namespace非常相关,但它不是user namespace中的概念,capabilities是进程的概念,它是进程的一种属性,它要远比user namespace出现的早

在这篇文章里,我们分四步走:

  1. 我们先来了解一下,user namespace的基本用法
  2. 以及user namespace如何结合capabilities实现容器的安全性隔离
  3. user namespace在解决什么问题?
  4. 内核实现
  5. 与其他namespace的交互以及兼容性问题

简单来说,有了这个东西之后,容器可以有一个假的root账户,在不影响宿主安全的情况下,最大限度的使用更多的内核特权功能,user namespace让容器变得更像虚拟机了

»» 继续阅读全文

基于veth的网络虚拟化

关于Network Namespace的原理不再详解,请直接移步:Namespaces in operation, part 7: Network namespaces 

但是需要注意的,这个文章里network namespace操作所使用的是最新内核&操作系统提供的非常便利的ip netns工具,不过这些工具在低版本的操作系统上都是不提供的。如果真的需要使用network namespace,最好通过netlink编程的方式来实现,直接基于操作系统调用来完成所有设备的虚拟化工作 我们知道在clone进程的时候使用CLONE_NEWNET参数可以创建一个新的独立的network namespace,但是光有这个还是远远不够的,所有网络设备都没有初始化、没启动,这个时候的容器就是一个完全的离线的容器,不在任何网络里,也访问不了任何网络。 

为了让容器独立能够与外网接通,我们需要创建并初始化一些设备,让容器内的网络和外网互通,veth是一种比较简单的方案

»» 继续阅读全文

Namespaces系列3:network namespace

As the name would imply, network namespaces partition the use of the network—devices, addresses, ports, routes, firewall rules, etc.—into separate boxes, essentially virtualizing the network within a single running kernel instance. Network namespaces entered the kernel in 2.6.24

1. 简介

简单点来说,network namespace主要实现了一套独立的协议栈,为不同的应用程序实现完整的网络隔离

由于有了独立的网络协议栈,应用程序可以灵活自主的组建适合自己的网络架构。network namespace技术本身其实不复杂,复杂的是有了network namespace之后网络的构建,就像给你一堆服务器,交换机,路由器,你需要用网线把这些设备连接起来,并设置路由规则,防火墙规则,网络地址等等,才能实现网络访问

network namespace能解决很多问题,常见的如端口

在多个业务混部在同一个机器上的时候,端口协调是一件非常困难的事情,kubernetes在介绍自身的网络模型中也提到了这一点:

Coordinating ports across multiple developers is very difficult to do at scale and exposes users to cluster-level issues outside of their control. Dynamic port allocation brings a lot of complications to the system - every application has to take

»» 继续阅读全文

Namespaces系列2:mnt namespace

mnt namespaces是实现容器文件系统最核心的基础技术之一,mnt namespaces可以为容器提供一个独立的文件系统视图

这里我除了介绍mnt namespace相关技术之外,还介绍shared subtrees技术,which allows mount and unmount events to be propagated between mount namespaces in an automatic, controlled fashion.

1. 简介

mnt namespaces是linux最早引入的namespace,appearing in 2002 in Linux 2.4.19. 主要是为了隔离不同进程组可以看到的挂载点,meaning that processes in different namespaces see and are able to manipulate different views of the single directory hierarchy.

这里面的隔离有几个意思:

  1. 同一个mnt namespace下的所有进程看到的mount points一定是一样的
  2. 不同的mnt namespace下的进程看到的mount points不一定是一样的
  3. 不同的mnt namespace下所做的mount和umount操作,都是互相不可见的

这个不一定的原因是因为mnt namespace刚创建出来的时候,默认会继承父亲namespace的所有信息,但是如上面第三点说的,之后所做的任何mount & umount操作,都与父namespace无关,也和任何其他的namespace无关

操作系统启动的时候,内核会为系统初始化一个根mnt namespace,也叫"initial namespace". 后面的mnt namespace都是通过clone系统调用 + CLONE_NEWNS参数创建出来的,When a new mount namespace is created, it

»» 继续阅读全文

Namespaces系列1:PID namespace

1. 简介

The global resource isolated by PID namespaces is the process ID number space. This means that processes in different PID namespaces can have the same process ID.

As with processes on a traditional Linux (or UNIX) system, the process IDs within a PID namespace are unique, and are assigned sequentially starting with PID 1. Likewise, as on a traditional Linux system, PID 1—the init process—is special: it is the first process created within the namespace, and it performs certain management tasks within the namespace.

PID隔离最主要的两个目的是:

  1. 为容器提供安全的进程操作
  2. »» 继续阅读全文

pid namespaces销毁触发内核crash

最近在测试pid namespaces的过程中发现一个问题:就是当机器OOM的时候,杀掉了一个有pid namespace的进程,这个进程在回收的过程中,触发了内核crash

内核crash的地方是在回收进程pid的时候踩了空指针,内核版本是2.6.32

所以在低版本内核中,如果pid namespace使用不正确,可能会带来致命的稳定性问题

pid namespace是实现容器的基础技术之一,docker和lxc中都使用了pid namespace来为容器提供独立隔离的进程体系,实现容器之间的PID隔离,但是我看了一下docker和lxc的实现,实现方式很简单,在低版本内核上是极有可能触发这个bug的,我们来了解一下docker和lxc的进程隔离实现方案

关于pid namespace的实现原理,可以参考: Namespaces in operation, part 3: PID namespaces

»» 继续阅读全文