0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

简要介绍了操作系统虚拟化的概念,以及实现操作系统虚拟化的技术

Linux爱好者 2018-01-10 15:00 次阅读

操作系统级虚拟化

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

lrwxrwxrwx1kelvin kelvin012月2616:28cgroup -> cgroup:[4026531835]

lrwxrwxrwx1kelvin kelvin012月2616:28ipc -> ipc:[4026531839]

lrwxrwxrwx1kelvin kelvin012月2616:28mnt -> mnt:[4026531840]

lrwxrwxrwx1kelvin kelvin012月2616:28net -> net:[4026531963]

lrwxrwxrwx1kelvin kelvin012月2616:28pid -> pid:[4026531836]

lrwxrwxrwx1kelvin kelvin012月2616:28user -> user:[4026531837]

lrwxrwxrwx1kelvin kelvin012月2616:28uts -> uts:[4026531838]

下面的代码演示了如何利用上述3个系统调用来操作进程的命名空间:

#define _GNU_SOURCE

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define STACK_SIZE (10 * 1024 * 1024)

charchild_stack[STACK_SIZE];

intchild_main(void* args){

pid_t child_pid = getpid();

printf("I'm child process and my pid is %d \n",child_pid);

// 子进程会被放到clone系统调用新创建的pid命名空间中, 所以其pid应该为1

sleep(300);

// 命名空间中的所有进程退出后该命名空间的inode将会被删除, 为后续操作保留它

return0;

}

intmain(){

/* Clone */

pid_t child_pid = clone(child_main,child_stack + STACK_SIZE,\

CLONE_NEWPID | SIGCHLD,NULL);

if(child_pid < 0){

perror("clone failed");

}

/* Unshare */

intret = unshare(CLONE_NEWPID);// 父进程调用unshare, 创建了一个新的命名空间,

//但不会创建子进程. 之后再创建的子进程将会被加入到新的命名空间中

if(ret < 0){

perror("unshare failed");

}

intfpid = fork();

if(fpid < 0){

perror("fork error");

}elseif(fpid == 0){

printf("I am child process. My pid is %d\n",getpid());

// Fork后的子进程会被加入到unshare创建的命名空间中, 所以pid应该为1

exit(0);

}else{

}

waitpid(fpid,NULL,0);

/* Setns */

charpath[80] = "";

sprintf(path,"/proc/%d/ns/pid",child_pid);

intfd = open(path,O_RDONLY);

if(fd == -1)

perror("open error");

if(setns(fd,0) == -1)

// setns并不会改变当前进程的命名空间, 而是会设置之后创建的子进程的命名空间

perror("setns error");

close(fd);

intnpid = fork();

if(npid < 0){

perror("fork error");

}elseif(npid == 0){

printf("I am child process. My pid is %d\n",getpid());

// 新的子进程会被加入到第一个子进程的pid命名空间中, 所以其pid应该为2

exit(0);

}else{

}

return0;

}

运行结果:

$sudo./ns

I'mchildprocess andmy pid is1

Iam childprocess.My pid is1

Iam childprocess.My pid is2

