Docker概述

2022/03/01 Docker

Docker概述

Docker是一个被广泛使用的开源容器引擎,是一种操作系统级别的虚拟化技术,它以一种特殊进程的方式运行于宿主机上,它依赖于liunx内核特性:namespace(名字空间进行资源的隔离)和cgroups(限制、记录任务组所使用的物理资源),它也可以对应用程序进行打包。

什么是Docker

Docker是基于Go语言实现的开源容器项目。它诞生于2013年年初,最初发起者是dotCloud公司。Docker自开源后受到业界广泛的关注和参与,目前已有80多个相关开源组件项目(包括Containerd、Moby、Swarm等),逐渐形成了围绕Docker容器的完整的生态体系。 dotCloud公司也随之快速发展壮大,在2013年年底直接改名为Docker Inc,并专注于Docker相关技术和产品的开发,目前已经成为全球最大的Docker容器服务提供商。官方网站为docker.com。 Docker项目已加入Linux基金会,并遵循Apache 2.0协议,全部开源代码均在https://github.com/docker项目仓库进行维护。在Linux基金会最近一次关于“最受欢迎的云计算开源项目”的调查中,Docker仅次于2010年发起的OpenStack项目,并仍处于上升趋势。2014年,Docker镜像下载数达到了一百万次,2015年直接突破十亿次,2017年更是突破了惊人的百亿次。 现在主流的操作系统包括Linux各大发行版、macOS、Windows等都已经支持Docker。例如,Redhat RHEL 6.5/CentOS 6.5、Ubuntu 16.04以及更新的版本,都已经在官方软件源中默认带有Docker软件包。此外,各大云服务提供商也纷纷推出了基于Docker的服务。 Google公司在其Platform as a Service(PaaS)平台及服务中广泛应用了Docker容器;IBM公司与Docker公司达成了战略合作伙伴关系,进行云业务上的深入技术合作;Microsoft公司在其Azure云平台上支持安全可扩展的Docker集群方案;公有云提供商Amazon在其AWS云平台上集成了对Docker的支持,提供高性能快速的部署。 Docker的构想是要实现“Build,Ship and Run Any App,Anywhere”,即通过对应用的封装(Packaging)、分发(Distribution)、部署(Deployment)、运行(Runtime)生命周期进行管理,达到应用组件级别的“一次封装,到处运行”。这里的应用组件,既可以是一个Web应用、一个编译环境,也可以是一套数据库平台服务,甚至是一个操作系统或集群。 基于Linux平台上的多项开源技术,Docker提供了高效、敏捷和轻量级的容器方案,并支持部署到本地环境和多种主流云平台。可以说,Docker首次为应用的开发、运行和部署提供了“一站式”的实用解决方案。

Docker是什么?

  • docker是一个开源的软件部署解决方案;
  • docker也是轻量级的应用容器框架;
  • docker可以打包、发布、运行任何的应用。

Docker 是使用最广泛的开源容器引擎,它彻底释放了计算虚拟化的威力,极大提高了应用的运行效率,降低了云计算资源供应的成本! 使用 Docker,可以让应用的部署、测试和分发都变得前所未有的高效和轻松!

Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。

Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。

Linux容器技术——巨人的肩膀

