1 前言

上图是百度的虚拟机和Docker容器的对比图,看着好像都差不多。那么虚拟机技术都这么成熟了,为什么Docker会火起来呢,Docker对比虚拟机等传统技术有什么优势?Docker又是通过什么方式来实现容器的一致性呢?这篇文章我们就通过探究Docker的核心原理,来侧面回答这个疑问。

2 docker容器技术

Docker的核心技术包含以下几点:

• Linux namespace

• Linux cgroup

• rootfs

• 镜像分层

下面我会依次介绍这些技术的原理。

注:本篇基于linux的docker来阐述。其他操作系统的docker容器实现原理不尽相同,各位可回想一下在win10下安装docker时,是不是要求必须启动hyper-V服务了?这个是win10自带的虚拟化服务,也就是说docker在win10下采用了虚拟化技术,并且借助创建MobyLinuxVM虚拟机来实现win10下的容器化

2.1 隔离:Namespace

这里我们先观察一下已经搭建好的集群容器的情况:

# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE
business-manager-666f454f7f-bg2bt 1/1 Running 0 27s 172.30.76.4 192.168.0.21
business-manager-666f454f7f-kvn5z 1/1 Running 0 27s 172.30.76.5 192.168.0.21
business-manager-666f454f7f-ncjp7 1/1 Running 0 27s 172.30.9.4 192.168.0.22
data-product-6664c6dcb9-7sxnz 1/1 Running 0 7m17s 172.30.76.2 192.168.0.21
data-product-6664c6dcb9-j2f48 1/1 Running 0 7m17s 172.30.76.3 192.168.0.21
data-product-6664c6dcb9-p5xkw 1/1 Running 0 7m17s 172.30.9.3 192.168.0.22

上图可知,我们有两个Pod跑在192.168.0.22这台宿主机上,pod里实际跑的正是我们打包的docker容器。我们在宿主机上执行docker ps,就可以看到上述两个容器(k8s还将DNS等其他模块的部分组件调度在这台机上,所以docker ps显示的容器不止2个):

# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
e411e063c652 reg.miz.so/aura/business-manager "/bin/sh -c 'nohup .…" 31 minutes ago Up 31 minutes
e081a599315c kubernetes/pause "/pause" 31 minutes ago Up 31 minutes
e07627a10c38 reg.miz.so/jo-demo/data-product "/bin/sh -c 'echo 19…" 37 minutes ago Up 37 minutes
6ff85402a1da kubernetes/pause "/pause" 38 minutes ago Up 38 minutes
1c92cc7a7f44 ist0ne/exechealthz-amd64 "/exechealthz '--cmd…" 3 hours ago Up 3 hours
937128a888f2 ist0ne/dnsmasq-metrics-amd64 "/dnsmasq-metrics --…" 3 hours ago Up 3 hours
4e926555a6f2 kubernetes/pause "/pause" 3 hours ago Up 3 hours

接下来我们进入其他一个容器执行ps,查看容器里都有些什么进程:

# kubectl exec -ti business-manager-666f454f7f-ncjp7 sh
$ ps -efj
UID PID PPID PGID SID C STIME TTY TIME CMD
root 1 0 1 1 0 14:47 ? 00:00:03 ./business-manager -conf /business-manager/config/config.json
root 22 0 22 22 0 15:25 pts/0 00:00:00 sh
root 28 22 28 22 0 15:29 pts/0 00:00:00 ps -efj

进入business-manager这个应用的容器内部,ps查看所有的进程,pid=1的是我们的应用程序,pid=22和28的分别是我们这一步操作执行的sh程序和ps程序。了解linux系统的同学应该知道,pid=1的不是内核的init进程吗(不一定非得是这个进程,但内核总得维护一个“1号”进程,它的作用是作为父进程来启动其他的进程,并且接收那些被应用“遗弃”的孤儿进程)?

那么init进程哪去了呢?

其实上面显示的1号进程,是docker容器的障眼法,这个business-manager进程就是跑在宿主机上的一个特殊的进程,我们查看下宿主机的真实进程情况:

# ps -efj|grep business-manager
root 38156 38138 38156 38156 0 14:47 ? 00:00:03 ./business-manager -conf /business-manager/config/config.json
root 47393 3471 47392 3471 0 15:34 pts/2 00:00:00 grep --color=auto business-manager

上面这个pid=33156的才是宿主机上对应business-manager容器的真实进程。

容器(指容器里的应用),是linux系统里的一个特殊进程,docker通过linux namespace技术对应用进程进行了隔离,使的应用只能看到指定的有限的系统信息,这就使应用“以为”自己在一个独立的操作系统环境下。

Linux namespace,跟K8S、C++的namespace的功能是类似的,目的都是将一组资源限定在一个有限的可见范围内。Linux namespace支持以下几项资源隔离:

