容器和虚机都可以运行在Linux操作系统上,他们的不同是虚机是一个靠硬件技术虚拟出来的一个真实的操作系统环境,里面包含了ghost os,而容器只是操作系统上的一个进程,它只是模拟了操作系统的环境,进行自我管理。
在操作系统上安装一个虚机,虚拟机软件本身的运行就占用上百兆内存,它对宿主机的调用受制于虚拟机软件的限制,对操作系统的网络、io、cpu都有很大的浪费。而容器本身只是一个操作系统上的进程,它和其他进程一样,共享操作系统的内核,对资源的浪费可以忽略不计。所以高性能和敏捷性是容器的一个特性。
docker和虚拟机的对比见下图,下图来自docker官网。
docker提供了一个工业级的容器标准,是一个轻量级的、安全的容器应用。
但是没有了虚拟化软件的管理,多个容器运行在一个操作系统上,共用宿主机的ghost os,隔离和限制是一个问题,本文主要讲述docker容器的隔离和限制。docker利用操作系统的namespace做隔离,使用cgroups做资源限制。
1.隔离
Linux的namespace提供了一种资源隔离的手段,将整个操作系统的资源放在不同的namespace空间中,每个namespace空间的进程只能使用自己的资源,这样就实现了隔离的目的。Linuxti提供了的隔离包括:进程(pid)、文件系统挂载点(mount)、UTS(域名和主机名信息)、IPC(进程间通信)、network(网络资源)、user(用户和用户组)
我的专栏《docker安装rabbitmq》中一个例子,在执行docker启动rabbitmq
docker run -d --name rabbitmq3.8.2 -p 5672:5672 -p 15672:15672 -v `pwd`/data:/var/lib/rabbitmq --hostname myRabbit -e RABBITMQ_DEFAULT_VHOST=my_vhost -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin --privileged=true a64a4ae7bc1f
之后进入容器
docker exec -it rabbitmq3.8.2 /bin/sh
执行ps命令,如下图:
可以看到,这个容器中有2个进程,一个是进入容器时的sh进程,宿主机上的其他进程是看不到的。sh这个进程是真实存在于宿主机上的,但是宿主机上pid不是513。容器中的这个进程是在调用宿主机上的clone创建进程时指定的,命令如下,传入一个clone_newpid参数,这样创建的进程就在一个新的namespace中,只能看到当前namespace中的进程。
int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);
2.限制
前面讲过,容器并不能像虚拟机那样完全模拟出一个ghost os,容器中的进程是在操作系统中是真实存在的,这些进程会跟操作系统上的其他进程共享系统的资源,这样肯定会有竞争。Linux的cgroups提供了一种资源限制的手段,它限制进程对操作系统资源的使用,包括cpu、内存、磁盘和网络。
在Linux上执行如下命令,查看cgroup能限制的资源种类。
以CPU资源为例,如下图:
cpu.cfs_period_us和cpu.cfs_quota_us这2个参数,限制进程在cpu.cfs_period_us的时间内,可以有cpu.cfs_quota_us这么长时间的cpu使用权。比如kubepods.slice这个jinc进程,进去查看一下:
可见,CPU的使用并没有做限制。这样当前进程可能把宿主机的CPU跑满,我们可以在cpu.cfs_quota_us文件中写入一个数字,比如20000,这样,当前进程就只能使用20%的CPU时间。而这个限制在容器启动时就可以指定参数值。如下
docker run -itd --cpu-period=100000 --cpu-quota=20000 --name myredis -p 6379:6379 docker.io/redis
这样启动容器后,即使容器中的cup已经打满,也只占操作系统的20%
参数的配置写入操作系统下面的文件:
/sys/fs/cgroup/cpu/system.slice/docker-d37a4c6c5771370db7485f5244a42222cd8c6cdfb416b0399a076886713ec71f.scope目录下的cpu.cfs_period_us和cpu.cfs_quota_us
参考:
https://zhuanlan.zhihu.com/p/73248894
极客时间《深入剖析kubernetes》