Docker实践(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-26 07:35:27

点击下载

作者:(美) 伊恩·米尔(Ian Miell) 艾丹·霍布森·塞耶斯(Aidan Hobson Sayers)

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Docker实践

Docker实践试读:

前言

2013年9月,浏览黑客志(Hacker News)的时候,我无意中在[1]《连线》上看到一篇介绍一项叫作“Docker”的新技术的文章。在读到这篇文章时,我便意识到Docker所拥有的革命性的潜力,并为此兴奋不已。

我为之工作了十余年的这家公司一直饱受软件交付速度不够快的困扰。准备环境是一件高成本、费时、手工且十分不优雅的事情。持续集成几乎没有,而且配置开发环境也是一件很考验耐心的事情。由于我的职位含有“DevOps经理”的字样,所以我有特别的动力来解决这些问题!

我通过公司的邮件列表招募了一批积极进取的同事(他们中有一位如今是我的合著者),接着我们的创新团队一起努力,将一个尚处于测试阶段的工具变为商业优势,为公司省去了高昂的虚拟机成本,并且开启了构建和部署软件的新思路。我们甚至构建并开源了一款自动化工具(ShutIt),以满足我们的组织的交付需求。

Docker 为我们提供了一个打包和维护的工具,它解决了很多如果仅靠我们自己根本很难逾越的难题。这是开源技术最棒的地方,它为我们提供了利用业余时间接受挑战的机会,帮助克服技术债务,并且每天都能有收获。我们可以从中学到的不只是Docker,还包括持续集成、持续交付、打包、自动化以及人们该如何应对日新月异的技术革新。

对我们来说,Docker是一个用途异常广泛的工具。只要使用Linux系统来运行软件,Docker便有用武之地。这也使编写这一主题的图书充满了挑战,毕竟我们的视角是落在广袤的软件本身。为了迎合软件生产方式这样一个本质上的变化,Docker生态系统也在飞速地产出新的解决方案,这也使写书的任务变得更加艰巨。随着时间的推移,我们开始逐渐了解这些问题和解决方案的本质,而在本书里,我们将竭尽所能地传达这些经验。这可以帮助读者找出满足自己的特定技术和业务约束场景的解决方案。

在聚会上面发表演讲时,我们也为Docker在愿意接纳它的组织内部迅速高效地投入使用的方法而感到震撼。本书如实讲述了我们是怎样使用Docker的,涵盖了从桌面到DevOps流水线,再一路到生产环境的整个过程。因此,这本书可能会显得不那么正统,但是作为工程师来说,我们相信纯粹性有时候必须让步于实用性,尤其是涉及节约成本方面的话题!本书的所有内容均来源于一线生产的实际经验,我们衷心希望读者可以从我们来之不易的经验中获益。

Ian Miell[1] http://www.wired.com/2013/09/docker/致谢

如果没有我们最亲近的人的支持、牺牲和耐心,这本书是绝对无法完成的。特别要提到的是Stephen Hazleton,本书的不少内容正是他为了使Docker能够造福我们的客户,同我们一起不懈努力的成果。

几位Docker的贡献者和Docker的员工还非常热情地在不同阶段帮忙审阅了本书的内容,并且提供了许多有价值的反馈,下面几位阅读了本书的初稿:Benoit Benedetti、Burkhard Nestmann、Chad Davis、David Moravec、Ernesto Cárdenas Cangahuala、Fernando Rodrigues、JoséSan Leandro、Kirk Brattkus、Pethuru Raj、Scott Bates、Steven Lembark、Stuart Woodward、Ticean Bennett、Valmiky Arquissandas和 Wil Moore III。

最后,本书很大程度上还归功于Manning出版社的编辑团队,他们用自己的方式推动我们改进,使这本书虽不至于完美,但已然做到尽可能好。我们希望他们会为在我们身上付出的努力而感到自豪。

Ian Miell感谢Sarah、Isaac和Rachel,感谢你们忍受我深夜编程,包容一位紧盯着笔记本屏幕的父亲,并且没完没了地念叨“Docker这Docker那,Docker……”,还要感谢我的父母从小就鼓励我去质疑现状,还给我买Spectrum(腕表)。

Aidan Hobson Sayers感谢Mona的支持和鼓励,感谢我的父母睿智和鼓励的话,还有我的合著者决定命运的那封“有谁试过Docker这种东西?”的电子邮件。关于本书

Docker可以说是目前增长速度最快的软件项目。它于2013年3月开源,到2016年它已经获得了近30 000个GitHub star以及超过7500次fork。它还接受了大量像Red Hat、IBM、微软、谷歌、思科和Vmware这些厂商的pull request。

Docker在这个关键时刻的出现正是为了迎合许多软件组织的一个迫切需求:以一种开放和灵活的方式来构建软件,然后在不同环境下能够可靠和一致地部署它。用户不需要学习新的编程语言,购买昂贵的硬件,也无须再为了构建、部署和运行可移植的应用程序而在安装或者配置过程上花费过多工夫。

本书将会通过我们在不同场景下用到的一些技术,带读者领略真实世界里的Docker实践案例。我们已经竭力尝试阐明这些技术,尽可能做到无须在阅读前事先具备其他相关技术的知识背景。我们假定读者了解一些基本的开发技术和概念,如开发一些结构化代码的能力,以及对软件开发和部署流程的一些了解。此外,我们认为读者还应了解一些核心的源代码管理理念并且对像TCP/IP、HTTP和端口这样的网络基础知识有一个基本的了解。其他不怎么主流的技术会在我们介绍到的时候予以说明。

我们将从第一部分介绍Docker的基础知识开始,而到了第二部分,我们将把重点放在介绍如何将Docker用到单台机器的开发环境。在第三部分里,我们将介绍Docker在DevOps流水线中的用法,介绍持续集成、持续交付和测试等内容。本书的最后一部分则覆盖了Docker生产实践的内容,重点关注与编排相关的一些备选方案。

Docker是一个用途广泛、灵活和动态的工具,以至于没有一点儿魄力的话很难追上它快速发展的脚步。我们会尽力通过真实世界的应用和例子让读者更好地理解其中的一些关键概念,目的是希望读者能够有实力、有信心在Docker的生态系统里审慎评估未来采用的工具和技术。我们一直在努力让本书变得更像是一次愉快的旅行,即介绍我们在很多方面见证的Docker是怎样使我们的生活变得更加轻松甚至于更加有趣的。我们正沉浸在Docker以一个别致的方式为我们呈现的覆盖整个软件生命周期的许多有意思的软件技术里,而我们希望本书的读者同样也能分享这样的体验。路线图

本书包括12章,分为4个部分。

第一部分奠定了本书其余部分的基础,介绍Docker的概念并且教读者运行一些基本的Docker命令。第2章的一些内容旨在让读者熟悉Docker的客户-服务器架构以及如何调试它,这对在非常规的Docker配置中定位问题是非常有用的。

第二部分关注熟悉Docker以及在自己的机器上如何充分利用Docker。我们将用到一个读者可能比较熟悉的相关概念——虚拟机,作为第3章的基础,提供Docker使用的一些介绍。然后第 4 章会详细介绍几个我们发现自己每天都在使用的Docker技巧。这一部分的最后一章则探索了更为深入的镜像构建方面的主题。

第三部分从关注Docker在DevOps上下文中的使用开始,从用它完成软件构建和测试的自动化到将它迁移至不同的环境。这一部分还会花一章的篇幅来总结Docker的虚拟网络,介绍Docker Compose,并且覆盖一些更为高级的网络主题,如网络模拟以及Docker网络插件等。

第四部分会介绍几个针对在生产环境中如何有效地利用Docker的主题。这一部分从第9章开始,在这一章里我们调研了一些最主流的容器编排工具,然后指出了它们往往倾向用在哪些场景。第10章讨论的是安全性的重要话题,阐明了如何锁定在容器里运行的进程,以及如何限制访问对外暴露的Docker守护进程。最后两章则会细讲一些在生产环境中运行Docker的重要实用信息。第11章会展示如何将经典的系统管理知识应用到容器上下文中,从登录到资源限制,而第12章着眼于一些读者可能遇到的问题并且给出对应的调试和解决步骤。

附录里则是一些以不同方式安装、使用和配置Docker的具体细节,包括在虚拟机里以及在Windows上。代码

本书中用到的所有由作者创建的工具、应用以及Docker镜像的源代码都可以在Manning出版社网站下载,地址是www.manning.com/books/docker-in-practice,读者也可以在GitHub上的docker-in-practise组织https://github.com/docker-in-practice/找到这些源代码。Docker Hub上dockerinpractise用户下的镜像(https://hub.docker.com/u/dockerinpractice/)均是从其中一个GitHub仓库自动构建生成的。在这里,我们已经意识到读者可能会有兴趣对技术背后的一些源代码做进一步的研究,因此在技术讨论里也嵌入了相关仓库的链接。

为了方便读者跟进,本书中列出的大量代码均以终端会话的形式,与相应的命令输出一起展示。这些会话里有几件事情要注意一下。

很长的终端命令可能会使用shell的续行字符(\)将一条命令分割成多行。虽然读者直接把它贴到自己的shell下面运行也能工作,但是读者也可以略去这个续行字符,在一行里键入整条命令。

当输出的部分对于读者来说没有提供额外有用的信息时,它可能会被省略并在相应的位置用省略号([...])替代。作者在线

购买本书的读者还可免费得到由Manning出版社运营的一个私有网站论坛的访问权限,在这里读者可以对本书作出评论,询问技术问题,并获得来自主要作者以及其他读者的帮助。要访问和订阅该论坛的话,请用Web浏览器打开www.manning.com/books/docker-in-practice。该页面将会提供一些信息,包括读者注册后该如何登录到论坛,能获得怎样的帮助,以及论坛里的一些行为准则。

Manning对读者的承诺是会为其提供一个读者之间以及读者和作者之间进行有价值讨论的场所。但并不承诺作者的参与程度,作者对论坛的贡献目前仍然还是停留在志愿性质(并且是无报酬的)。我们建议读者试着问一些有挑战的问题,以激发作者回答问题的兴趣!作者在线论坛和之前讨论的档案只要书还在发行就一直可以在Manning出版社网站上访问。关于封面插画

本书的封面图片的标题是“一个来自克罗地亚赛尔切的男人”(Man from selc, croatia)。这张图片取自19世纪中期Nikola Arsenovic的一本克罗地亚传统服饰图集的复刻版,由克罗地亚斯普利特人种学博物馆在2003年出版。该图由人种学博物馆的一位热心的图书管理员提供。该博物馆位于中世纪时罗马帝国的核心城镇,从约公元304年起,帝国国王戴克里先退位后居住的皇宫的遗迹就在这里。这本书中涵盖了来自克罗地亚各个地区的华丽的彩色图片,并介绍了他们的服饰和日常生活。

在这过去的200年里,服饰和生活方式都发生了巨大的变化,各地当时的特色也已随时间消逝。如今,来自不同大陆的人都已经变得难以区分,更不用说相隔仅数千米的村镇居民了。或许,文化多样性也是我们为获得丰富多彩的个人生活而付出的代价——现在生活无疑是更多姿多彩的、快节奏的高科技生活。

Manning出版社用两个世纪前各地独具特色的生活方式来赞美计算机行业的诞生和发展,并用古老的书籍和图册中的图片让我们领略那个时代的风土人情。第一部分Docker基础

本书的第一部分由第1章和第2章构成,将带领读者开始使用Docker,并讲解其基础知识。第1章阐述Docker的起源及其核心概念,如镜像、容器和分层。在第1章的最后,读者将动手使用Dockerfile创建自己的第一个镜像。第2章介绍一些有用的技巧,让读者深入理解Docker的架构。我们通过依次讲解每个主要组件,阐述Docker守护进程与其客户端、Docker注册中心和Docker Hub之间的关系。在第一部分结束时,读者将对Docker的核心概念有所了解,并能够演示一些有用的技巧,为理解本书的后续内容打下坚实的基础。第1章Docker初探

本章主要内容● Docker是什么● Docker的使用以及它如何能节省时间和金钱● 容器与镜像之间的区别● Docker的分层特性● 使用Docker构建并运行一个to-do应用程序

Docker是一个允许用户“在任何地方构建、分发及运行任何应用”的平台。它在极短的时间内发展壮大,目前已经被视为解决软件中最昂贵的方面之一——部署的一个标准方法。

在Docker出现之前,开发流水线通常由用于管理软件活动的不同技术组合而成,如虚拟机、配置管理工具、不同的包管理系统以及各类依赖库复杂的网站。所有这些工具需要由专业的工程师管理和维护,并且多数工具都具有自己独特的配置方式。

Docker改变了这一切,允许不同的工程师参与到这个过程中,有效地使用同一门语言,这让协作变得轻而易举。所有东西通过一个共同的流水线转变成可以在任何目标平台上使用的单一的产出——无须继续维护一堆让人眼花缭乱的工具配置,如图1-1所示。

与此同时,只要现存的软件技术栈依然有效,用户就无须抛弃它——用户可以将其原样打包到一个Docker容器内供其他人使用。由此获得的额外好处是,用户能看到这些容器是如何构建的,因此如果需要深入其细节,完全没问题。

本书针对的是具有一定Docker知识的中级开发人员。如果读者对本书的基础部分较熟悉,可随意跳到后续章节。本书的目标是揭示Docker所带来的现实世界的挑战,并展示其解决之道。不过,首先我们将提供一个Docker自身的快速回顾。如果读者想了解更全面的Docker基础,请查阅Jeff Nickoloff编写的《Docker in Action》一书(Manning Publications,2016)。

第2章将更深入地介绍Docker的架构,并通过一些技巧来演示其威力。在本章中,读者将了解到Docker是什么、为什么它很重要,并开始使用它。图1-1 Docker如何消除了工具维护的负担1.1 Docker是什么以及为什么用Docker

在动手实践之前,我们将对Docker稍做讨论,以便读者了解它的背景、“Docker”名字的来历以及为什么使用它!1.1.1 Docker是什么

要理解Docker是什么,从一个比喻开始会比技术性解释来得简单,而且这个Docker的比喻非常有说服力。Docker原本是指在船只停靠港口之后将商品移进或移出的工人。箱子和物品的大小和形状各异,而有经验的码头工人能以合算的方式手工将商品装入船只,因而他们倍受青睐(见图1-2)。雇人搬东西并不便宜,但除此之外别无选择。

对在软件行业工作的人来说,这听起来应该很熟悉。大量时间和精力被花在将奇形怪状的软件放置到装满了其他奇形怪状软件、大小各异的船只上,以便将其卖给其他地方的用户或商业机构。

图1-3展示了使用Docker概念时如何能节省时间和金钱。图1-2 标准化集装箱前后的航运对比

在Docker出现之前,部署软件到不同环境所需的工作量巨大。即使不是采用手工运行脚本的方式在不同机器上进行软件配备(还是有很多人这么做),用户也不得不全力应付那些配置管理工具,它们掌管着渴求资源且快速变化的环境的状态。即便将这些工作封装到虚拟机中,还是需要花费大量时间来部署这些虚拟机、等待它们启动并管理它们所产生的额外的资源开销。

使用Docker,配置工作从资源管理中分离了出来,而部署工作则是微不足道的:运行docker run,环境的镜像会被拉取下来并准备运行,所消耗的资源更少并且是内含的,因此不会干扰其他环境。

读者无须担心容器是将被分发到Red Hat机器、Ubuntu机器还是CentOS虚拟机镜像中,只要上面有Docker,就没有问题。图1-3 使用Docker前后软件交付的对比1.1.2 Docker有什么好处

几个重要的实际问题出现了:为什么要使用Docker,Docker用在什么地方?针对“为什么”的简要答案是:只需要一点点付出,Docker就能快速为企业节省大量金钱。部分方法(肯定不是所有的)将在随后的几节中讨论。我们已经在实际工作环境中切身体会到所有这些益处。1.替代虚拟机(VM)

Docker可以在很多情况下替代虚拟机。如果用户只关心应用程序,而不是操作系统,可以用Docker替代虚拟机,并将操作系统交给其他人去考虑。Docker不仅启动速度比虚拟机快,迁移时也更为轻量,同时得益于它的分层文件系统,与其他人分享变更时更简单、更快捷。而且,它牢牢地扎根在命令行中,非常适合脚本化。2.软件原型

如果想快速体验软件,同时避免干扰目前的设置或配备一个虚拟机的麻烦,Docker可以在几毫秒内提供一个沙箱环境。在亲身体验之前,很难感受到这种解放的效果。3.打包软件

因为对Linux用户而言,Docker镜像实际上没有依赖,所以非常适合用于打包软件。用户可以构建镜像,并确保它可以运行在任何现代Linux机器上——就像Java一样,但不需要JVM。4.让微服务架构成为可能

Docker 有助于将一个复杂系统分解成一系列可组合的部分,这让用户可以用更离散的方式来思考其服务。用户可以在不影响全局的前提下重组软件使其各部分更易于管理和可插拔。5.网络建模

由于可以在一台机器上启动数百个(甚至数千个)隔离的容器,因此对网络进行建模轻而易举。这对于现实世界场景的测试非常有用,而且所费无几。6.离线时启用全栈生产力

因为可以将系统的所有部分捆绑在Docker容器中,所以用户可以将其编排运行在笔记本电脑中移动办公,即便在离线时也没问题。7.降低调试支出

不同团队之间关于软件交付的复杂谈判在业内司空见惯。我们亲身经历过不计其数的这类讨论:失效的库、有问题的依赖、更新被错误实施或是执行顺序有误,甚至可能根本没执行以及无法重现的错误等。估计读者也遇到过。Docker让用户可以清晰地说明(即便是脚本的形式)在一个属性已知的系统上调试问题的步骤,错误和环境重现变得更简单,而且通常与所提供的宿主机环境是分离的。8.文档化软件依赖及接触点

通过使用结构化方式构建镜像,为迁移到不同环境做好准备,Docker 强制用户从一个基本出发点开始明确地记录软件依赖。即使用户不打算在所有地方都使用Docker,这种对文档记录的需要也有助于在其他地方安装软件。9.启用持续交付

持续交付(continuous delivery,CD)是一个基于流水线的软件交付范型,该流水线通过一个自动化(或半自动化)流程在每次变动时重新构建系统然后交付到生产环境中。

因为用户可以更准确地控制构建环境的状态,Docker 构建比传统软件构建方法更具有可重现性和可复制性。使持续交付的实现变得更容易。通过实现一个以Docker为中心的可重现的构建过程,标准的持续交付技术,如蓝/绿部署(blue/green deployment,在生产环境中维护“生产”和“最新”部署)和凤凰部署(phoenix deployment,每次发布时都重新构建整个系统)变得很简单。

现在,读者对Docker如何能够提供帮助有了一定了解。在进入一个真实示例之前,让我们来了解一下几个核心概念。1.1.3 关键的概念

在本节中,我们将介绍一些关键的Docker概念,如图1-4所示。图1-4 Docker的核心概念

在开始运行Docker命令之前,将镜像、容器及层的概念牢记于心是极其有用的。简而言之,容器运行着由镜像定义的系统。这些镜像由一个或多个层(或差异集)加上一些Docker的元数据组成。

让我们来看一些核心的Docker命令。我们将把镜像转变成容器,修改它们,并添加层到我们即将提交的新镜像中。如果这一切听上去有点儿混乱,不用太担心。在本章结束时,一切都将更加清晰。1.关键的Docker命令

Docker的中心功能是构建、分发及在任何具有Docker的地方运行软件。

对终端用户而言,Docker是一个用于运行的命令行程序。就像git(或任何源代码控制工具)一样,这个程序具有用于执行不同操作的子命令。

表1-1中列出了将在宿主机上使用的主要的Docker子命令。表1-1 Docker子命令命  令目  的docker build构建一个Docker镜像docker run以容器形式运行一个Docker镜像docker commit将一个Docker容器作为一个镜像提交docker tag给一个Docker镜像打标签2.镜像与容器

如果读者不熟悉Docker,这可能是第一次听说本文所说的“容器”和“镜像”这两个词。它们很可能是Docker中最重要的概念,因此有必要花点儿时间明确其差异。

在图1-5中,读者将看到这些概念的展示,里面有从一个基础镜像启动的3个容器。图1-5 Docker镜像与容器

看待镜像和容器的一种方式是将它们类比成程序与进程。一个进程可以视为一个被执行的应用程序,同样,一个Docker容器可以视为一个运行中的Docker镜像。

如果读者熟悉面向对象原理,看待镜像和容器的另一种方法是将镜像看作类而将容器看作对象。对象是类的具体实例,同样,容器是镜像的实例。用户可以从单个镜像创建多个容器,就像对象一样,它们之间全都是相互隔离的。不论用户在对象内修改了什么,都不会影响类的定义——它们从根本上就是不同的东西。1.2 构建一个Docker应用程序

现在,我们要动手使用Docker来构建一个简单的“to-do”应用程序(todoapp)镜像了。在这个过程中,读者会看到一些关键的Docker功能,如Dockerfile、镜像复用、端口暴露及构建自动化。这是接下来10分钟读者将学到的东西:● 如何使用Dockerfile来创建Docker镜像;● 如何为Docker镜像打标签以便引用;● 如何运行新建的Docker镜像。

to-do应用是协助用户跟踪待完成事项的一个应用程序。我们所构建的应用将存储并显示可被标记为已完成的信息的简短字符串,它以一个简单的网页界面呈现。

图1-6展示了如此操作将得到的结果。图1-6 构建一个Docker应用程序

应用程序的细节不是重点。我们将演示从我们所提供的一个简短的Dockerfile开始,读者可以放心地在自己的宿主机上使用与我们相同的方法构建、运行、停止和启动一个应用程序,而无须考虑应用程序的安装或依赖。这正是 Docker 赋予我们的关键部分——可靠地重现并简便地管理和分享开发环境。这意味着用户无须再遵循并迷失在那些复杂的或含糊的安装说明中。to-do应用程序 这个to-do应用程序将贯穿本书,多次使用,它非常适合用于实践和演示,因此值得读者熟悉一下。1.2.1 创建新的Docker镜像的方式

创建Docker镜像有4种标准的方式。表1-2逐一列出了这些方法。表1-2 创建Docker镜像的方式方  法描  述详见技巧Docker命令/“手工”使用docker run启动一个容器,并在命令行输入命令来详见创建镜像。使用docker commit来创建一个新镜像技巧14Dockerfile从一个已知基础镜像开始构建,并指定一组有限的简稍后单命令来构建讨论Dockerfile及配置管理与Dockerfile相同,不过将构建的控制权交给了更为复详见(configuration 杂的CM工具技巧management,CM)工具47从头创建镜像并导入一组文从一个空白镜像开始,导入一个含有所需文件的TAR详见件文件技巧10

如果用户所做的是概念验证以确认安装过程是否正常,那么第一种“手工”方式是没问题的。在这个过程中,用户应对所采取的步骤做记录,以便在需要时回到同一点上。

到某个时间点,用户会想要定义创建镜像的步骤。这就是第二种方式(也就是我们这里所用的方式)。

对于更复杂的构建,用户需要使用第三种方式,特别是在Dockerfile功能还不足以满足镜像要求的时候。

最后一种方式从一个空镜像开始,通过叠加一组运行镜像所需要的文件进行构建。如果用户想导入一组在其他地方创建好的自包含的文件,这将非常有用,不过这在主流应用中非常罕见。

现在,我们来看一下Dockerfile方法,其他方法将在本书后面再说明。1.2.2 编写一个Dockerfile

Dockerfile是一个包含一系列命令的文本文件。本示例中我们将使用的Dockerfile如下:FROM node (1)MAINTAINER ian.miell@gmail.com (2)RUN git clone -q https://github.com/docker-in-practice/todo.git (3)WORKDIR todo (4)RUN npm install > /dev/null (5)EXPOSE 8000 (6)CMD ["npm","start"] (7)(1)❶定义基础镜像(2)❷声明维护人员(3)❸克隆todoapp代码(4)❹移动到新的克隆目录(5)❺运行node包管理器的安装命令(npm)(6)❻指定从所构建的镜像启动的容器需要监听这个端口(7)❼指定在启动时需要运行的命令

Dockerfile的开始部分是使用FROM命令定义基础镜像❶。本示例使用了一个Node.js镜像以便访问Node.js程序。官方的Node.js镜像名为node。

接下来,使用MAINTAINER命令声明维护人员❷。在这里,我们我们使用的是其中一个人的电子邮件地址,读者也可以替换成自己的,因为现在它是你的Dockerfile了。这一行不是创建可工作的Docker镜像所必需的,不过将其包含进来是一个很好的做法。到这个时候,构建已经继承了node容器的状态,读者可以在它上面做操作了。

接下来,使用RUN命令克隆todoapp代码❸。这里使用指定的命令获取应用程序的代码:在容器内运行git。在这个示例中,Git是安装在基础node镜像里的,不过读者不能对这类事情做假定。

现在移动到使用WORKDIR命令新克隆的目录中❹。这不仅会改变构建环境中的目录,最后一条WORKDIR命令还决定了从所构建镜像启动容器时用户所处的默认目录。

接下来,运行node包管理器的安装命令(npm)❺。这将为应用程序设置依赖。我们对输出的信息不感兴趣,所以将其重定向到/dev/null上。

由于应用程序使用了8000端口,使用EXPOSE命令告诉Docker从所构建镜像启动的容器应该监听这个端口❻。

最后,使用CMD命令告诉Docker在容器启动时将运行哪条命令❼。

这个简单的示例演示了Docker及Dockerfile的几个核心功能。Dockerfile是一组严格按顺序运行的有限的命令集的简单序列。它们影响了最终镜像的文件和元数据。这里的RUN命令通过签出并安装应用程序影响了文件系统,而EXPOSE、CMD和WORKDIR命令影响了镜像的元数据。1.2.3 构建一个Docker镜像

读者已经定义了自己的Dockerfile的构建步骤。现在可以键入图1-7所示的命令从而构建Docker镜像了。图1-7 Docker build命令

读者将看到类似下面这样的输出:Sending build context to Docker daemon 178.7 kB (1)Sending build context to Docker daemonStep 0 : FROM node (2) ---> fc81e574af43 (3)            Step 1 : MAINTAINER ian.miell@gmail.com ---> Running in 21af1aad6950 ---> 8f32669fe435Removing intermediate container 21af1aad6950 (4)Step 2 : RUN git clone https://github.com/ianmiell/todo.git ---> Running in 0a030ee746eaCloning into 'todo'... ---> 783c68b2e3fcRemoving intermediate container 0a030ee746eaStep 3 : WORKDIR todo ---> Running in 2e59f5df7152 ---> 8686b344b124Removing intermediate container 2e59f5df7152Step 4 : RUN npm install ---> Running in bdf07a308fcanpm info it worked if it ends with ok (5)[...]npm info ok ---> 6cf8f3633306Removing intermediate container bdf07a308fcaStep 5 : RUN chmod -R 777 /todo ---> Running in c03f27789768 ---> 2c0ededd3a5eRemoving intermediate container c03f27789768Step 6 : EXPOSE 8000 ---> Running in 46685ea97b8f ---> f1c29feca036Removing intermediate container 46685ea97b8fStep 7 : CMD npm start ---> Running in 7b4c1a9ed6af ---> 66c76cea05bbRemoving intermediate container 7b4c1a9ed6afSuccessfully built 66c76cea05bb (6)(1)Docker会上传docker build指定目录下的文件和目录(2)每个构建步骤从 0 开始按顺序编号,并与命令一起输出(3)每个命令会导致一个新镜像被创建出来,其镜像ID在此输出(4)为节省空间,在继续前每个中间容器会被移除(5)构建的调试信息在此输出(限于篇幅,本代码清单做了删减)(6)此次构建的最终镜像ID,可用于打标签

现在,拥有了一个具有镜像ID(前面示例中的“66c76cea05bb”,不过读者的ID会不一样)的Docker镜像。总是引用这个ID会很麻烦,可以为其打标签以方便引用。

输入图1-8所示的命令,将66c76cea05bb替换成读者生成的镜像ID。图1-8 Docker tag命令

现在就能从一个Dockerfile构建自己的Docker镜像副本,并重现别人定义的环境了!1.2.4 运行一个Docker容器

读者已经构建出Docker镜像并为其打上了标签。现在可以以容器的形式来运行它了:  docker run -p 8000:8000 --name example1 todoapp (1)   npm install  npm info it worked if it ends with ok  npm info using npm@2.14.4  npm info using node@v4.1.1  npm info prestart todomvc-swarm@0.0.1  > todomvc-swarm@0.0.1 prestart /todo (2)  > make all  npm install  npm info it worked if it ends with ok  npm info using npm@2.14.4  npm info using node@v4.1.1  npm WARN package.json todomvc-swarm@0.0.1 No repository field.  npm WARN package.json todomvc-swarm@0.0.1 license should be a   ➥ valid SPDX license expression  npm info preinstall todomvc-swarm@0.0.1  npm info package.json statics@0.1.0 license should be a valid   ➥ SPDX license expression  npm info package.json react-tools@0.11.2 No license field.  npm info package.json react@0.11.2 No license field.  npm info package.json node-jsx@0.11.0 license should be a valid   ➥ SPDX license expression  npm info package.json ws@0.4.32 No license field.  npm info build /todo  npm info linkStuff todomvc-swarm@0.0.1  npm info install todomvc-swarm@0.0.1  npm info postinstall todomvc-swarm@0.0.1  npm info prepublish todomvc-swarm@0.0.1  npm info ok  if [ ! -e dist/ ]; then mkdir dist; fi  cp node_modules/react/dist/react.min.js dist/react.min.js  LocalTodoApp.js:9:   // TODO: default english version  LocalTodoApp.js:84:        fwdList =   ➥ this.host.get('/TodoList#'+listId); // TODO fn+id sig  TodoApp.js:117:   // TODO scroll into view  TodoApp.js:176:   if (i>=list.length()) { i=list.length()-1;}   ➥ // TODO .length  local.html:30:    model/TodoList.js:29:   ➥ // TODO one op - repeated spec? long spec?  view/Footer.jsx:61:    // TODO: show the entry's metadata  view/Footer.jsx:80:       todoList.addObject(new TodoItem());   ➥ // TODO create default  view/Header.jsx:25:   ➥ // TODO list some meaningful header (apart from the id)npm info start todomvc-swarm@0.0.1> todomvc-swarm@0.0.1 start /todo> node TodoAppServer.jsSwarm server started port 8000^C (3)                 $ docker ps –a (4)           CONTAINER ID IMAGE     COMMAND     CREATED   ➥ STATUS          PORTS NAMESb9db5ada0461 todoapp:latest "npm start" 2 minutes ago ➥ Exited (130) 2 minutes ago example1$ docker start example1 (5)    example1$ docker ps -aCONTAINER ID  IMAGE      COMMAND  CREATED➥ STATUS      PORTS         NAMESb9db5ada0461 todoapp:latest "npm start" 8 minutes ago➥ Up 10 seconds 0.0.0.0:8000->8000/tcp example1 (6)$ docker diff example1 (7)            C /todo (8)              A /todo/.swarmA /todo/.swarm/TodoItemA /todo/.swarm/TodoItem/1tlOc02+A~4Uzcz (9)    A /todo/.swarm/_log  A /todo/distA /todo/dist/LocalTodoApp.app.jsA /todo/dist/TodoApp.app.jsA /todo/dist/react.min.js(1)❶docker run子命令启动容器,-p将容器的 8000 端口映射到宿主机的8000端口上,--name给容器赋予一个唯一的名字,最后一个参数是镜像(2)容器的启动进程的输出被发送到终端中(3)❷在此按Ctrl+C终止进程和容器(4)❸运行这个命令查看已经启动和移除的容器,以及其ID和状态(就像进程一样)(5)❹重新启动容器,这次是在后台运行(6)❺再次运行ps命令查看发生变化的状态(7)❻docker diff子命令显示了自镜像被实例化成一个容器以来哪些文件受到了影响(8)❼修改了/todo目录(9)❽增加了/todo/.swarm目录

docker run子命令启动容器❶。-p标志将容器的8000端口映射到宿主机的8000端口上,读者现在应该可以使用浏览器访问http://localhost:8000来查看这个应用程序了。--name标志赋予了容器一个唯一的名称,以便后面引用。最后的参数是镜像名称。

一旦容器启动,我们按下CTRL-C终止进程和容器❷。读者可以运行ps命令查看被启动且未被移除的容器❸。注意,每个容器都具有自己的容器 ID 和状态,与进程类似。它的状态是Exited(已退出),不过读者可以重新启动它❹。这么做之后,注意状态已经改变为Up(运行中),且容器到宿主机的端口映射现在也显示出来了❺。

docker diff子命令显示了自镜像被实例化成一个容器以来哪些文件受到了影响❻。在这个示例中,修改了todo目录❼,并增加了其他列出的文件❽。没有文件被删除,这是另一种可能性。

如读者所见,Docker“包含”环境的事实意味着用户可以将其视为一个实体,在其上执行的动作是可预见的。这赋予了Docker宽广的能力——用户可以影响从开发到生产再到维护的整个软件生命周期。这种改变正是本书所要描述的,在实践中展示Docker所能完成的东西。

接下来读者将了解Docker的另一个核心概念——分层。1.2.5 Docker分层

Docker分层协助用户管理在大规模使用容器时会遇到的一个大问题。想象一下,如果启动了数百甚至数千个to-do应用,并且每个应用都需要将文件的一份副本存储在某个地方。

可想而知,磁盘空间会迅速消耗光!默认情况下,Docker在内部使用写时复制(copy-on-write)机制来减少所需的硬盘空间量(见图 1-9)。每当一个运行中的容器需要写入一个文件时,它会通过将该项目复制到磁盘的一个新区域来记录这一修改。在执行Docker提交时,这块磁盘新区域将被冻结并记录为具有自身标识符的一个层。图1-9 启动时复制与写时复制对比

这部分解释了Docker容器为何能如此迅速地启动——它们不需要复制任何东西,因为所有的数据已经存储为镜像。写时复制 写时复制是计算技术中使用的一种标准的优化策略。在从模板创建一个新的(任意类型)对象时,只在数据发生变化时才能将其复制进来,而不是复制整个所需的数据集。依据用例的不同,这能省下相当可观的资源。

图1-10展示了构建的to-do应用,它具有我们所感兴趣的3层。

因为层是静态的,所以用户只需要在想引用的镜像之上进行构建,变更的内容都在上一层中。在这个to-do应用中,我们从公开可用的node镜像构建,并将变更叠加在最上层。图1-10 Docker中to-do应用的文件系统分层

所有这3层都可以被多个运行中的容器共享,就像一个共享库可以在内存中被多个运行中的进程共享一样。对于运维人员来说,这是一项至关重要的功能,可以在宿主机上运行大量基于不同镜像的容器,而不至于耗尽磁盘空间。

想象一下,你将所运行的to-do应用作为在线服务提供给付费用户,可以将服务扩散给大量用户。如果你正在开发中,可以一下在本地机器上启动多个不同的环境。如果你正在进行测试,可以比之前同时运行更多测试,速度也更快。有了分层,所有这些东西都成为了可能。

通过使用Docker构建和运行一个应用程序,读者开始见识到Docker能给工作流带来的威力。重现并分享特定的环境,并能在不同的地方落地,让用户在开发过程中兼具灵活性和可控性。1.3 小结

依据读者以往的Docker经验不同,本章可能存在一个陡峭的学习曲线。我们在短时间内讨论了大量的基础内容。

读者现在应该:● 理解Docker镜像是什么;● 知道Docker分层是什么,以及为什么它很有用;● 能够从一个基础镜像提交一个新的Docker镜像;● 知道Dockerfile是什么。

我们已经使用这项知识:● 创建了一个有用的应用程序;● 毫不费力地重现了一个应用程序中的状态。

接下来,我们将介绍几个有助于读者理解Docker如何工作的技巧,然后讨论有关Docker用法的一些更广泛的技术争论。前两个介绍

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载