操作系统级虚拟化概述
2019独角兽企业重金招聘Python工程师标准>>>
操作系统级虚拟化
KVM、XEN等虚拟化技术允许各个虚拟机拥有自己独立的操作系统。与KVM、XEN等虚拟化技术不同,所谓操作系统级虚拟化,也被称作容器化,是操作系统自身的一个特性,它允许多个相互隔离的用户空间实例的存在。这些用户空间实例也被称作为容器。普通的进程可以看到计算机的所有资源而容器中的进程只能看到分配给该容器的资源。通俗来讲,操作系统级虚拟化将操作系统所管理的计算机资源,包括进程、文件、设备、网络等分组,然后交给不同的容器使用。容器中运行的进程只能看到分配给该容器的资源。从而达到隔离与虚拟化的目的。
实现操作系统虚拟化需要用到Namespace及cgroups技术。
命名空间(Namespace)
在编程语言中,引入命名空间的概念是为了重用变量名或者服务例程名。在不同的命名空间中使用同一个变量名而不会产生冲突。Linux系统引入命名空间也有类似的作用。例如,在没有操作系统级虚拟化的Linux系统中,用户态进程从1开始编号(PID)。引入操作系统虚拟化之后,不同容器有着不同的PID命名空间,每个容器中的进程都可以从1开始编号而不产生冲突。
目前,Linux中的命名空间有6种类型,分别对应操作系统管理的6种资源:
- 挂载点(mount point) CLONE_NEWNS
- 进程(pid) CLONE_NEWPID
- 网络(net) CLONE_NEWNET
- 进程间通信(ipc) CLONE_NEWIPC
- 主机名(uts) CLONE_NEWUTS
- 用户(uid) CLONW_NEWUSER
将来还会引入时间、设备等对应的namespace.
Linux 2.4.19版本引入了第一个命名空间——挂载点,因为那时还没有其他类型的命名空间,所以clone系统调用中引入的flag就叫做CLONE_NEWNS
与命名空间相关的三个系统调用(system calls)
下面3个系统调用用来操作命名空间:
- clone() —— 用来创建新的进程及新的命名空间,新的进程会被放到新的命名空间中
- unshare() —— 创建新的命名空间但并不创建新的子进程,之后创建的子进程会被放到新创建的命名空间中去
- setns() —— 将进程加入到已经存在的命名空间中
注意:这3个系统调用都不会改变调用进程(calling process)的pid命名空间,而是会影响其子进程的pid命名空间
命名空间本身并没用名字(囧),不同的命名空间用不同的inode号来标识,这也符合Linux用文件一统天下的惯例。可以在proc文件系统中查看一个进程所属的命名空间,例如,查看PID为4123的进程所属的命名空间:
kelvin@desktop:~$ ls -l /proc/4123/ns/
总用量 0
lrwxrwxrwx 1 kelvin kelvin 0 12月 26 16:28 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 kelvin kelvin 0 12月 26 16:28 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 kelvin kelvin 0 12月 26 16:28 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 kelvin kelvin 0 12月 26 16:28 net -> net:[4026531963]
lrwxrwxrwx 1 kelvin kelvin 0 12月 26 16:28 pid -> pid:[4026531836]
lrwxrwxrwx 1 kelvin kelvin 0 12月 26 16:28 user -> user:[4026531837]
lrwxrwxrwx 1 kelvin kelvin 0 12月 26 16:28 uts -> uts:[4026531838]
下面的代码演示了如何利用上述3个系统调用来操作进程的命名空间:
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#define STACK_SIZE (10 * 1024 * 1024)char child_stack[STACK_SIZE];int child_main(void* args) {pid_t child_pid = getpid();printf("I'm child process and my pid is %d \n", child_pid);// 子进程会被放到clone系统调用新创建的pid命名空间中, 所以其pid应该为1sleep(300);// 命名空间中的所有进程退出后该命名空间的inode将会被删除, 为后续操作保留它return 0;
}int main() {/* Clone */pid_t child_pid = clone(child_main, child_stack + STACK_SIZE, \CLONE_NEWPID | SIGCHLD, NULL);if(child_pid < 0) {perror("clone failed");}/* Unshare */int ret = unshare(CLONE_NEWPID); // 父进程调用unshare, 创建了一个新的命名空间,//但不会创建子进程. 之后再创建的子进程将会被加入到新的命名空间中if (ret < 0) {perror("unshare failed");}int fpid = fork();if (fpid < 0) {perror("fork error");} else if (fpid == 0) {printf("I am child process. My pid is %d \n", getpid());// Fork后的子进程会被加入到unshare创建的命名空间中, 所以pid应该为1exit(0);} else {}waitpid(fpid, NULL, 0);/* Setns */char path[80] = "";sprintf(path, "/proc/%d/ns/pid", child_pid);int fd = open(path, O_RDONLY);if (fd == -1)perror("open error");if (setns(fd, 0) == -1)// setns并不会改变当前进程的命名空间, 而是会设置之后创建的子进程的命名空间perror("setns error");close(fd);int npid = fork();if (npid < 0) {perror("fork error");} else if (npid == 0) {printf("I am child process. My pid is %d \n", getpid());// 新的子进程会被加入到第一个子进程的pid命名空间中, 所以其pid应该为2exit(0);} else {}return 0;
}
运行结果:
$ sudo ./ns
I'm child process and my pid is 1
I am child process. My pid is 1
I am child process. My pid is 2
控制组(Cgroups)
如果说命名空间是从命名和编号的角度进行隔离,而控制组则是将进程进行分组,并真正的将各组进程的计算资源进行限制、隔离。控制组是一种内核机制,它可以对进程进行分组、跟踪限制其使用的计算资源。对于每一类计算资源,控制组通过所谓的子系统(subsystem)来进行控制,现阶段已有的子系统包括:
cpusets: 用来分配一组CPU给指定的cgroup,该cgroup中的进程只等被调度到该组CPU上去执行
blkio : 限制cgroup的块IO
cpuacct : 用来统计cgroup中的CPU使用
devices : 用来黑白名单的方式控制cgroup可以创建和使用的设备节点
freezer : 用来挂起指定的cgroup,或者唤醒挂起的cgroup
hugetlb : 用来限制cgroup中hugetlb的使用
memory : 用来跟踪限制内存及交换分区的使用
net_cls : 用来根据发送端的cgroup来标记数据包,流量控制器(traffic controller)会根据这些标记来分配优先级
net_prio : 用来设置cgroup的网络通信优先级
cpu :用来设置cgroup中CPU的调度参数
perf_event : 用来监控cgroup的CPU性能
与命名空间不同,控制组并没有增加系统调用,而是实现了一个文件系统,通过文件及目录操作来管理控制组。下面通过一个例子来看一看cgroup是如何利用cpuset子系统来把进程绑定到指定的CPU上去执行的。
1. 创建一个一直执行的shell脚本
#!/bin/bashx=0while [ True ];do:
done;
2. 在后台执行这个脚本
# bash run.sh &
[1] 20553
3. 查看该脚本在哪个CPU上运行
# ps -eLo ruser,lwp,psr,args | grep 20553 | grep -v grep
root 20553 3 bash run.sh
可以看到PID为20553的进程运行在编号为3的CPU上,下面利用cgroups将其绑定到编号为2的CPU上去执行
4. 挂载cgroups类型的文件系统到一个新创建的目录cgroups中
# mkdir cgroups
# mount -t cgroup -o cpuset cgroups ./cgroups/
# ls cgroups/
cgroup.clone_children cpuset.memory_pressure_enabled
cgroup.procs cpuset.memory_spread_page
cgroup.sane_behavior cpuset.memory_spread_slab
cpuset.cpu_exclusive cpuset.mems
cpuset.cpus cpuset.sched_load_balance
cpuset.effective_cpus cpuset.sched_relax_domain_level
cpuset.effective_mems docker
cpuset.mem_exclusive tasks
cpuset.mem_hardwall notify_on_release
cpuset.memory_migrate release_agent
cpuset.memory_pressure
5. 创建一个新的组group0
# mkdir group0
# ls group0/
cgroup.clone_children cpuset.mem_exclusive cpuset.mems
cgroup.procs cpuset.mem_hardwall cpuset.sched_load_balance
cpuset.cpu_exclusive cpuset.memory_migrate cpuset.sched_relax_domain_level
cpuset.cpus cpuset.memory_pressure notify_on_release
cpuset.effective_cpus cpuset.memory_spread_page tasks
cpuset.effective_mems cpuset.memory_spread_slab
6. 将上面的进程20553加入到新建的控制组中:
# echo 20553 >> group0/tasks
# cat group0/tasks
20553
7. 限制该组的进程只能运行在编号为2的CPU上
# echo 2 > group0/cpuset.cpus
# cat group0/cpuset.cpus
2
8. 查看PID为20553的进程所运行的CPU编号
# ps -eLo ruser,lwp,psr,args | grep 20553 | grep -v grep
root 20553 2 bash run.sh
上面的例子简单的展示了如何使用控制组。控制组通过文件和目录来操作,文件系统又是树形结构,因此如果不对cgroups的使用做一些限制的话,配置会变得异常复杂和混乱。因此,在新版的cgroups中做了一些限制。
小结
本文简要介绍了操作系统虚拟化的概念,以及实现操作系统虚拟化的技术——命名空间及控制组。并通过两个简单的例子演示了命名空间及控制组的使用方法。
阅读原文
转载于:https://my.oschina.net/kelvinxupt/blog/1602990
操作系统级虚拟化概述相关推荐
- 全虚拟化半虚拟化硬件辅助搜索虚拟化操作系统级虚拟化
全虚拟化(FullVirtulization) 简介:主要是在客户操作系统和硬件之间捕捉和处理那些对虚拟化敏感的特权指令,使客户操作系统无需修改就能运行,速度会根据不同的实现而不同,但大致能满足用户的 ...
- 裸金属服务器能虚拟化吗,裸金属服务器虚拟化概述
裸金属服务器虚拟化概述 内容精选 换一换 华为云帮助中心,为用户提供产品简介.价格说明.购买指南.用户指南.API参考.最佳实践.常见问题.视频帮助等技术文档,帮助您快速上手使用华为云服务. SAP ...
- 虚拟化概述及VMware VSphere介绍
虚拟化概述及VMware VSphere介绍: 虚拟化打破了物理硬件与操作系统及在其上运行的应用程序之间的硬性连接.操作系统和应用程序在虚拟机中实现虚拟化之后,便不再因位于单台物理计算机中而受到种种束 ...
- 云计算与虚拟化概述-你不得不知的云计算与虚拟化基础知识
本文主要灵感来自老男孩架构师班-赵班长实战讲解KVM,以及speedy Cloud云公司CEO董伟(董总)云计算与虚拟化讲座,综合整理而来.--为表示感谢--特整理此文分享给大家. 1.1云计算概述 ...
- 《VMware、Citrix和Microsoft虚拟化技术详解与应用实践》一1.1 虚拟化概述
1.1 虚拟化概述 在了解虚拟化之前,你可能会提出以下一些问题: 什么是虚拟化? 为什么我们需要虚拟化? 虚拟化技术有哪些? 虚拟化的历史由来是怎样的? 怎么才能实现虚拟化技术? 1.1.1 虚拟化的 ...
- 解读三种虚拟化之路连载一:x86虚拟化概述
从1998年开始,VMware创造性的将虚拟化引入x86平台,通过二进制翻译(BT)和直接执行的模式,让x86芯片可以同时运行不同的几种操作系统,并且确保性能.稳定性和安全性. 从那时起,数以万计的企 ...
- 《Linux KVM虚拟化架构实战指南》——第1章 KVM虚拟化概述 1.1XEN虚拟化介绍
本节书摘来自异步社区<Linux KVM虚拟化架构实战指南>一书中的第1章,第1.1节,作者:何坤源著,更多章节内容可以访问云栖社区"异步社区"公众号查看 第1章 KV ...
- 北京大学公开课:操作系统与虚拟化安全 学习与研究
一.公开课地址 https://www.coursera.org/course/osvirtsecurity 二.课程介绍 从操作系统与虚拟化平台面临的安全问题和应该采取的安全机制入手,帮助你学习和掌 ...
- 云计算----虚拟化概述、CPU虚拟化、内存虚拟化、IO虚拟化、aSV虚拟化、aSAN等技术原理
1.虚拟化概述 (1)虚拟化的几个概念 Guest OS:运行在虚拟机之上的操作系统 Guest Machine:虚拟出来的虚拟机 Hypervisor (Virtual Machine Monito ...
最新文章
- Win10 下 RabbitMQ 的 安装 配置
- Python使用matplotlib函数subplot可视化多个不同颜色的折线图、为多个子图添加总标题(main title)
- android stadio 快捷键最好的材料 android stadio大全 最牛逼的android stadio快捷键
- ddt python_python-ddt实践
- VS2010不能编译.Net3.5项目的解决方法
- Python编程基础05:运算符与表达式
- terminal mysql 停止_转载MySQL之终端(Terminal)管理MySQL
- linux内核I2C体系结构(注意结构体原型)
- 【拾贝】hive unoin all map数爆增
- NIPS论文遭受全面质疑:论证过程普遍不完整,又何谈对错?
- JavaScript高级编程
- linux实现定时任务
- 当前版本与卡刷包android_安卓SuperSU卡刷包 V2.82 SR5 安卓版下载 - win10专业版官网 - win10系统之家...
- python知识图谱智能问答_机器人之基于知识图谱的智能问答机器人
- 费马大定理与费马小定理
- steam++工具箱
- 学校计算机报损报废申请表,学校财产登记报损上报制度
- Linux命令·traceroute
- java调用微信支付流程
- 如何做一个基于微信酒店预订小程序系统毕业设计毕设作品
热门文章
- RDCL报表的两种使用方法/为DataSet添加两个Table_AX
- opencv 图像雾检测_OpenCV图像处理-基于OpenPose的关键点检测
- python变量作用域图解_python的变量作用域问题
- JavaScript设计模式学习——builder pattern(建造者模式)
- 大道至简——失败也是积累
- 剑指offer第41题 和为s的两个数
- ViewPager嵌套ViewPager 滑动冲突
- VIM入门必读(转)
- 平面电子地图如何表现同一位置的POI
- FCTH(Fuzzy Color and Texture Histogram)算法