1-Docker - 基础篇

什么是容器

容器与虚拟化的区别

容器是一种虚拟化的方案,也可以说是虚拟化技术的一种,它与传统的虚拟机不同。传统的虚拟机,是通过中间层,将一台或多台独立的机器虚拟虚拟运行在物理硬件之上,而容器是直接运行在操作系统内核之上的用户空间,也因此容器虚拟化也被称为操作系统虚拟化。

由于容器依赖于操作系统的特性,所以容器只能运行在底层操作系统相同或者相似内核的操作系统中。

而docker技术则依赖于Linux内核NamespaceCgroup(Control Group)特性。所以,docker只能运行于Linux类型的系统,而不能运行在Windows系统(现在应该是能了)。这也因此导致了容器技术相对于虚拟机技术在系统维护性上存在劣势。

see also:namespace Cgroup

容器技术的优点

图片来源

使用虚拟机部署应用,不但要包含应用和依赖的库,还需要包含完整的操作系统来支持。可能一个几兆的应用却需要几个G的操作系统,非常占用空间。

而容器只需要包含应用本身和依赖的库即可。

除此之外,虚拟机需要模拟硬件的行为,对内核CPU的损耗也非常大。所以,同样配置的服务器,使用容器技术的性能更高。

但因为容器技术本身相对复杂,难以管理和维护,也不容易自动化,所以.......直到docker的出现。

什么是docker

docker能够将开发的应用程序自动部署到容器的开源引擎,它使用go语言开发,在2013年初由dotCloud(现docker公司)基于Apache 2.0开源授权协议发布。

docker的特别之处在于在虚拟化的容器执行环境中,增加一个应用程序部署引擎,该引擎的目标是提供一个轻量、快速的环境,能够运行程序,并方便的将程序从开发环境部署到测试环境再到生产环境。

docker的特点

  • docker提供简单轻量的建模方式:
    • docker非常容易上手,我们只需要几分钟就能把应用程序docker化,并且大多数的docker容器只需要不到一秒就能运行起来。
    • 由于去除了管理程序的开销,docker容器拥有非常高的性能,同时同一台宿主机中能够运行更多的容器,充分的发挥系统的资源。
  • 职责划分清晰:
    • 使用docker,开发人员只需要关心容器中运行的开发程序,运维人员只需要关心如何管理容器。
    • docker设计的目的,就是加强开发环境与部署环境的一致性。
  • 快速高效的开发生命周期:
    • docker的目标之一就是缩短从开发、测试、部署到上线部署的时间。
    • 让程序具有可移植性。
    • 在容器中开发,以容器的形式交付和分发;这样,开发、测试、生产的环境都是一致的。
  • 鼓励使用面向服务的架构:
    • docker推荐单个容器只运行一个程序或者进程,这样就形成了分布式的应用程序模型,在该模型下,应用程序或服务都可以表示为一系列内部互联的容器。

docker的使用场景

  • 使用docker容器开发、测试、部署服务。
  • 创建隔离的运行环境。
  • 搭建测试环境。
  • 构建多用户的平台即(PassS)基础设施。
  • 提供软件及服务(SaaS)应用程序。
  • 高性能、超大规模的宿主机部署。

docker的基本组成

docker主要由以下几个组成部分:

  • Docker Client客户端
  • Docker Daemon守护进程
  • docker Image镜像
  • Docker Container容器
  • Docker Registry仓库

Docker Client/Daemon

Docker是C/S架构的程序。

Docker的客户端向Docker服务端(Docker守护进程)发送命令请求,守护进程处理完所有的操作,将结果返回给客户端。

Docker客户端对服务端的访问即可以是本地,也可以是远程访问。

Docker Image

Docker镜像是容器的基石。

容器基于镜像启动、运行;镜像保存了容器启动的各种条件。

往深了说,Docker镜像是层叠的只读文件系统

它的最低端是引导文件系统(bootfs)(类似于Linux的引导文件系统),Docker用户一般不和引导文件系统打交道。其实,当一个容器启动后,它将会移动到内存中,而引导文件系统将被卸载。

Docker镜像的第二层是root文件系统(rootfs(Ubuntu)),root文件系统位于引导文件系统之上,root文件系统可以是一种或者多种操作系统,如Ubuntu或者CentOS。

在传统的Linux引导中,root文件系统会最先以只读的方式加载,当引导结束并完成了完整性校验后才会切换为读写模式; 而Docker中,root文件系统永远是只读状态,并且Docker利用联合加载(union mount)技术,在root文件系统之上,加载更多的只读文件系统。