与大部分新兴技术的诞生一样,Docker也并非“从石头缝里蹦出来的”,而是站在前人的肩膀上。其中最重要的就是Linux容器(Linux Containers,LXC)技术。IBM DeveloperWorks网站关于容器技术的描述十分准确:“容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。与虚拟化相比,这样既不需要指令级模拟,也不需要即时编译。容器可以在核心CPU本地运行指令,而不需要任何专门的解释机制。此外,也避免了准虚拟化(para-virtualization)和系统调用替换中的复杂性。” 当然,LXC也经历了长期的演化。最早的容器技术可以追溯到1982年Unix系列操作系统上的chroot工具(直到今天,主流的Unix、Linux操作系统仍然支持和带有该工具)。早期的容器实现技术包括Sun Solaris操作系统上的Solaris Containers(2004年发布),FreeBSD操作系统上的FreeBSD jail(2000年左右发布),以及GNU/Linux上的Linux-VServer(http://linux-vserver.org,2001年10月)和OpenVZ(http://openvz.org,2005年)。 在LXC之前,这些相关技术经过多年的演化已经十分成熟和稳定,但是由于种种原因,它们并没有被很好地集成到主流的Linux内核中,使用起来并不方便。例如,如果用户要使用OpenVZ技术,需要先手动给操作系统打上特定的内核补丁方可使用,而且不同版本并不一致。类似的困难造成在很长一段时间内这些优秀的技术只在技术人员的小圈子中交流。 后来LXC项目借鉴了前人成熟的容器设计理念,并基于一系列新引入的内核特性,实现了更具扩展性的虚拟化容器方案。更加关键的是,LXC终于被集成到到主流Linux内核中,进而成为Linux系统轻量级容器技术的事实标准。从技术层面来看,LXC已经趟过了绝大部分的“坑”,完成了容器技术实用化的大半历程。

Docker是如何产生的

Docker最初诞生于dotCloud公司,这是一家于2010年成立的,专注于PAAS(Platform as a Service)平台的创业型公司。PAAS概念可以说是SAAS概念的升级版,而且直接面向广大程序员,旨在减少软件开发周期中最烦琐、最耗时的环境准备环节。所以这个概念一经推出,就立刻得到了程序员的热捧。

但在2010年的时候,市面上已经有一些科技巨头进入了PAAS这个领域,比如IBM、Amazon、Google、VMWare和微软。这些巨头纷纷推出了自己的产品,比如Amazon的EC2、google的GAE、VMWare的Cloud Foundry、IBM的Blue Mix以及微软的Azure。所以在2010年的时候,dotCloud的日子并不是很好过,它虽然拿到了1000万美元的风投,但仍然举步维艰。在经过深思熟虑之后,dotCloud创始人Solomon Hykes提议,将他们的核心虚拟化产品Docker开源。

山穷水尽疑无路,柳暗花明又一村。

Docker一经开源,马上得到业界程序员的热烈吹捧。这个基于Linux Container技术的虚拟化产品大大降低了容器技术的使用门槛,程序员所希望的免费、轻量级、可移植、虚拟化和与语言无关、封装后的镜像可以随处部署和迁移等各种苛刻的要求,在Docker上面都一一得到了满足。

哇!开发界,测试界和生产环境三界统一了!

Docker得到了极大的关注度,大有席卷市场的意思。这时,各大科技巨头也马上改变策略,先后宣布将在各自的云平台中支持Docker,就连微软都宣布一定会在Windows环境中原生支持Docker。

至此,Docker在市场上站稳了脚跟。而dotCloud公司也顺势在2014年8月卖给了德国的cloudControl公司,Solomon Hykes等人也全职开始维护Docker开源社区,为广大使用Docker的公司提供技术支持。

从Linux容器到Docker

在LXC的基础上,Docker进一步优化了容器的使用体验,让它进入寻常百姓家。首先,Docker提供了各种容器管理工具(如分发、版本、移植等),让用户无须关注底层的操作,更加简单明了地管理和使用容器;其次,Docker通过引入分层文件系统构建和高效的镜像机制,降低了迁移难度,极大地改善了用户体验。用户操作Docker容器就像操作应用自身一样简单。 早期的Docker代码实现是直接基于LXC的。自0.9版本开始,Docker开发了libcon-tainer项目作为更广泛的容器驱动实现,从而替换掉了LXC的实现。目前,Docker还积极推动成立了runC标准项目,并贡献给开放容器联盟,试图让容器的支持不再局限于Linux操作系统,而是更安全、更开放、更具扩展性。 简单地讲,读者可以将Docker容器理解为一种轻量级的沙盒(sandbox)。每个容器内运行着一个应用,不同的容器相互隔离,容器之间也可以通过网络互相通信。容器的创建和停止十分快速,几乎跟创建和终止原生应用一致;另外,容器自身对系统资源的额外需求也十分有限,远远低于传统虚拟机。很多时候,甚至直接把容器当作应用本身也没有任何问题。

为什么要使用Docker

Docker项目的发起人、Docker公司CTO Solomon Hykes认为,Docker在正确的地点、正确的时间顺应了正确的趋势——如何正确地构建应用。 在云时代,开发者创建的应用必须要能很方便地在网络上传播,也就是说应用必须脱离底层物理硬件的限制;同时必须是“任何时间任何地点”可获取的。因此,开发者们需要一种新型的创建分布式应用程序的方式,快速分发和部署,而这正是Docker所能够提供的最大优势。 举个简单的例子,假设用户试图基于最常见的LAMP(Linux+Apache+MySQL+PHP)组合来构建网站。按照传统的做法,首先需要安装Apache、MySQL和PHP以及它们各自运行所依赖的环境;之后分别对它们进行配置(包括创建合适的用户、配置参数等);经过大量的操作后,还需要进行功能测试,看是否工作正常;如果不正常,则进行调试追踪,意味着更多的时间代价和不可控的风险。可以想象,如果应用数目变多,事情会变得更加难以处理。 更为可怕的是,一旦需要服务器迁移(例如从亚马逊云迁移到其他云),往往需要对每个应用都进行重新部署和调试。这些琐碎而无趣的“体力活”,极大地降低了用户的工作效率。究其根源,是这些应用直接运行在底层操作系统上,无法保证同一份应用在不同的环境中行为一致。 而Docker提供了一种更为聪明的方式,通过容器来打包应用、解耦应用和运行平台。这意味着迁移的时候,只需要在新的服务器上启动需要的容器就可以了,无论新旧服务器是否是同一类型的平台。这无疑将帮助我们节约大量的宝贵时间,并降低部署过程出现问题的风险。 对开发和运维(DevOps)人员来说,最梦寐以求的效果可能就是一次创建或配置,之后可以在任意地方、任意时间让应用正常运行,而Docker恰恰是可以实现这一终极目标的“瑞士军刀”。具体说来,在开发和运维过程中,Docker具有如下几个方面的优势: 更快速的交付和部署。使用Docker,开发人员可以使用镜像来快速构建一套标准的开发环境;开发完成之后,测试和运维人员可以直接使用完全相同的环境来部署代码。只要是开发测试过的代码,就可以确保在生产环境无缝运行。Docker可以快速创建和删除容器,实现快速迭代,节约开发、测试、部署的大量时间。并且,整个过程全程可见,使团队更容易理解应用的创建和工作过程。 更高效的资源利用。运行Docker容器不需要额外的虚拟化管理程序(Virtual Machine Manager,VMM,以及Hypervisor)的支持,Docker是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。与传统虚拟机方式相比,Docker的性能要提高1~2个数量级。 更轻松的迁移和扩展。Docker容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等,同时支持主流的操作系统发行版本。这种兼容性让用户可以在不同平台之间轻松地迁移应用。 更简单的更新管理。使用Dockerfile,只需要小小的配置修改,就可以替代以往大量的更新工作。所有修改都以增量的方式被分发和更新,从而实现自动化并且高效的容器管理。

  • 更高效的利用系统资源 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。
  • 更快速的启动时间 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。
  • 一致的运行环境 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性。
  • 持续交付和部署 使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。一次创建或配置,可以在任意地方正常运行。
  • 更轻松的迁移 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。

Docker与虚拟机比较

作为一种轻量级的虚拟化方式,Docker在运行应用上跟传统的虚拟机方式相比具有如下显著优势: Docker容器很快,启动和停止可以在秒级实现,这相比传统的虚拟机方式(数分钟)要快得多; Docker容器对系统资源需求很少,一台主机上可以同时运行数千个Docker容器(在IBM服务器上已经实现了同时运行10K量级的容器实例); Docker通过类似Git设计理念的操作来方便用户获取、分发和更新应用镜像,存储复用,增量更新; Docker通过Dockerfile支持灵活的自动化创建和部署机制,以提高工作效率,并标准化流程。 Docker容器除了运行其中的应用外,基本不消耗额外的系统资源,在保证应用性能的同时,尽量减小系统开销。传统虚拟机方式运行N个不同的应用就要启用N个虚拟机(每个虚拟机需要单独分配独占的内存、磁盘等资源),而Docker只需要启动N个隔离得“很薄的”容器,并将应用放进容器内即可。应用获得的是接近原生的运行性能。 当然,在隔离性方面,传统的虚拟机方式提供的是相对封闭的隔离。但这并不意味着Docker不安全。Docker利用Linux系统上的多种防护技术实现了严格的隔离可靠性,并且可以整合众多安全工具。从1.3.0版本开始,Docker重点改善了容器的安全控制和镜像的安全机制,极大地提高了使用Docker的安全性。在已知的大规模应用中,目前尚未出现值得担忧的安全隐患。

Docker与虚拟化

虚拟化(virtualization)技术是一个通用的概念,在不同领域有不同的理解。在计算领域,一般指的是计算虚拟化(computing virtualization),或通常说的服务器虚拟化。维基百科上的定义如下: “在计算机技术中,虚拟化是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体结构间的不可切割的障碍,使用户可以用比原本的组态更好的方式来应用这些资源。” 可见,虚拟化的核心是对资源的抽象,目标往往是为了在同一个主机上同时运行多个系统或应用,从而提高系统资源的利用率,并且带来降低成本、方便管理和容错容灾等好处。

从大类上分,虚拟化技术可分为基于硬件的虚拟化和基于软件的虚拟化。其中,真正意义上的基于硬件的虚拟化技术不多见,少数如网卡中的单根多IO虚拟化(Single Root I/O Virtualization and Sharing Specification,SR-IOV)等技术,也超出了本书的讨论范畴。 基于软件的虚拟化从对象所在的层次,又可以分为应用虚拟化和平台虚拟化(通常说的虚拟机技术即属于这个范畴)。前者一般指的是一些模拟设备或诸如Wine这样的软件,后者又可以细分为几个子类: 完全虚拟化。虚拟机模拟完整的底层硬件环境和特权指令的执行过程,客户操作系统无须进行修改。例如IBM p和z系列的虚拟化、VMware Workstation、VirtualBox、QEMU等; 硬件辅助虚拟化。利用硬件(主要是CPU)辅助支持(目前x86体系结构上可用的硬件辅助虚拟化技术包括Intel-VT和AMD-V)处理敏感指令来实现完全虚拟化的功能,客户操作系统无须修改,例如VMware Workstation,Xen,KVM; 部分虚拟化。只针对部分硬件资源进行虚拟化,客户操作系统需要进行修改。现在有些虚拟化技术的早期版本仅支持部分虚拟化; 超虚拟化(paravirtualization)。部分硬件接口以软件的形式提供给客户机操作系统,客户操作系统需要进行修改,例如早期的Xen; 操作系统级虚拟化。内核通过创建多个虚拟的操作系统实例(内核和库)来隔离不同的进程。容器相关技术即在这个范畴。 可见,Docker以及其他容器技术都属于操作系统虚拟化这个范畴,操作系统虚拟化最大的特点就是不需要额外的supervisor支持。Docker虚拟化方式之所以有众多优势,跟操作系统虚拟化技术自身的设计和实现是分不开的。

Docker核心概念

Docker的三大核心概念:镜像(Image) 容器(Container) 仓库(Repository) 只有理解了这三个核心概念,才能顺利地理解Docker容器的整个生命周期。

镜像(Images)

Docker镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。镜像是创建Docker容器的基础。 Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。 Docker 设计时,充分利用 Union FS 的技术,将其设计为分层存储的架构,Docker 镜像由多层文件系统联合组成。镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。

容器(Container)

Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用。容器是从镜像创建的应用运行实例。它可以启动、开始、停止、删除,而这些容器都是彼此相互隔离、互不可见的。 可以把容器看作一个简易版的Linux系统环境(包括root用户权限、进程空间、用户空间和网络空间等)以及运行在其中的应用程序打包而成的盒子。 镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。 容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。 每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。 按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。 数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器可以随意删除、重新 run ,数据却不会丢失。

镜像仓库(Registry)

Docker仓库类似于代码仓库,是Docker集中存放镜像文件的场所。 镜像仓库是一个集中的存储、分发镜像的服务。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。 通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。 最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像。用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。

Docker常用概念

概念 说明
Docker 镜像(Images) Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。
Docker 容器(Container) 容器是独立运行的一个或一组应用,是镜像运行时的实体。
Docker 客户端(Client) Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。
Docker 主机(Host) 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。
Docker Registry Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
Docker Machine Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。

Docker安装

Docker引擎是使用Docker容器的核心组件,可以在主流的操作系统和云平台上使用,包括Linux操作系统(如Ubuntu、Debian、CentOS、Redhat等),macOS和Windows操作系统,以及IBM、亚马逊、微软等知名云平台。

用户可以访问Docker官网的Get Docker (https://www.docker.com/get-docker)页面,查看获取Docker的方式,以及Docker支持的平台类型。

目前Docker支持Docker引擎、Docker Hub、Docker Cloud等多种服务。

  • Docker引擎:包括支持在桌面系统或云平台安装Docker,以及为企业提供简单安全弹性的容器集群编排和管理;
  • DockerHub:官方提供的云托管服务,可以提供公有或私有的镜像仓库;
  • DockerCloud:官方提供的容器云服务,可以完成容器的部署与管理,可以完整地支持容器化项目,还有CI、CD功能。 Docker引擎目前分为两个版本:社区版本(Community Edition,CE)和企业版本(Enterprise Edition,EE)。社区版本包括大部分的核心功能,企业版本则通过付费形式提供认证支持、镜像管理、容器托管、安全扫描等高级服务。通常情况下,用户使用社区版本可以满足大部分需求;若有更苛刻的需求,可以购买企业版本服务。社区版本每个月会发布一次尝鲜(Edge)版本,每个季度(3、6、9、12月)会发行一次稳定(Stable)版本。版本号命名格式为“年份.月份”,如2018年6月发布的版本号为v18.06。

CentOS7 安装步骤

CentOS 安装参考官方文档:https://docs.docker.com/install/linux/docker-ce/centos/

  • 卸载旧版本
    # yum remove docker docker-common docker-selinux
    
  • 安装依赖包
    # yum install -y yum-utils device-mapper-persistent-data lvm2
    
  • 安装 Docker 软件包源
    # yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    
  • 安装 Docker CE
    # yum install docker-ce
    
  • 启动 Docker 服务
    # systemctl start docker
    
  • 设置开机启动
    # systemctl enable docker
    
  • 验证安装是否成功
    # docker -v
    # docker info
    

Docker 命令

通过 –help 参数可以看到 docker 提供了哪些命令,可以看到 docker 的用法是 docker [选项] 命令 。

命令有两种形式,Management Commands 是子命令形式,每个命令下还有子命令;Commands 是直接命令,相当于子命令的简化形式。

[root@localhost usr]# docker --help

Usage:  docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Options:
      --config string      Location of client config files (default "/root/.docker")
  -c, --context string     Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with "docker context use")
  -D, --debug              Enable debug mode
  -H, --host list          Daemon socket(s) to connect to
  -l, --log-level string   Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
      --tls                Use TLS; implied by --tlsverify
      --tlscacert string   Trust certs signed only by this CA (default "/root/.docker/ca.pem")
      --tlscert string     Path to TLS certificate file (default "/root/.docker/cert.pem")
      --tlskey string      Path to TLS key file (default "/root/.docker/key.pem")
      --tlsverify          Use TLS and verify the remote
  -v, --version            Print version information and quit

Management Commands:
  app*        Docker App (Docker Inc., v0.9.1-beta3)
  builder     Manage builds
  buildx*     Docker Buildx (Docker Inc., v0.8.0-docker)
  config      Manage Docker configs
  container   Manage containers
  context     Manage contexts
  image       Manage images
  manifest    Manage Docker image manifests and manifest lists
  network     Manage networks
  node        Manage Swarm nodes
  plugin      Manage plugins
  scan*       Docker Scan (Docker Inc., v0.17.0)
  secret      Manage Docker secrets
  service     Manage services
  stack       Manage Docker stacks
  swarm       Manage Swarm
  system      Manage Docker
  trust       Manage trust on Docker images
  volume      Manage volumes

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  build       Build an image from a Dockerfile
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  events      Get real time events from the server
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  history     Show the history of an image
  images      List images
  import      Import the contents from a tarball to create a filesystem image
  info        Display system-wide information
  inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  login       Log in to a Docker registry
  logout      Log out from a Docker registry
  logs        Fetch the logs of a container
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  ps          List containers
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  run         Run a command in a new container
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  search      Search the Docker Hub for images
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  version     Show the Docker version information
  wait        Block until one or more containers stop, then print their exit codes

Run 'docker COMMAND --help' for more information on a command.

To get more help with docker, check out our guides at https://docs.docker.com/go/guides/

继续查看 Management Commands 有哪些子命令,例如查看 image 的子命令。docker image ls 等同于 docker images,docker image pull 等同于 docker pull。

[root@localhost usr]# docker image --help

Usage:  docker image COMMAND

Manage images

Commands:
  build       Build an image from a Dockerfile
  history     Show the history of an image
  import      Import the contents from a tarball to create a filesystem image
  inspect     Display detailed information on one or more images
  load        Load an image from a tar archive or STDIN
  ls          List images
  prune       Remove unused images
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rm          Remove one or more images
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE

Run 'docker image COMMAND --help' for more information on a command.

Docker 和 VM 比较

Docker 工作原理

Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上,然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。容器,是一个运行时环境,就是我们前面说到的集装箱。

为什么 Docker 运行速度远大于 VM?

  1. Docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。

  2. Docker利用的是宿主机的内核,而不需要CentOS。因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。从而避免加载操作系统内核这个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载CentOS,整个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,因此新建一个docker容器只需要几秒钟。

Docker Hello World

通过输入docker pull hello-world来拉取hello-world镜像

[root@localhost usr]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
Digest: sha256:bfea6278a0a267fad2634554f4f0c6f31981eea41c553fdf5a83e95a41d40c38
Status: Image is up to date for hello-world:latest
docker.io/library/hello-world:latest

这样我们就从仓库拉取到了HelloWorld的镜像,接下来我们来运行一下,通过输入docker run hello-world

[root@localhost usr]# docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

若是出现了上图的内容则说明hello-world运行成功。

什么是LXC

在引入Docker之前,或许有必要先聊聊LXC。在Linux使用过程中,大家很少会接触到LXC,因为LXC对于大多数人来说仍然是一个比较陌生的词汇。那为什么我们要在开篇之时,先聊这个陌生的概念呢?这是因为LXC是整个Docker运行的基础。

众所周知,CPU、内存、I/O、网络等都称之为系统资源,而Linux内核有一套机制来管理其所拥有的这些资源,这套机制的核心被称之为CGroups和Namespaces。

CGroups可以限制、记录、调整进程组所使用的物理资源。比如说:使用CGroups可以给某项进程组多分配一些CPU使用周期。同样也可以通过CGroups限制某项进程组可使用的内存上限,一旦达到上限,内核就会发出Out Of Memory错误。同时CGroups也具有记录物理资源使用情况的功能,比如CGroups调用cpuacct子系统就可以记录每个进程所使用的内存数量、CPU时间等数据。正因为Linux有了CGroups资源管理机制,内核虚拟化才变成了可能。

Namespaces则是另外一个重要的资源隔离机制。Namespaces将进程、进程组、IPC、网络、内存等资源都变得不再是全局性资源,而是将这些资源从内核层面属于某个特定的Namespace。在不同的Namespace之间,这些资源是相互透明、不可见的。比如说,A用户登录系统后,可以查看到B用户的进程PID。虽说A用户不能杀死B用户的进程,但A和B却能相互感知。但假如A用户在Namespace-A中,B用户在Namespace-B中,虽然A和B仍然共存于同一个Linux操作系统当中,但A却无法感知到B。在这种情况下,Linux内核不但将Namespace相互隔离,而且将所分配的资源牢牢固定在各自空间之中。

而LXC就是基于Linux内核通过调用CGroups和Namespaces,来实现容器轻量级虚拟化的一项技术,与此同时,LXC也是一组面向Linux内核容器的用户态API接口。Linux Container容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源。用户通过LXC提供的资源限制和隔离功能,可以创建一套完整并且相互隔离的虚拟应用运行环境。

Docker为什么选择了AUFS

Docker为什么选择了AUFS?回答这个问题,需要从AUFS的起源谈起。AUFS原名为Another UnionFS,从名称可以看出,AUFS是对UnionFS的补充。UnionFS是一个堆栈式的联合文件系统,打包在Linux发行版中。但UnionFS很久不进行更新,同时也存在一些不稳定的问题,因此在UnionFS的基础之上进行功能完善,推出了一个新版本,名为AUFS。

当AUFS发布之后,最新版的UnionFS又吸收了AUFS的很多功能,并随之发布在最新的UnionFS版本之中。AUFS也同步更名为Advanced Multi Layered Unification Filesystem。

虽然名称发生了变更,但AUFS本质上仍是堆栈式的联合文件系统。AUFS的功能简单说就是,可以将分布在不同地方的目录挂载到同一个虚拟文件系统当中。

这句话不长,但理解起来颇需一些脑力。没关系,我们慢慢来分析这句话。

首先我们将思路切换到Linux启动阶段。典型的Linux启动时,首先加载bootfs(Boot File System)目录。这个目录里面包括Bootloader和kerenl。Bootloader用来加载启动kerenl。当kerenl成功加载到内存中后,bootfs就会释放掉,kerenl随之开始加载rootfs。

rootfs(Root File System)包含的是Linux系统中标准的/dev、/proc、/bin、/etc等文件。因为rootfs是后续kerenl启动的基础,对于kerenl来说异常重要,因此此时kerenl将Rootfs加锁—设为readonly。在只读权限下,kerenl进行一系列的检查操作。当kerenl确认rootfs包含的文件正确无误后,将readonly改为readwrite(可读可写),以后用户就可以按照正确的权限对这些目录进行操作了。

说到这里,就轮到到AUFS登场了。当Docker利用LXC虚拟化出来一个容器之后,就相当于购买了一台裸机,有内存、CPU、硬盘,但没有操作系统。Docker参考Linux的启动过程,将一个readonly权限的bootfs挂载到容器文件系统中,然后通过AUFS,再将readonly权限的rootfs添加到bootfs之上,当rootfs检查完毕之后,再将用户所要使用的文件内容挂载到rootfs之上,同样是readonly权限。每次挂载一个FS文件层,并且每层之间只会挂载增量(在这里大家可以借助于SVN进行理解,相当每个FS层都是SVN提交上去的数据增量)。

这些文件层就是堆栈式文件系统中所保存的数据。将不同的文件层挂载到同一个文件系统中的文件系统,就是联合文件系统;而AUFS就是用来管理、使用这些文件层的文件系统,因此也称之为高级多层次统一文件系统(Advanced Multi Layered Unification Filesystem)。

但是每个FS层都是readonly权限,那么容器内部如何向这些文件写入数据呢?其实当Docker利用AUFS加载完最高一层之后,会在最上面再添加一个FS层,而这个层是readwrite权限。容器内部的应用,对当前文件系统所有的写操作(包括删除)都会保存在这个FS层当中,而当容器向Docker发出commit命令后,Docker会将这个FS层中的数据作为单独一个文件层保存到AUFS之中。

而一个镜像(image)就可以理解为:特定FS层的集合。所以可以看出镜像的层次关系,处于下层的image是上层image的父类,而没有父类image的就是baseimage。因此需要从image启动container时,Docker会依次加载baseimage和父类image,而用户所有的操作就都保存在最高层的readwrite的layer中。

通过将镜像“分隔”为AUFS的文件层,使得所有容器都可以共享文件层,且不会发生写冲突。但在Docker中,所有的镜像都是只读的,所有的镜像也都不保存用户信息,只会用于新建和复制。而对于容器而言,其所看到的所有文件都是可读写的,只不过所有的写操作都被保存在最上层的文件层当中。

Docker正是通过AUFS的这些特性,解决了容器初始化和写时复制问题,所以Docker选择AUFS作为其第二个核心组件。

参考资料

Docker 社区版各个环境的安装参考官方文档:https://docs.docker.com/install/ Docker官方文档:http://www.docker.com/
Docker官方博客:https://blog.docker.com/
Docker官方Github:https://github.com/moby/moby
Docker用户指引:https://docs.docker.com/engine/userguide/
Docker Hub:https://hub.docker.com/
Docker 开源:https://www.docker.com/open-source
Docker中文社区:http://www.docker.org.cn/
一小时Docker教程:https://blog.csphere.cn/archives/22
Github上的Docker实战:https://github.com/yeasy/docker_practice/blob/master/SUMMARY.md
Github上的Docker资料汇总:https://github.com/hangyan/docker-resources/blob/master/README_zh.md

参考数据

Docker全攻略 第一本Docker书 Docker技术入门与实战 Docker源码分析 Docker全攻略

Search

    微信好友

    博士的沙漏

    Table of Contents