前言

Docker是一个开源的软件项目,让用户程序部署在一个相对隔离的环境运行,借此在Linux操作系统上提供一层额外的抽象,以及操作系统层虚拟化的自动管理机制。需要额外指出的是,Docker并不等于容器(containers),Docker只是容器的一种,其他的种类的容器还有Kata container,Rocket container等等。

基本原理

Docker利用Linux中的核心分离机制,例如Cgroups,以及Linux的核心Namespace(名字空间)来创建独立的容器。一句话概括起来Docker就是利用Namespace做资源隔离,用Cgroup做资源限制,利用Union FS做容器文件系统的轻量级虚拟化技术。Docker容器的本质还是一个直接运行在宿主机上面的特殊进程,看到的文件系统是隔离后的,但是操作系统内核是共享宿主机OS,所以说Docker是轻量级的虚拟化技术。

Namespace

Linux Namespace 是Linux 提供的一种内核级别环境隔离的方法,使其中的进程好像拥有独立的操作系统环境。Linux Namespace 有 Mount Namespace,UTS Namespace, IPC Namespace, PID Namespace, Network Namespace, User Namespace, Cgroup Namespace。详情看下表:

分类 系统调用参数 隔离内容 内核版本
Mount Namespace CLONE_NEWNS 文件系统挂载点 Linux 2.4.19(2002年)
UTS Namespace CLONE_NEWUTS Hostname和domain name Linux 2.6.19
IPC Namespace CLONE_NEWIPC 进程间通信方式,例如消息队列 Linux 2.6.19
PID Namespace CLONE_NEWPID 进程ID编号 Linux 2.6.24
Network Namespace, CLONE_NEWNET 网络设备,协议栈,路由表,防火墙规则,端口等 Linux 2.6.24 start Linux 2.6.29 end
User Namespace CLONE_NEWUSER 用户及组ID Linux 2.6.23 start Linux 3.8 end
Cgroup Namespace CLONE_NEWCGROUP Cgroup根目录 Linux 4.6

上述系统调用参数CLONE_NEWNS等主要应用于以下三个系统调用:

  • clone 创建新进程并设置它的Namespace,类似于fork系统调用,可创建新进程并且指定子进程将要执行的函数,通过上述CLONE_NEWNS等参数使某类资源处于隔离状态

函数声明 :

#include <sched.h>

