【转】Docker那些事(一)

做者:荣幸html

为何是容器

若是问你如今最热门的服务器端技术什么?想必不少人会不假思索的说是容器!node

容器技术实际上并非一个新鲜的名词,如今你们一提到容器立刻想到的就是Docker,可是容器这个词并非Docker公司发明的,早期的Pass项目如CloudFoundry,其底层就是基于namespace和cgroups的容器技术。linux

Docker在当时其实是个小弟,并无引发你们的注意,可是如今Docker已经成为容器事实上的标准,是什么让Docker发展成如今这样的程度呢?docker

这个功能就是Docker镜像。npm

早期的Pass平台最为人诟病的一个软肋就是应用的打包部署问题,一个应用包在本地部署的好好的,接入Pass平台后却问题重重,而Docker镜像解决了这个根本性问题。json

容器究竟是怎么回事

前面咱们说了容器其实是很早之前就有的技术,主要用到的是Linux的namespace,cgroups和rootfs。bash

咱们常常说沙盒或者集装箱,他们里面装的是货物,那容器这个沙盒装的又是什么呢?是进程!服务器

咱们把进程装进一个沙盒(容器)里面,给他制造边界,和盒子外面的世界隔离,因此咱们会说容器实际上就是加了围墙的一个进程。网络

Namespace

为进程制造边界就须要用到namespace技术,咱们先运行一个docker进程看一下:app

docker run -it busybox /bin/sh 
# -it 是提供一个tty的输入输出环境
# -d  后台运行程序
# -v  挂载外部存储
# -p  端口映射
# -e  参数变量
# busybox 轻量级的容器镜像

咱们执行ps命令,能够看到有趣的现象,PID为1的就是咱们的启动进程。

clipboard.png

而实际上在宿主机中也会同步启动一个进程,其PID在宿主机中是22035。

clipboard.png

这就是PID namespace实现的障眼法,它在Linux进程启动的时候(clone函数),会添加CLONE_NEWPID的参数,进程就会看到一个新的命名空间,因此进程ID就会变成1,实际上进程在宿主机上面仍是22035。

除了PID namespace以外,还有不少的namespace,好比Network、Mount、User等,经过这些namespace对进程进行网络、储存、文件等进行限制,使这个进程看不到宿主机的真实状况,装在了盒子里,这就是容器的核心原理了。

Cgroups

咱们经过 Linux 的命名空间为新建立的进程隔离了文件系统、网络、宿主机器上的其余进程,可是命名空间并不可以为咱们提供物理资源上的隔离,好比 CPU 或者内存。在同一台机器上可能运行着多个对彼此以及宿主机器一无所知的『容器』,但这些容器却共同占用了宿主机器的物理资源。

clipboard.png

若是其中的某一个容器正在执行 CPU 密集型的任务,那么它就会影响其余容器的任务执行效率,致使多个容器相互影响而且抢占资源。如何对多个容器的资源使用进行限制就成了解决进程虚拟资源隔离以后的主要问题,而 Control Group(简称 cgroups)就能隔离宿主机器上的物理资源,例如 CPU、内存、磁盘 I/O 和网络带宽。cgroups介绍、应用实例及原理描述

容器是一个单进程的模型

经过namespace和cgroups的学习咱们知道了容器就是一个启用了多个namespace的应用进程,而这个进程可以使用的资源受到cgroups的限制。这里面有个很重要的概念:容器是一个单进程的模型。

因为容器本质上面是一个进程,即PID=1的进程,他是后续其余进程的父进程,这就意味着在一个容器内,你没有办法同时运行两个应用,除非找到一个公共的PID=1的父进程,并使用像systemd或者supervisor这样的软件替代PID=1的进程来作为容器的启动进程。

可是咱们仍是但愿容器和应用是同生命周期的,由于若是容器是好的,而里面的进程却已经挂了,这样处理起来就会很是麻烦了。

经过上面对容器原理的了解,咱们能不能分析出容器和虚拟机的区别?

  • 虚拟机须要hypervisor层,在上面建立虚拟机是一个完整的OS
  • 容器是Linux上的一个进程
  • 虚拟机的OS资源消耗比容器大的多
  • 容器使用的是宿主机上相同的内核
  • 容器隔离不了时间等资源

镜像

前面说了Docker可以成为容器如今的事实标准,主要是由于Docker创新了镜像这个东西,那么镜像在Linux系统里面是怎么存在的呢?

clipboard.png

咱们Docker的工做目录是/app/docker/docker/ ,其中有个overlay2子目录,它就是咱们的镜像目录。

clipboard.png

咱们在这个目录下有三个目录和一个l的目录,以下:

clipboard.png

咱们能够进入其中一个目录,并查看该目录下diff子目录的内容:

clipboard.png

到这里咱们能够知道,镜像是由多个层组织并定义的,这些层本质上是文件,这些文件是只读的,每层具体的文件存放在层标识符下的diff目录下。

因此咱们在制做镜像的时候就须要理解层的概念,提升镜像制做的效率和重复使用性。

以咱们最常使用的Dockerfile制做镜像举例:

FROM node:8.16.0

RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo "Asia/Shanghai" >> /etc/timezone
RUN date -R

RUN mkdir -p /opt/app/
WORKDIR /opt/app

RUN rm -rf /opt/app/node_modules/
COPY package.json ./

RUN npm install --registry=https://registry.npm.taobao.org

Dockerfile 中的每一条命令在最终生成的镜像中都会产生一层。Docker为了提升镜像分发效率,给镜像赋予了复用层的能力,在拉取,推送,build不一样镜像时,不一样镜像中内容相同的层能够被复用从而节省大量操做。

因此咱们应该尽可能把不变的命令放到 Dockerfile 的上层,这样会显著提升镜像的使用效率。


若是但愿了解更多关于Docker或运维技术的知识,请关注徐徐运维的公众号
clipboard.png

相关文章
相关标签/搜索