名称 宏定义 隔离内容
Cgroup CLONE_NEWCGROUP 资源限制Cgroup root directory (since Linux 4.6)
IPC CLONE_NEWIPC IPC资源System V IPC, POSIX message queues (since Linux 2.6.19)
Network CLONE_NEWNET 网络Network devices, stacks, ports, etc. (since Linux 2.6.24)
Mount CLONE_NEWNS 文件系统Mount points (since Linux 2.4.19)
PID CLONE_NEWPID 进程号Process IDs (since Linux 2.6.24)
User CLONE_NEWUSER 用户User and group IDs (started in Linux 2.6.23 and completed in Linux 3.8)
UTS CLONE_NEWUTS 主机名Hostname and NIS domain name (since Linux 2.6.19)

这些隔离属性,基本涵盖了一个小型操作系统的运行要素,包含主机名、网络、文件系统等。

要使用上述namespace很容易,在调用内核api clone()函数创建新的进程时,加上上述参数即可。这正是Docker在创建容器(现在大家知道了,就是创建我们的应用程序进程)时所要做的事情。

2.2 限制:Cgroup

Linux的Cgroup机制,是Docker利用的又一大利器。上一节我们知道,容器其实就是宿主机里的一个被框进来的进程,它不能看到外面,但它与宿主机上其他的进程共享了内核资源,所以接下来我们需要对它所能使用的资源作限制,这就是Cgroup机制所提供的。

Cgroup的使用,比较简单粗暴,它利用一组目录和文件的组合,来实现配置和控制。这些目录和文件在/sys/fs/cgroup目录下:

# cd /sys/fs/cgroup/
# ls
blkio cpu cpuacct cpu,cpuacct cpuset devices freezer hugetlb memory net_cls net_cls,net_prio net_prio perf_event pids systemd

上述文件夹各自对一些资源进行控制。要使用cgroup很简单,在对应目录下创建一个新的文件夹,cgroup会自动为我们生成相关的一些配置文件:

# cd cpu
# mkdir JoTest
# cd JoTest/
# ls
cgroup.clone_children cgroup.procs cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.event_control cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks

我们可以修改period和quota文件,配置进程能够占用的CPU百分比,然后将需要应用这组限制的进程的ID写入tasks文件,即可完成cpu的限制。

2.3 rootfs

Namespace对应用进行了隔离,而cgroup则完成了资源的分配和限制,现在一个针对应用程序的沙盒已经成型。接下来就是考虑开篇提到的一致性问题了?一致性主要是为了解决应用跑在不同的宿主机上不受宿主机环境的差异影响的问题。容器技术出来之前,手动或脚本迁移应用的时候,往往会遇到新的宿主机缺少某个关键组件、或是某些依赖版本差异甚至是操作系统内核差异等因素导致的不一致问题。现在我们来看看docker是怎么解决这个问题的。

对于单个应用程序进程来说,对环境的依赖,关键体现在对操作系统所提供的文件系统的依赖,所以docker所要做的就是通过以下3步给你一套想要的文件系统:

• 通过mount namespace(2.1章节)将应用的文件系统隔离开

• 将应用所需要的文件系统(比如centos:7的所有文件)拷贝到某个目录D下

• 调用chroot将应用的根目录调整为目录D(mount namespace的隔离作用在这里体现出来了,chroot只对在当前namespace下的应用生效,应用在这个“根目录”下可以随便折腾,而不会影响到真实的宿主机根目录。)

上面这3步所构造出来的文件系统,我们称之为rootfs(根文件系统)。应用程序执行“cd /"指令进入的根目录,将被限定在上述目录D下。下面我们简单验证一下这个rootfs。

这里我们在容器的根目录新建一个文件jo1,然后在宿主机上查找这个文件,定位到如下位置:

# cd /var/lib/docker/overlay2/b2231f9f15050ae8d609726d308c2ead60114df3fc5404a24c688d805d4a9883/merged/
# ls
anaconda-post.log bin business-manager data dev etc home jo1 lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var

可以看到,上面这个文件夹正是我们的容器所在的“根目录”。

我们也可以用mount指令查看当前宿主机的挂载情况,限于篇幅,这里就不展开解析mount了,下面是mount的输出节选:

