Docker 之NameSpace与Cgroup
一、比较docker容器技术与传统虚拟化技术 Docker容器技术是一个与传统的虚拟化技术有些本质上的差别,传统的虚拟化技术,是站硬件物理资源的基础上,虚拟出多个OS,然后在OS的基础上构建相对独立的程序运行环境,而Docker则是在OS的基础上进行虚拟,所以,Docker轻量很多,因此其资源占用、性能消耗相比传统虚拟化都有很大的优势。
docker容器很快,启动和停止可以在秒级实现,比传统的虚拟化技术要快很多,docker核心解决的问题是利用容器来实现类似VM的功能,从而节省更多的硬件资源,docker容器除了运行其中的应用之外,基本不消耗额外的系统资源,从而在保证性能的同时,减小系统开销,同时,它还可以达到“一次封装,到处运行”的目的。
Docker和传统虚拟化的区别如下:
特性 |
Docker容器 |
传统虚拟化技术 |
---|---|---|
启动速度 |
秒级 |
分钟级 |
隔离性 |
资源限制 |
完全隔离 |
性能 |
接近原生 |
弱于 |
计算机能力消耗 |
几乎无 |
损耗50%左右 |
系统支持量(单机) |
上千个 |
几十个 |
Docker和传统虚拟化的架构上的区别比较图如下:
二、NameSpace和Cgroup的概念与作用 Docker中有三个核心概念,分别是镜像、容器、仓库。而镜像的概念主要就是把运行环境和业务代码进行镜像打包,每个镜像都会存在多个“层”,镜像层都是只读的,不能往里写数据,如果想要写,就需要在其基础之上启动成一个容器, 在容器层,我们是可写的。
在镜像的多个“层”中,有一个busybox的概念,我将它理解为欺骗层。 虚拟化的技术就是来解决宿主机与虚拟机之间的耦合问题(简称“解耦”),传统虚拟化是属于完全解耦的,而docker是属于半解耦的。关于“耦合、解耦”的概念可以参考文档:什么是耦合、解耦?
1、NameSpace 那么,Docker技术是如何解耦的呢?这就引入了NameSpace的概念,其目的是将某个特定的全局系统资源通过抽象的方法使得NameSpace中的进程看起来拥有他们自己的隔离的全局系统资源实例,Docker技术通过Linux内核实现了六种NameSpace,如下:
Namespace |
系统调用参数 |
隔离内容 |
---|---|---|
UTS |
CLONE_NEWUTS |
主机名与域名 |
IPC |
CLONE_NEWIPC |
信息量、消息队列和共享内存 |
PID |
CLONE_NEWPID |
进程编号 |
Network |
CLONE_NEWNET |
网络设备、网络栈、端口等等 |
Mount |
CLONE_NEWNS |
挂载点(文件系统) |
User |
CLONE_NEWUSER |
用户和用户组 |
当Docker创建一个容器时,它会创建新的以上六种NameSpace的实例,然后把容器中的所有进程放到这些NameSpace之中,使得容器这个父进程只对自己的子进程有感知,而对于宿主机其他进程一无所知,从而产生一种它就是一个独立的系统的“错觉”。 3、Cgroup Cgroup作用:控制程序对资源的占用。
Cgroup的具体作用如下:
- 限制资源的使用:Cgroup可以对进程组使用的资源总额进行限制;
- 优先级控制:通过分配CPU时间片数量及磁盘IO带宽大小,实际上就是相当于控制子进程运行的优先级。
- 资源统计:Cgroup可以统计系统资源使用量,比如CPU使用时间,内存使用量等。可用于按量计费。
- 进程控制:恢复执行进程;
使用Cgroup,我们可以更具体地控制对系统资源的分配、优先顺序、拒绝、管理和监控。可更好地根据任务和用户分配硬件资源,提高总体的效率,这样可以在docker容器中的服务受到外部干扰时,可以将其限制在容器之中,而不会影响宿主机或其他容器的运行,提高了安全性。
那么,docker是如何来定义容器使用的资源呢? (1)Cgroup的应用举例 1、基于centos镜像运行一个容器,要求CPU使用权重为512。 先来看看其不进行CPU限制时,它是什么样子的? 1)宿主机的CPU限制
[root@docker ~]# cat /sys/fs/cgroup/cpu/cpu.shares # 查看宿主机CPU的权重
1024
2)容器的CPU限制
[root@docker ~]# docker run -it centos
[root@40033df95ce4 /]# cat /sys/fs/cgroup/cpu/cpu.shares
1024 # 可以看到和宿主机是一样的
如果不进行修改CPU的权重,那么容器与宿主机对CPU的权重都是默认的1024,这样是很危险的,因为宿主机与容器对CPU的权重一样,因而导致,它们在对CPU资源出现抢占的情况下,其可使用的CPU资源是1:1,那么,如果在运行这个容器时,对其进行限制呢?若限制容器为512,宿主机还是1024,那么其CPU使用权重的比例就变成了2:1,下面对容器进行限制:
[root@docker ~]# docker run -it --name test1 -c 512 centos
[root@1694de884b3a /]# cat /sys/fs/cgroup/cpu/cpu.shares
512 # 可以看到已经变成了512
2、基于centos镜像运行一个容器,要求MEM为200M,MEM-SWAP为400M 1)以下是宿主机内存、交换空间的限制
[root@docker ~]# cat /sys/fs/cgroup/memory/memory.limit_in_bytes # 查看内存的限制
9223372036854771712
[root@docker ~]# cat /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes # 查看交换空间的限制
9223372036854771712
2)以下是容器中对内存、交换空间的限制
[root@docker ~]# docker run -it centos
[root@692e78a5fedf /]# cat /sys/fs/cgroup/memory/memory.limit_in_bytes # 内存限制
9223372036854771712
[root@692e78a5fedf /]# cat /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes # 交换空间限制
9223372036854771712 #单位是“bytes”
可以看到容器对内存和交换空间可以使用的量和宿主机是一样的,说明并没有进行限制,那么如何进行限制呢?
[root@docker ~]# docker run -it --name test2 -m 200M --memory-swap 400M centos
# 启动一个容器限制内存为300M,交换空间为400M
[root@bfc999f40acf /]# cat /sys/fs/cgroup/memory/memory.limit_in_bytes
209715200 # 查看确认,单位为bytes
[root@bfc999f40acf /]# cat /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes
419430400 # 查看确认,单位为bytes
3、基于centos镜像运行一个容器,要求写入速度为40M。 默认运行一个容器,不进行限制:
[root@bfc999f40acf /]# time dd if=/dev/zero of=a.txt bs=1M count=200 oflag=direct
200+0 records in
200+0 records out
209715200 bytes (210 MB, 200 MiB) copied, 0.203469 s, 1.0 GB/s # 结果为每秒写入468MB。
real 0m0.206s
user 0m0.001s
sys 0m0.167s
可以看到,如果不对其进行限制,那么会使用宿主机最大的写速度,那么怎么限制呢?
[root@docker ~]# docker run -it --name test3 --device-write-bps /dev/sda:40MB centos
[root@a3cd9813e2e6 /]# time dd if=/dev/zero of=a.txt bs=1M count=200 oflag=direct
200+0 records in
200+0 records out
209715200 bytes (210 MB, 200 MiB) copied, 4.91592 s, 42.7 MB/s # 写入速度被限制在了40MB左右
real 0m4.918s
user 0m0.000s
sys 0m0.155s
- MySQL Online DDL(二)(r11笔记第88天)
- 转-Android上面运行golang
- Golang适合高并发场景的原因分析
- 浅谈MySQL中的事务隔离级别(r11笔记第86天)
- 巧用echo命令解决Samba批量添加用户难题
- 分分钟搭建MySQL Group Replication测试环境(r11笔记第82天)
- MySQL 5.7 Group Replication错误总结(r11笔记第84天)
- 空结构体struct{}解析
- 动态创建MySQL Group Replication的节点(r11笔记第84天)
- sysbench压测小记(r11笔记第99天)
- WordPress启用memcached动态缓存以及报错解决
- 升级CentOS6.5内核,开启Nginx的fastopen和reuseport特性
- Nginx网站使用CDN之后禁止用户真实IP访问的方法
- 相差数十倍的SQL性能分析(r11笔记第98天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 手把手教你搭建SSM框架(Eclipse版)
- 【手把手教你】使用pyfinance进行证券收益分析
- [English] Creating a New Theme
- 脏读,不可重复读,幻读
- 建议收藏!这份MySQL 连接查询超全详解送给你
- Redis点赞新思路 bitmap
- PyQt5 技术篇-调用字体对话框(QFontDialog)获取字体,控件设置字体。
- deepin使用
- 解决deepin下安装sqlite3依赖过新的问题
- PyQt5 技术篇-调用文件对话框获取文件、文件夹路径。文件对话框返回选中的多个文件路径
- deepin安装golang
- PyQt5 技术篇-调用输入对话框(QInputDialog)获取用户输入内容。
- Python+selenium 自动化-通过窗口名切换窗口,如何获取当前窗口的title窗口名
- deepin 任务栏消失问题
- PyQt5 技术篇-调用消息对话框(QMessageBox)进行简单提示!