控制组(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/bash

x=0

while[True];do

done;

2. 在后台执行这个脚本

# bash run.sh &

[1]20553

3. 查看该脚本在哪个CPU上运行

# ps -eLo ruser,lwp,psr,args | grep 20553 | grep -v grep

root 20553 3bash 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.procscpuset.memory_spread_page

cgroup.sane_behaviorcpuset.memory_spread_slab

cpuset.cpu_exclusivecpuset.mems

cpuset.cpus cpuset.sched_load_balance

cpuset.effective_cpus cpuset.sched_relax_domain_level

cpuset.effective_mems docker

cpuset.mem_exclusivetasks

cpuset.mem_hardwall notify_on_release

cpuset.memory_migrate release_agent

cpuset.memory_pressure

5. 创建一个新的组group0

# mkdir group0

# ls group0/

cgroup.clone_childrencpuset.mem_exclusive cpuset.mems

cgroup.procs cpuset.mem_hardwallcpuset.sched_load_balance

cpuset.cpu_exclusive cpuset.memory_migratecpuset.sched_relax_domain_level

cpuset.cpuscpuset.memory_pressure notify_on_release

cpuset.effective_cpuscpuset.memory_spread_pagetasks

cpuset.effective_memscpuset.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 2bash run.sh

上面的例子简单的展示了如何使用控制组。控制组通过文件和目录来操作,文件系统又是树形结构,因此如果不对cgroups的使用做一些限制的话,配置会变得异常复杂和混乱。因此,在新版的cgroups中做了一些限制。

小结

本文简要介绍了操作系统虚拟化的概念,以及实现操作系统虚拟化的技术——命名空间及控制组。并通过两个简单的例子演示了命名空间及控制组的使用方法。
简要介绍了操作系统虚拟化的概念,以及实现操作系统虚拟化的技术

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 虚拟化
    +关注

    关注

    1

    文章

    349

    浏览量

    29557
  • 命名空间
    +关注

    关注

    0

    文章

    3

    浏览量

    1832
  • 控制组
    +关注

    关注

    0

    文章

    1

    浏览量

    1242

原文标题:操作系统级虚拟化概述

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    常见嵌入式操作系统介绍

    常见嵌入式操作系统介绍其实,嵌入式系统并不是一个新生的事物,从八十年代起,国际上就有一些IT组织、公司,开始进行商用嵌入式系统和专用操作系统
    发表于 08-12 00:31

    什么是QNX操作系统

    QNX是一个实时的、可扩充的操作系统;它部分遵循POSIX相关标准,如POSIX.1b 实时扩展;它提供一个很小的微内核以及一些可选的配合进程。其内核仅提供4种服务:进程调度、进程间通信、底层
    发表于 06-07 14:16

    实时操作系统概念

    对很多嵌入式系统来说,一个设计良好的实时操作系统可以让开发工程师把握系统执行任何任务或响应任何关键事件的时间,满足系统实时性要求。为了理解RTOS如何通过
    发表于 07-19 06:18

    Linux上的虚拟技术历史回顾

    虚拟技术的应用十分广泛. 当前虚拟技术主要关注于服务器的
    发表于 07-22 07:18

    虚拟机如何安装linux操作系统

    虚拟机中安装linux操作系统的过程
    发表于 08-01 09:04

    几种主要的虚拟技术有什么不同?

    虚拟技术作为建设绿色数据中心的一项重要技术,一直在不断发展完善,其应用领域包括操作系统、服务器、存储
    发表于 08-14 06:52

    操作系统的重要性如何?

    明白你学习操作系统的目的是什么?操作系统的重要性如何?学习操作系统会给我带来什么?下面我会从这几个方面为你回答下。操作系统也是一种软件,但是操作系统
    发表于 07-23 08:26

    什么是嵌入式操作系统? 

    、INTEGRITY、OSE、C ExecuTIve  什么是嵌入式操作系统 嵌入式操作系统是一种支持嵌入式系统应用的操作系统软件,它是嵌入式系统
    发表于 10-28 07:35

    用于嵌入式系统操作系统

    、设备驱动接口、通信协议、图形界面、标准浏览器等。嵌入式操作系统具有通用操作系统的基本特点,如能够有效管理越来越复杂的系统资源;能够把硬件虚拟
    发表于 10-28 06:30

    嵌入式实时操作系统基本概念

    第1章嵌入式实时操作系统基本概念1.计算机操作系统(Operating System,OS)操作系统的地位:是系统硬件之上的第一层软件,为其
    发表于 10-28 07:51

    掌握Linux操作系统虚拟机定制安装

    、实验内容和原理实验内容:利用虚拟机软件定制安装Linux操作系统,熟悉安装过程中各个选项的意义。实验原理:虚拟机可以说是一种软件,也可以说是一种技术,它允许用户在一台主机上
    发表于 12-16 08:10

    什么是计算机虚拟

    长期从事嵌入式软件研制的单位。 随着虚拟技术发展, 公司决策层决定在公司原有嵌入式实时操作系统基础上, 研制具备虚拟
    发表于 12-21 06:42

    简要分析AArch64的虚拟

    上一篇介绍虚拟和hypervisor的基本概念。为了配合虚拟
    发表于 03-30 10:36

    ARM的虚拟技术是什么?如何去实现

    主流的操作系统都有一个假设,就是这个系统有一个特权模式之下的OS,之上在跑多个非特权模式的APP;而ARM的虚拟技术就是在同一个
    发表于 05-09 09:55

    深入了解AArch64虚拟

    大多数主流操作系统都是基于这样的假设构建的:系统具有单个 运行多个非特权应用程序的特权操作系统。然而,ARM虚拟支持更多功能 而不是一个
    发表于 08-02 12:52