# mount|grep overlay2
overlay on /var/lib/docker/overlay2/be512d9faf97c7d860fa16ecc4ecd5057e12feffc8b0804115923f0795bb9f75/merged type overlay (rw,relatime,seclabel,lowerdir=/var/lib/docker/overlay2/l/ZSXN3J4UXRRBMRG3F3RNUZGWUB:/var/lib/docker/overlay2/l/2CCAOTBFIGCYNR73TQEE333CO6:/var/lib/docker/overlay2/l/6Y5GTV75CBUR4WORCMOHYJZQ7Y:/var/lib/docker/overlay2/l/VWENHOE7X3WDA4NK5P7DTTPSIX,upperdir=/var/lib/docker/overlay2/be512d9faf97c7d860fa16ecc4ecd5057e12feffc8b0804115923f0795bb9f75/diff,workdir=/var/lib/docker/overlay2/be512d9faf97c7d860fa16ecc4ecd5057e12feffc8b0804115923f0795bb9f75/work)
overlay on /var/lib/docker/overlay2/8a7546027e2e354bf0bba12600fdb6ac87c199d09589ba90952f28aed74d13b6/merged type overlay (rw,relatime,seclabel,lowerdir=/var/lib/docker/overlay2/l/KOZRXUFTWITQUNAKOZMWSYWTSH:/var/lib/docker/overlay2/l/2CCAOTBFIGCYNR73TQEE333CO6:/var/lib/docker/overlay2/l/6Y5GTV75CBUR4WORCMOHYJZQ7Y:/var/lib/docker/overlay2/l/VWENHOE7X3WDA4NK5P7DTTPSIX,upperdir=/var/lib/docker/overlay2/8a7546027e2e354bf0bba12600fdb6ac87c199d09589ba90952f28aed74d13b6/diff,workdir=/var/lib/docker/overlay2/8a7546027e2e354bf0bba12600fdb6ac87c199d09589ba90952f28aed74d13b6/work)
...

2.4 镜像分层

上面3个章节已经可以实现一个基本的容器了。接下来的问题是,我们这么多应用的docker镜像如果全部都包含了整个操作系统的文件,势必给镜像的传播下载带来不便,所以docker为我们实现了镜像分层来解决镜像大小问题。

FROM reg.miz.so/library/centos:7
MAINTAINER "maizuo <aura@hyx.com>"
RUN rm /etc/localtime && \
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
WORKDIR /business-manager
ADD ./build/main /business-manager/business-manager
ADD ./build/resource /business-manager/resource
RUN mkdir /data && cd /data && mkdir logs

查看上面这个典型的dockerfile文件,其中FROM字段表示我们当前打包的镜像是基于reg.miz.so/library/centos:7来创建的,dockerfile文件里每条指令均会创建一个新的镜像层,这些层合在一起就是一个完整的镜像。

镜像分层的应用,简单的举个例子,比如我们的business-manager和data-product都是基于reg.miz.so/library/centos:7这个镜像建立的,那么我们第一次下载data-product镜像时,需要把reg.miz.so/library/centos:7也下载下来,但当我们再次下载其他的镜像比如business-manager,已经存在的镜像层如reg.miz.so/library/centos:7镜像则无需重复下载,只需要下载增量部分即可,所以多个应用如果基于同样的基础层创建,除第1次外,后面的镜像下载往往只需要下几十M的应用程序即可,这就很大程度上解决了镜像大小的问题。

不同的容器镜像共用相同的层,那么容器如果修改了底层的文件,会不会影响到其他容器呢?答案是不会,docker在这里运用了copy-on-write的手法,限于篇幅,也不展开说了。我们需要记住的是,基于同样的底层镜像创建的新镜像,可以共用相同的镜像层,所以无论是下载还是硬盘存储,都不会太大。(这就是为什么有时候删除一个docker镜像,磁盘空间基本没啥变化)

3 docker容器与虚拟机的对比

有了前面的原理分析,接下来我们可以解答开篇的疑问了:

特性或原理 Docker Container 虚拟机
核心原理 进程隔离,共享操作系统内核 硬件虚拟化,在宿主操作系统上再跑一个操作系统
如何保证一致性 镜像(rootfs) 安装一个相同的操作系统
启动速度 秒级-进程级启动 分钟级-系统级启动
硬盘使用 MB-镜像分层的优势 GB
性能 几乎无损耗 有损耗
单机支持量 单机支持上千个容器 一般几十个

当然,docker也存在一些弊端,主要是隔离性不足以及隔离不足所带来的安全风险。虚拟机基于硬件虚拟化,每个虚拟机上都运行着独立的系统内核,可以保证与宿主机和其他虚拟机有强隔离,跑在虚拟机内的应用可以随便折腾而无需担心影响到“邻居”。而docker所依赖的namespace提供的是有限的隔离,典型的是系统时间没有被隔离,容器内修改系统时间会直接体现在宿主机上;所以开发过程中,当我们的应用需要修改内核参数时,务必谨慎,明确自己在干啥。