int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...
/* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );

例如:

int pid = clone(call_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);

会让新创建的该进程执行call_function,例如/bin/bash,且该进程的PID进程编号是隔离状态,也就是新的PID编号,该进程ps将会看到它的PID是1。

如果多次执行上述clone就会创建多个PID Namespace,而每个Namespace里面的应用进程都认为自己是当前容器里的1号进程,它们既看不到宿主机里的真实进程空间,也看不到其他PID Namespace里面的具体情况。

  • int unshare(int flags) 使进程脱离某个Namespace,flags参数和clone的用法一致。
  • int setns(int fd, int nstype) 使进程进入某个已经存在的Namespace。经常用于从宿主机进入已经启动的容器Network Namespace,然后设置它的网络。

Cgroup

上面已经讲过Docker 容器运行起来是一个直接运行在宿主机上面的进程,那么如果限定每个容器最多消耗多少CPU资源呢?如果一个容器疯狂的消耗资源岂不是会影响同一宿主机上面其他的容器?所以Docker就需要一个限制容器能够使用资源上限的机制,那就是Linux Cgroup技术。Linux Cgroup 全称是Linux Control Group。它最主要的作用是限制一个进程组能够使用的资源上限,包括CPU,MEM,DISK,NET等等。

下面我将演示一个利用Cgroup限制进程CPU的例子:

[root@nginx- /sys/fs/cgroup/cpu]# ll
total
-rw-r--r-- root root Sep cgroup.clone_children
--w--w--w- root root Sep cgroup.event_control
-rw-r--r-- root root Sep cgroup.procs
-r--r--r-- root root Sep cgroup.sane_behavior
-r--r--r-- root root Sep cpuacct.stat
-rw-r--r-- root root Sep cpuacct.usage
-r--r--r-- root root Sep cpuacct.usage_percpu
-rw-r--r-- root root Sep cpu.cfs_period_us
-rw-r--r-- root root Sep cpu.cfs_quota_us
-rw-r--r-- root root Sep cpu.cfs_relax_thresh_sec
-rw-r--r-- root root Sep cpu.rt_period_us
-rw-r--r-- root root Sep cpu.rt_runtime_us
-rw-r--r-- root root Sep cpu.shares
-r--r--r-- root root Sep cpu.stat
drwxr-xr-x root root Jun : docker
-rw-r--r-- root root Sep notify_on_release
-rw-r--r-- root root Sep release_agent
-rw-r--r-- root root Sep tasks
[root@nginx- /sys/fs/cgroup/cpu]# mkdir mytest #创建mytest目录,系统会自动添加以下文件
[root@nginx- /sys/fs/cgroup/cpu/mytest]# ll
total
-rw-r--r-- root root Jun : cgroup.clone_children
--w--w--w- root root Jun : cgroup.event_control
-rw-r--r-- root root Jun : cgroup.procs
-r--r--r-- root root Jun : cpuacct.stat
-rw-r--r-- root root Jun : cpuacct.usage
-r--r--r-- root root Jun : cpuacct.usage_percpu
-rw-r--r-- root root Jun : cpu.cfs_period_us
-rw-r--r-- root root Jun : cpu.cfs_quota_us
-rw-r--r-- root root Jun : cpu.cfs_relax_thresh_sec
-rw-r--r-- root root Jun : cpu.rt_period_us
-rw-r--r-- root root Jun : cpu.rt_runtime_us
-rw-r--r-- root root Jun : cpu.shares
-r--r--r-- root root Jun : cpu.stat
-rw-r--r-- root root Jun : notify_on_release
-rw-r--r-- root root Jun : tasks
[root@nginx- /sys/fs/cgroup/cpu/mytest]# while : ; do : ; done & # 运行一个死循环命令
[]

top观察会发现该进程CPU跑到了100%,符合预期

主要的限制参数来源自文件cpu.cfs_quota_us,默认是-1,不做限制,如果改成20000说明限定20%的CPU上限。因为总量存在于cpu.cfs_period_us,是100000,意思cpu时间总量是100000us,20000/100000=20%。然后将bash命令的PID写到tasks文件中,改完之后的CPU占用是20%,符合预期:

同理可限制MEM,DISK和NET,需要特殊指出的是MEM是硬限制,当容器的内存使用量超过了Cgroup限定值会被系统OOM。

Union FS

每个容器运行起来后都有一个独立的文件系统,例如Ubuntu镜像的容器能够看到Ubuntu的文件系统,Centos能够看到Centos的文件系统, 不是说容器是运行在宿主机上面的进程吗,为什么能够看到和宿主机不一样的文件系统呢?那就要归功于Union FS,全称是Union File System,联合文件系统。将多个不同位置的目录联合挂载到同一个目录,将相同的部分合并。Docker利用这种联合挂载能力,将容器镜像里面的多层内容呈现为统一的rootfs(根文件系统),即root用户能够看到的根目录底下所有的目录文件。rootfs打包了整个操作系统的文件和目录,是应用运行时所需要的最完整的“依赖库”,也就是我们说的“镜像”。

镜像分为基础镜像只读层,和Init层,和读写层。

Init 层存放的是/etc/hostname,/etc/resolv.conf 等, docker commit的时候不提交。

读写层一开始的时候为空,用户如果修改了文件系统,比如说增删改了文件,docker commit的时候就会提交这一层信息。

Docker VS 虚拟机

从上面这幅图就可以看出,虚拟机是正儿八经的存在一层硬件虚拟层,模拟出了运行一个操作系统需要的各种硬件,例如CPU,MEM,IO等设备。然后在虚拟的硬件上安装了一个新的操作系统Guest OS。所以在Windows宿主机上面可以跑Linux虚拟机。因为多了一层虚拟,所以虚拟机的性能必然会有所损耗。Docker容器是由Docker Deamon(Docker Deamon是运行在宿主机上面的一个后台进程,负责拉起和设置容器)拉起的一个个进程,通过Docker Deamon设置完Namespace和Cgroup之后,本质上就是一个运行在宿主机上面的进程。因为没有一层虚拟的Guest OS,所以Docker轻量级很多。但是有利就有弊,由于Docker 容器直接运行在宿主机上面,安全性就相对较差些,另外也没有办法在Windows上面运行Linux的容器,如果容器里面的应用对特定系统内核有要求也不能运行在不满足要求的宿主机上面。

总结

Docker 容器总结起来就是利用Linux Namespace做资源隔离,Cgroup做资源上限限制,rootfs做文件系统 运行在宿主机上面的一个特殊进程。

Docker基础原理的更多相关文章

  1. 【docker】docker基础原理,核心技术简介

    关于docker的核心技术,就是以下的三大技术: 1.namespaces [命名空间] 使用linux的命名空间实现的进程间隔离.Docker 容器内部的任意进程都对宿主机器的进程一无所知. 除了进 ...

  2. Docker基础修炼2--Docker镜像原理及常用命令

    通过前文的讲解对Docker有了基本认识之后,我们开始进入实战操作,本文先演示Docker三要素之镜像原理和相关命令. 本文的演示环境仍然沿用上一篇文章在本地Centos7中安装的环境,如果你本地没有 ...

  3. 『现学现忘』Docker基础 — 16、Docker中的基本概念和底层原理

    目录 1.Docker的底层原理 2.Docker中常用的基本概念 3.run命令的运行流程 4.为什么Docker比VM快 Docker架构图: 我们依照Docker架构图进行Docker基础概念的 ...

  4. Docker基础技术:Linux Namespace(下)

    在 Docker基础技术:Linux Namespace(上篇)中我们了解了,UTD.IPC.PID.Mount 四个namespace,我们模仿Docker做了一个相当相当山寨的镜像.在这一篇中,主 ...

  5. Docker 基础技术:Linux Namespace(下)

    导读 在Docker基础技术:Linux Namespace(上篇)中我们了解了,UTD.IPC.PID.Mount 四个namespace,我们模仿Docker做了一个相当相当山寨的镜像.在这一篇中 ...

  6. docker基础内容讲解

    一.初识docker 1.1 LXC介绍 LXC为LinuX Container的简写.Linux Container容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提 ...

  7. OpenStack的基础原理

    OpenStack的基础原理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   OpenStack既是一个社区,也是一个项目和一个开源软件,它提供了一个部署云的操作平台或工具集.其 ...

  8. 沉淀,再出发:docker的原理浅析

    沉淀,再出发:docker的原理浅析 一.前言 在我们使用docker的时候,很多情况下我们对于一些概念的理解是停留在名称和用法的地步,如果更进一步理解了docker的本质,我们的技术一定会有质的进步 ...

  9. docker运行原理与使用总结

    docker运行原理概述 Client-Server架构 docker守护进程运行在宿主机上systemctl start docker daemon进程通过socket从客户端(docker命令)接 ...

随机推荐

  1. AC日记——[国家集训队2010]小Z的袜子 cogs 1775

    [国家集训队2010]小Z的袜子 思路: 传说中的莫队算法(优雅的暴力): 莫队算法是一个离线的区间询问算法: 如果我们知道[l,r], 那么,我们就能O(1)的时间求出(l-1,r),(l+1,r) ...

  2. ConstraintLayout 约束布局

    约束布局ConstraintLayout 这种布局方式出现已经有一段时间了,刚出现的时候一直以为这种布局只是针对拖拽使用的布局,最近在新项目里看到了这种布局,又重新学习了这种布局,才发现以前真的是图样 ...

  3. HDU 6227.Rabbits-规律 (2017ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学))

    Rabbits Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total S ...

  4. (5)python tkinter-单选、多选

    单选按钮 tkinter.Radiobutton(root,text='a').pack() tkinter.Radiobutton(root,text='b').pack() tkinter.Rad ...

  5. 洛谷 P1328 生活大爆炸版石头剪刀布【模拟/环/周期】

    题目描述 石头剪刀布是常见的猜拳游戏:石头胜剪刀,剪刀胜布,布胜石头.如果两个人出拳一样,则不分胜负.在<生活大爆炸>第二季第8 集中出现了一种石头剪刀布的升级版游戏. 升级版游戏在传统的 ...

  6. 洛谷 P1372 又是毕业季I[数论/神坑规律题]

    题目描述 为了把毕业晚会办得更好,老师想要挑出默契程度最大的k个人参与毕业晚会彩排.可是如何挑呢?老师列出全班同学的号数1,2,……,n,并且相信k个人的默契程度便是他们的最大公约数(这不是迷信哦~) ...

  7. 笔记-迎难而上之Java基础进阶7

    序列化流 把对象以流的方式写入到文件中保存,叫做对象的序列化 把文件中保存的对象,以流的方式读取出来,叫做对象大反序列化 对象的序列化流_ObjectOutputtream继承自OutputStrea ...

  8. 代码统计利器--CLOC

    MAC下安装命令:$ brew install cloc 其他的linux安装 $ aptitude install cloc 使用方法.到目录下运行: $ cloc . The default ou ...

  9. MATLAB逻辑函数

    %%逻辑函数 %%all:判断是否有元素非0,A是多维矩阵,all(A)是以列为单位来处理的,当前列的逻辑 %值为1,当且仅当当前列的每一个元素都非0 A=[1,2,3;0,2,1;5,0,2]; % ...

  10. fastjson的常用用法以及自定义排序

    fastJson的四种常用方法 JSON 转 POJO public static <T> T getObject(String pojo, Class<T> tclass) ...