联合加载指的是一次同时加载多个文件系统,而外部只能看到一个文件系统;联合加载会将各层文件系统以"栈"的形式叠加起来,这样最终的文件系统会包含所有的底层文件系统和目录,Docker将这样的文件系统称之为————镜像。

一个镜像可以放到另一个镜像的顶部,位于底部的镜像称为父镜像,以此类推,直到镜像"栈"的底部,"栈"底部的镜像称为基础镜像,如上图中的root文件系统。

Docker Container

Docker容器通过镜像启动,容器是镜像的执行单元,容器中可以运行用户的一个或者多个进程。

如果说镜像是Docker生命周期中的构建和打包阶段,那么容器则是启动和执行阶段。

容器是如何通过镜像启动的呢?

当一个容器启动时,Docker会在该镜像的最顶层加载一个读写文件系统,即读(可)写文件层;我们在Docker中运行的程序,就是在可写层中执行的。

当Docker第一次启动一个容器时,初始的读写层是空的,当文件系统发生变化时,这些变化都会应用在这一层上,比如,如果想修改一个文件,这个文件首先会从该读写层下面的只读层复制到该读写层。由此,该文件的只读版本依然存在于只读层,只是被读写层的该文件副本所隐藏。该机制则被称之为————写时复制(Copy on write)。

每个只读镜像层都是只读的,并且永远不会改变。

当创建一个新容器时,Docker会构建一个镜像"栈",在栈的最顶层添加可写层,这个可写层加上下面的镜像层及配置数据,就构成了一个容器。

容器的这种特点加上镜像分层框架使我们可以快速的构建镜像,并运行包含应用和服务的容器。

Docker Registry

Docker用仓库来保存用户构建的镜像。

仓库分为共有和私有两种,Docker公司提供了公有仓库————Docker Hub,我们可以在Docker Hub上进行注册,然后保存和分享自己的镜像,也因此Docker Hub现在有了很多共有的镜像供我们使用,减少了很多构建镜像的时间。

当然,我们也可以搭建自己的私有仓库。

最后,我们再来总结一下Docker的基本组成:

我们通过客户端来访问Docker的守护进程,从而操作Docker的容器,而容器是通过镜像创建的,而镜像又保存在仓库中。

Docker容器和Namespace/Cgroups

在本文开头,我们说了Docker技术则依赖于Linux内核的两个重要特性:

  • Namespace命名空间
  • Control groups(cgroups)控制组

Namespace

很多编程语言都包含了命名空间的概念,编程语言级别的命名空间可以理解为封装,而封装本身则实现的是代码隔离。

在操作系统中,命名空间提供的是系统资源隔离,包括进程、网络、文件系统等等。

而Linux内核实现命名空间的主要目的之一,就是实现轻量级的虚拟化服务,也就是容器,在同一个命名空间中的进程,可以感知彼此的变化,而无法感知到其他命名空间中的进程,这样,对于容器中的进程来说,它处于一个独立的系统环境中,依次达到隔离的目的。

从Docker公开的文档来看,它使用了5种命名空间:

  • PID(Process ID) 进程隔离
  • NET(Network) 管理网络接口
  • IPC(InterProcess Communication) 管理跨进程通信的访问
  • MNT(Mount) 管理挂载点
  • UTS(Unit Timesharing System) 隔离内核和版本标识

那这些隔离的资源是如何管理起来的呢?这就用到了Control groups控制组了。

Control groups(cgroups)

Control groups是Linux内核提供的限制、记录、隔离进程组所使用的物理资源的机制。

最初由Google工程师提出,然后于2007年被Linux kernel2.6.24版本整合进来。毫不夸张的说,Control groups就是为了实现容器而生的。

那Control groups提供了哪些功能呢?

首先是资源限制,如memory子系统可以为进程组设置一个内存使用上线,一旦内存达到上线,当进程组再申请内存时,就会抛出一个out of memory的消息提示。

其次是优先级设定,它可以设定哪些进程组使用更多的CPU和磁盘资源。

第三,实现了资源计量,它可以计算进程组使用了多少系统资源;这一点在计费系统中显得尤为重要。

第四,实现了资源控制,它可以将进程组挂起/恢复。

Namespace和Cgroups为Docker赋予了哪些能力呢?

首先是文件系统的隔离,每个容器都有自己的root文件系统。

其次是进程隔离,每个容器都运行在自己的进程环境中。

第三是网络隔离,容器间的虚拟网络接口和IP地址都是分开的。

第四是资源隔离和分组,Cgroups将CPU和内存之类的资源独立分配给每个Docker容器。


that's all
posted @ 2020-03-26 17:41  听雨危楼  阅读(562)  评论(0编辑  收藏  举报