Docker容器技术的核心原理的更多相关文章

  1. Docker容器技术的核心

    容器技术的核心 所谓容器,其实是由Linux Namespace.Linux Cgroups和rootfs三种技术构建出来的进程的隔离环境 对于Docker项目来说,其实最核心就是为待创建的用户进程: ...

  2. 微服务架构:基于微服务和Docker容器技术的PaaS云平台架构设计(微服务架构实施原理)

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 基于微服务架构和Docker容器技术的PaaS云平台建设目标是给我们的开发人员提供一套服务快速开发.部署.运维管理.持续开发持续集成的流程 ...

  3. k8s 核心功能 - 每天5分钟玩转 Docker 容器技术(116)

    本节带领大家快速体验 k8s 的核心功能:应用部署.访问.Scale Up/Down 以及滚动更新. 部署应用 执行命令: kubectl run kubernetes-bootcamp \ --im ...

  4. Service IP 原理 - 每天5分钟玩转 Docker 容器技术(137)

    Service Cluster IP 是一个虚拟 IP,是由 Kubernetes 节点上的 iptables 规则管理的. 可以通过 iptables-save 命令打印出当前节点的 iptable ...

  5. Docker容器技术的PaaS云平台架构设计***

    基于微服务架构和Docker容器技术的PaaS云平台建设目标是给我们的开发人员提供一套服务快速开发.部署.运维管理.持续开发持续集成的流程.平台提供基础设施.中间件.数据服务.云服务器等资源,开发人员 ...

  6. Prometheus 到底 NB 在哪里?- 每天5分钟玩转 Docker 容器技术(84)

    本节讨论 Prometheus 的核心,多维数据模型.我们先来看一个例子. 比如要监控容器 webapp1 的内存使用情况,最传统和典型的方法是定义一个指标 container_memory_usag ...

  7. 如何快速部署 Prometheus?- 每天5分钟玩转 Docker 容器技术(85)

    上一节介绍了 Prometheus 的核心,多维数据模型.本节演示如何快速搭建 Prometheus 监控系统. 环境说明 我们将通过 Prometheus 监控两台 Docker Host:192. ...

  8. 神奇的 routing mesh - 每天5分钟玩转 Docker 容器技术(100)

    接上一节案例,当我们访问任何节点的 8080 端口时,swarm 内部的 load balancer 会将请求转发给 web_server 其中的一个副本. 这就是 routing mesh 的作用. ...

  9. 学习 Kubernetes 的 Why 和 How - 每天5分钟玩转 Docker 容器技术(114)

    这是一个系统学习 Kubernetes 的教程,有下面两个特点: 系统讲解当前最流行的容器编排引擎 Kubernetes包括了安装部署.应用管理.网络.存储.监控.日志管理等多各个方面. 重实践并兼顾 ...

随机推荐

  1. shell 发送Post请求,并获取状态码

    #!/bin/bash aa=$ result=$(curl -H "Content-type: application/json" -X POST -o /dev/null -s ...

  2. 配置本地和远程maven仓库

    <mirrors><mirror> <id>alimaven</id> <name>aliyun maven</name> &l ...

  3. Azkaban2.5安装部署(系统时区设置 + 安装和配置mysql + Azkaban Web Server 安装 + Azkaban Executor Server安装 + Azkaban web server插件安装 + Azkaban Executor Server 插件安装)(博主推荐)(五)

    Azkaban是什么?(一) Azkaban的功能特点(二) Azkaban的架构(三) Hadoop工作流引擎之Azkaban与Oozie对比(四) 不多说,直接上干货! http://www.cn ...

  4. tyvj P4879骰子游戏-美国70分

    需要FFT优化... #include<iostream> #include<cstdio> #include<queue> #include<vector& ...

  5. (wp8.1)样式资源

    在开发wp的时候,难免要设置好多属性.但是有好多属性是重复的,我们可不可统一 设置样式呢,答案是肯定的 代码如下 <Page x:Class="Blue.MainPage" ...

  6. log4j.properties配置详情

    log4j: log for java 是Apache的一个开源项目! 00.将我们的日志信息,输出到指定的位置(控制台   文件中) 01.我们可以控制每一条日志的输出格式 02.我们设置日志信息的 ...

  7. 1043 方格取数 2000年NOIP全国联赛提高组

    1043 方格取数 2000年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond         题目描述 Description 设有N* ...

  8. Mind must be master of the body, strong mind can separate the body from its suffering.

    Mind must be master of the body, strong mind can separate the body from its suffering.意志是身体的主人,有顽强的意 ...

  9. 在jquery事件中修改Angular的model

    HTML代码如下 <!DOCTYPE html> <html ng-app="qm"> <body> <input type=" ...

  10. (三)我的JavaScript系列:不同调用方式的this指向

    人生自是有情痴,此恨不关风与月 今天所写的内容,是对之前的内容的总结和扩展.老实说,对于自己之前的一些杜撰和臆测,我并不是很满意.所以这篇博文,我希望能来点干货. 不同调用方式的this指向 在Jav ...