Docker从入门到实战(txt+pdf+epub+mobi电子书下载)

作者:黄靖钧

出版社:机械工业出版社

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

Docker从入门到实战

Docker从入门到实战试读:

前言

Docker作为一个2013年才诞生的开源项目,其发展的速度和火爆程度却令人惊叹。容器技术本不是什么新鲜事物,但是在Docker的整合下,一切变得清晰、易用起来,并且随着各大云计算厂商的进场,使Docker得到了极大的推广。

如今,Docker已经成为容器技术领域当仁不让的领头羊。国内外以Docker技术起家的创业公司如雨后春笋般涌现出来,体现了容器市场的巨大需求。越来越多的企业开始逐步把传统的应用开发流程迁移到Docker容器中作为开发部署流程的一环。伴随而来的是各种复杂的需求与Docker尚不算完善的功能所产生的矛盾,这些问题制约着企业容器化的脚步。

另一方面,Docker以其友好的使用体验使广大开发者对其“一见倾心”,越来越多的开发者使用Docker作为应用分发部署的一个重要阵地。尽管如此,Docker对于大部分开发者而言还是尚未开拓的疆土。特别是对于国内环境而言,Docker的推广基本上靠国内几家与Docker相关的初创公司。本书以一位普通的全栈开发者的身份,详细介绍了Docker的基础知识,分享了企业级容器云的实战经验。

为什么学习Docker

如果您是一名开发者,想必遇到过“这个程序只有在我的机器上才可以运行”的情况。随着用户需求变得多样,软件愈发复杂,所依赖环境愈发庞大,使得软件在其他机器上运行需要做大量的迁移工作。更糟糕的是,这些琐事完成后软件还不一定能正常运行。

为了解决这些问题,虚拟化技术开始普及。人们可以通过各种虚拟化技术来实现软件的迁移和分发。最常见的就是虚拟机或KVM技术。在虚拟机里完成开发再迁移到线上不会出现环境问题,解决了迁移过程中的诸多难题,但是仍然存在性能低下、分发流程麻烦、耗时和成本昂贵等问题。在云计算时代这些问题更加突出。

随着容器技术的普及,人们意识到容器技术可以极大地降低成本。容器技术具有启动快、体积小和分发迅速等诸多特点,这简直就是开发人员梦寐以求的工具。

而“欣喜若狂”的不止是开发人员,还有运维人员。如果在十年前,普通企业要管理上百台服务器,最可能使用的方法是通过Shell脚本的方式使用SSH连接到所有服务器然后执行相同的指令,并把日志保存起来归档。这种方式我们称之为第一代运维。那时维护服务器是一项繁重的工作,工程师不得不把大量的时间耗费在服务器管理上。

随着技术的发展,虚拟化技术的普及和云计算的出现,企业需要管理的服务器数量大幅增长。过去我们只要管理企业内部数据中心的物理服务器,而现在则要管理遍布全球的服务器,运维成本愈发昂贵。于是开发者开始针对云计算时代服务器运维方式做出改变,涌现出了诸如Ansible、Puppet、SaltStack和Chef等出色的运维工具。人们可以通过这些工具快速地完成对上百台甚至上千台服务器的管理操作。这被称之为第二代运维。它极大地解决了管理庞大服务器集群的难题,使人们可以在屏幕面前通过一个界面管理所有服务器。但本质上这些工具都是通过SSH或者类似于SSH的方式连接到服务器来管理服务器集群,这意味着其实第二代运维和第一代运维并没有发生根本性的改变。

上面那些运维工具在云计算普及的大势下很快暴露了它们的问题——速度。因为大部分运维工具依靠的是SSH连接来交换信息,这使得整个过程十分耗时,更不用说其他复杂的管理操作。而随着容器技术的爆发,以Docker为代表的容器技术开始发力,并随着DevOps概念的普及,使运维发生了根本性的改变。容器集群管理不再是通过低效的SSH来连接服务器,甚至不需要登录服务器就可以完成对服务器的管理。人们发现,通过容器管理集群可以抛弃传统的“SSH+秘钥”的连接方式来连接服务器,这对大规模集群来说是一个极大的变革。而且在速度上,容器技术在上百台服务器上启动应用只需要一眨眼的时间,这使得运维的工作大大减轻。

运维和开发在容器时代逐步“融为一体”,形成一个流水线车间的工作环境。这对于软件行业来说无疑是一次巨大的变革。

如果您也对传统的软件开发和运维的烦琐流程感到吃力,又对容器技术感兴趣,那么本书将是很好的入门书籍。

如果您不是职业的开发和运维人员,对Linux也不算熟悉,但属于一个对Docker感兴趣的极客,想通过Docker部署一些复杂的应用,本书也一样适合您。本书虽以Linux为平台介绍Docker的使用,但是与在Windows和Mac OS平台上的操作基本一致,普通用户完全可以把Docker当做一个“好玩的工具”来使用,体验Docker带来的便捷。

本书特色

·适合新手入门。本书在基础方面内容非常详尽,包括镜像的构建、容器的运行监控、网络的管理、仓库的应用、集群的部署等内容,全面、细致地介绍了Docker的基本使用方法与实现原理,适合新手入门。

·应用结合实际。本书在实战应用部分结合实际应用,从不同的角度分析问题并提出对应的解决办法,扩展了很多实用的实战技巧。实战部分根据不同类型的开发环境构建基础开发环境镜像,使读者可以直接使用Docker进入测试开发,并根据不同类型的应用部署做了详细介绍。

·范例丰富。在实战章节中的范例皆由浅入深,全面、实用且不缺乏趣味性,有助于读者了解其内部原理,进而应用到其他项目的思考与开发中。全书的代码均有指明出处以及链接,读者可以通过文中链接找到源代码。

·版本最新。本书使用目前流行的Docker 1.12版本,紧跟Docker更新步伐,介绍了新的Docker Swarm集群管理方式。

本书内容体系

第1篇 容器技术与Docker概念(第1~3章)

本篇主要介绍了容器技术的发展历史与容器技术的原理,并解释了Docker与其他容器技术的区别,对比了Docker与虚拟机的异同,客观地评价了两者的优缺点。另外,本篇还介绍了Docker分别在Linux、Windows和Mac OS系统下的安装方法,以及二进制安装方法。

第2篇 Docker基础知识(第4~10章)

本篇主要介绍了Docker的基本操作及简单应用,包括Docker基础、Docker镜像、Docker file文件、Docker仓库、Docker容器、数据卷的使用方法与原理及网络管理等内容。通过对本篇内容的学习,读者可以掌握最常用的Docker知识。

第3篇 Docker进阶实战(第11~19章)

本篇包含了许多Docker在实际开发中的应用实例,包括操作系统、编排工具Compose、Web服务器与应用、数据库、编程语言、Docker API、私有仓库、集群网络、Docker安全等内容,详细讲解了Docker在容器云环境中的应用。读者通过这部分内容的学习已经完全可以在实际生产环境中应用Docker了。

本书读者对象

·Dock开发入门人员;

·容器技术爱好者;

·各类运维人员;

·基于Docker构建云计算平台的技术人员;

·大、中专院校的学生;

·相关培训学校的学员。

本书配套资源及获取方式

本书涉及的源代码文件等配套学习资源需要读者自行下载。请读者登录机械工业出版社华章公司的网站www.hzbook.com,然后搜索到本书页面,按照页面上的说明进行下载即可。

本书作者

本书由黄靖钧主笔编写。其他参与编写的人员有张昆、张友、赵桂芹、晁楠、高彩琴、郭现杰、刘琳、王凯迪、王晓燕、吴金艳、尹继平、张宏霞、张晶晶、陈冠军、魏春、张燕、范陈琼、孟春燕、王晓玲、顼宇峰、肖磊鑫、薛楠、杨丽娜、闫利娜、王韶、李杨坡、刘春华、黄艳娇、刘雁。

本书的顺利出版,要感谢机械工业出版社华章公司各位编辑的辛勤劳动和付出,另外对网络上提供有益资料的众多作者也在此表示感谢。

虽然我们对本书中所述内容都尽量核实,并多次进行文字校对,但因时间所限,加之水平所限,书中疏漏和错误在所难免,敬请广大读者批评指正。第1篇 容器技术与Docker概念

◆第1章 容器技术

◆第2章 Docker简介

◆第3章 安装Docker第1章 容器技术

随着容器技术的长足发展,特别是Docker的流行,容器技术已经被越来越多的企业应用于生产环境中。在了解Docker之前,需要先了解一下容器技术。

本章将详细介绍容器技术,逐步认识容器的原理,并尝试启动简单的容器。在学习中了解容器技术的发展历程。

本章主要包括3部分:

·认识容器技术,了解容器技术的发展历程。

·了解容器技术的概念及基本原理。

·了解容器与容器云对软件行业的影响。1.1 什么是容器

容器技术并不是一个全新的概念,它又称为容器虚拟化。显然它是虚拟化技术中的一种。虚拟化技术目前主要有硬件虚拟化、半虚拟化和操作系统虚拟化等。本书讲述的容器虚拟化属于操作系统虚拟化,其相较于其他主流虚拟化技术更轻量。1.1.1 关于虚拟化

虚拟化技术的分类与定义在不同领域有不同理解。对于计算机领域,虚拟化技术主要分为两大类:一类基于硬件虚拟化,另一类基于软件虚拟化。硬件虚拟化并不多见,大都是半虚拟化与软件结合,应用较为广泛的则是基于软件的虚拟化技术。

基于软件虚拟化又可以分为应用虚拟化(如Wine)和平台虚拟化(如虚拟机)。本书中的容器技术属于操作系统虚拟化,属于平台虚拟化的一种。

从图1.1中可以看到,Docker属于容器技术的一种,而容器技术属于操作系统虚拟化的一种,有时这种分类会因为技术的发展而有变动。图1.1 容器技术在虚拟化技术的位置1.1.2 容器的定义

所谓容器,顾名思义就是用来放东西的道具。有意思的是,在Docker刚进入国内时,还有过一段时间在讨论Container这个单词是翻译为“容器”合适,还是翻译为“集装箱”合适。

之所以有人建议翻译为“集装箱”,并不仅仅是因为Docker的图标是一条鲸鱼驮着几个集装箱的形象(如图1.2所示),还因为容器技术本身就是借鉴了工业运输的经验发展而来。图1.2 容器技术与集装箱《经济学家》这样评价工业运输领域的集装箱:“没有集装箱,就不可能有全球化。”在1956年集装箱出现之前,货物运输缺乏标准,成本很高。特别是远洋运输。直到“集装箱”这个概念的出现,毫不起眼的集装箱降低了货物运输的成本,实现了货物运输的标准化,并以此为基础逐步建立全球范围内的船舶、港口、航线、公路、中转站、桥梁、隧道、多式联运相配套的物流系统,世界经济形态因此而改变。

同样,软件行业的容器技术也是在尝试打造一套标准化的软件构建、分发流程,以降低运维成本,提高软件安全与运行稳定等。与工业运输的集装箱不同,容器技术要复杂得多。它不仅仅是要打造一个运输用的“集装箱”,还要保证软件在容器内能够运行,在操作系统上打造一个“独立的箱子”。这需要解决文件系统、网络、硬件等多方面的问题。经过长时间的发展,容器技术已经逐步成熟,并在Docker的诞生下迎来它的繁荣时代。

读者大可把容器理解为一个沙盒,每个容器是独立的,容器之间可以相互通信。1.1.3 为什么使用容器

与传统软件行业的开发和运维相比,容器虚拟化可以更高效地构建应用,也更容易管理维护。举个简单的例子,常见的LAMP组合开发网站,按照传统的做法自然是各种安装,然后配置、测试、发布,中间麻烦事一大堆,相信不少读者深有体会。

当服务器需要搬迁时,往往需要再执行一次以前的部署步骤,极大地浪费了运维人员的时间。最可怕的是搬迁后往往因为一些不可预知的原因而导致软件无法正常运行,只能一头扎进代码中找Bug。

如果使用了容器技术,运维只需要一句简单的命令即可部署一整套LAMP环境,并且不需要复杂的配置与测试。即便搬迁也只是打包传输即可。即使在另一台机器上,软件也不会出现“水土不服”的情况。这无疑节约了运维人员的大量时间。

而对于开发者来说,一处构建,到处运行,大概是梦寐以求的事情。这也是很多跨平台语言的宣传标语之一。但不管是怎样的跨平台语言,在很多细节上都需要不少调整才能运行在另一个平台上。但容器技术则不一样,开发者可以使用熟悉的编程语言开发软件,之后用容器技术打包构建,便可以一键运行在所有支持该容器技术的平台上。

容器技术具有更快的交付和部署速度,而且相较于其他虚拟化技术,容器技术更加轻量。1.2 容器技术的前世今生

如果说工业上的集装箱是从一个箱子开始的,那么软件行业上的容器则是从文件系统隔离开始的。1.2.1 容器技术的起源

最早的容器技术大概是chroot(1979年)了,它最初是一个UNIX操作系统上的系统调用,用于将一个进程及其子进程的根目录改变到文件系统中的一个新位置,让这些进程只能访问到该目录。直到今天,主流Linux上还有这个工具。

打开一个终端,输入chroot–help,查看一下这个古老的命令。$ chroot --help 用法:chroot [选项] 新根 [命令 [参数]...]  或:chroot 选项 以指定的新根为运行指定命令时的根目录。 --userspec=用户:组 指定所用的用户及用户组(可使用“数字”或“名字”) --groups=组列表 指定可供选择的用户组列表,形如组1,组2,组3... --help 显示此帮助信息并退出 --version 显示版本信息并退出 If no command is given, run '${SHELL} -i' (default: '/bin/sh -i'). 请向bug-coreutils@gnu.org 报告chroot 的错误 GNU coreutils 的主页: GNU 软件一般性帮助: 要获取完整文档,请运行:info coreutils 'chroot invocation'

chroot这个命令主要用来把用户的文件系统根目录切换到指定的目录下,实现简单的文件系统隔离。可以说chroot的出现是为了提高安全性,但这种技术并不能防御来自其他方面的攻击,黑客依然可以逃离设定访问宿主机上的其他文件。1.2.2 容器技术的发展

2000年,由R&D Associates公司的Derrick T.Woolworth为FreeBSD引入的FreeBSD Jails成为了最早的容器技术之一。与chroot不同的是,它可以为文件系统、用户、网络等的隔离增加进程沙盒功能。因此,它可以为每个jail指定IP地址,可以对软件的安装和配置进行定制等。

紧接着出现了Linux VServer,这是另外一种jail机制,用于对计算机系统上的资源(如文件系统、CPU处理时间、网络地址和内存等)进行安全划分。每个所划分的分区叫做一个安全上下文(Security Context),在其中的虚拟系统叫做虚拟私有服务器(Virtual Private Server,VPS)。

在2004和2005年期间分别出现了Solaris Containers和OpenVZ技术,在可控性和便捷性上更胜一筹,如图1.3所示。图1.3 常见的容器技术

到了2006年,Google公司公开了Process Containers技术,用于对一组进程进行限制、记账、隔离资源(CPU、内存、磁盘I/O、网络等)。后来为了避免和Linux内核上下文中的“容器”一词混淆,而改名为Control Groups(简写为Groups)。2007年被合并到了Linux2.6.24内核中。

在前面Cgroups等技术出现以后,容器技术有了更快的发展。如图1.4给出了容器技术的发展史。图1.4 容器技术发展史

2008年出现了LXC(LinuX Containers),它是第一个最完善的Linux容器管理器的实现方案,是通过Cgroups和Linux名字空间namespace实现的。LXC存在于liblxc库中,提供了各种编程语言的API实现。与其他容器技术不同的是,LXC可以工作在普通的Linux内核上,而不需要增加补丁。

LXC的出现为后面一系列工具的出现奠定了基础。2011年CloudFoundry发布了Warden。不像LXC,Warden并不紧密耦合到Linux上,而是可以工作在任何可以提供隔离环境的操作系统上。它以后台守护进程的方式运行,为容器管理提供了API。

在2013年,Google公司发布了Lmctfy,它是一个Google容器技术的开源版本,提供Linux应用容器。Google启动这个项目,旨在提供性能可保证的、高资源利用率的、资源共享的、可超售的、接近零消耗的容器。Lmctfy首次发布于2013年10月。到了2015年,Google公司决定贡献其核心的Lmctfy概念,并抽象成libcontainer。现在为Kubernetes所用的cAdvisor工具就是从Lmctfy项目的成果开始的。

libcontainer项目最初由Docker发起,现在已经被移交给了开放容器基金会(Open Container Foundation)。

同年,dotCloud发布了Docker(Logo是一条鲸鱼驮着一堆集装箱,如图1.5所示)——至今最流行和使用最广泛的容器管理系统。在LXC的基础上,Docker进一步优化了容器的使用体验,使得容器更容易操作和管理。图1.5 Docker Logo(标志)

Docker提供了从构建、运行、管理、监控等一系列工具,引入了一整个管理容器的生态系统,包括高效分层的容器镜像模型、全局和本地的容器注册库、清晰的REST API、命令行等。这是Docker与其他容器平台最大的不同。在如图1.6中可以看到Docker跨越了多个层面,整合了一系列零散的工具从而达到一系列便捷的操作。这是当时Docker从众多容器技术中脱颖而出的一个重要原因。图1.6 一张图说明Docker的位置

围绕Docker的生态系统更有数不胜数的工具,极大地方便了开发者使用容器技术。关于Docker的更多特性,将在第2章介绍。

Docker开始阶段使用的也是LXC,之后采用自己开发的libcontainer替代了LXC。

之后出于各种原因,CoreOS启动项目Rocket,非常类似于Docker,但是修复了一些Docker中发现的问题。与Docker相比,Rocket是在一个更加开放的标准App Container规范上实现的。现今不少容器管理工具都支持Rocket与Docker。

2015年微软公司也在Windows Server上为其基于Windows的应用添加了容器支持,称之为Windows Containers,与Windows Server 2016一同发布。通过该实现,Docker可以原生地在Windows上运行Docker容器,而不需要启动一个虚拟机来运行Docker(Windows上早期运行Docker需要使用Linux虚拟机)。同年,Mac OS也原生支持运行Docker容器。如图1.7所示为官网给出的下载按钮。至此Docker完成了三大平台的适配。图1.7 Docker在2016年正式支持Windows 10与Mac OS

容器虚拟化技术经过几十年不断的发展与完善,相继加入了pivot_root等很多技术。市场上也出现了一些商业化的容器技术公司。在这些公司与全球开发者的共同努力下,容器技术得到不断推进和发展。最后核心容器技术进入了Linux的内核主线,再后来诸多大厂加入开发的libcontainer,使得如今人人皆可得心应手地操作容器。1.3 容器的原理

前文提到,容器的核心技术是Cgroups与namespace,在此基础上还有一些其他工具共同构成容器技术。容器本质上是宿主机上的进程。容器技术通过namespace实现资源隔离,通过Cgroups实现资源控制,通过rootfs实现文件系统隔离,再加上容器引擎自身的特性来管理容器的生命周期。

简单来说,本书所说的Docker的早期其实就相当于LXC的管理引擎,LXC是Cgroups的管理工具,Cgroups是namespace的用户空间管理接口。namespace是Linux内核在task_struct中对进程组管理的基础机制。1.3.1 从namespace说起

想要实现资源隔离,第一个想到的就是chroot命令。通过它可以实现文件系统隔离,这是最早的容器技术。但是在分布式的环境下,容器必须要有独立的IP、端口和路由等,自然就有了网络隔离。同时,进程通信隔离、权限隔离等也需要考虑到,因此基本上一个容器需要做到6项基本隔离,也就是Linux内核中提供的6种namespace隔离,如表1.1所示。表1.1 namespace说明

当然,一项完善的容器技术还需要处理很多工作。

对namespace的操作主要是通过clone()、setns()、unshare()这3个系统调用来完成的。

clone()可以用来创建新的namespace。clone()有一个flags参数,该参数以CLONE_NEW*为格式,包括CLONE_NEWNS、CLONE_NEWIPC、CLONE_NEWUTS、CLONE_NEWNET、CLONE_NEWPID和CLONE_NEWUSER,通过传入这些参数后,由clone()创建出来的新进程就位于新的namespace之中了。

因为Mount namespace是第一个实现的namespace,当初实现没有考虑到还有其他namespace的出现,因此用了CLONE_NEWNS的名字,而不是CLONE_NEWMNT之类的名字。其他CLONE_NEW*都可以看名字知用途。

那么,如何为已有的进程创建新的namespace呢?这就需要用到unshare()了,使用unshare()调用的进程会被放进新的namespace里面。而setns()则是将进程放到已有的namespace中,docker exec命令的实现原理就是setns()。

事实上,开发namespace的主要目的之一就是实现轻量级虚拟化服务,在同一个namespace下的进程可以彼此响应,而对外界进程隔离,这样在一个namespace下,进程仿佛处于一个独立的系统环境中,以达到容器的目的。

上面介绍的是一些概念,下面来实践一下。因为user namespace是在Linux内核3.8之后才支持的,所以本节讨论的namespace均是3.8以后的版本。1.查看当前进程的namespace

在了解namespace API之前,先来了解如何查看进程的namespace。在root用户模式下执行:# ls -l /proc/$$/ns total 0 lrwxrwxrwx 1 root root 0 6月 10 20:29 ipc -> ipc:[4026531839] lrwxrwxrwx 1 root root 0 6月 10 20:29 mnt -> mnt:[4026531840] lrwxrwxrwx 1 root root 0 6月 10 20:29 net -> net:[4026531956] lrwxrwxrwx 1 root root 0 6月 10 20:29 pid -> pid:[4026531836] lrwxrwxrwx 1 root root 0 6月 10 20:29 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 6月 10 20:29 uts -> uts:[4026531838]

这里的$$是指当前进程ID号。可以看到诸如4026531839这样的数字,表示当前进程指向的namespace。当两个进程指向同一串数字时,表示它们处于同一个namespace下。2.使用clone()创建新的namespace

创建一个namespace的方法是使用clone()系统调用,它会创建一个新的进程。为了说明创建的过程,给出clone()的原型如下:int clone(int(*child_func)(void *), void *child_stack, int flags, void*arg);

本质上,clone()是一个通用的fork()版本。fork()的功能由flags参数控制。总的来说,约有超过20个不同的CLONE_*标志控制clone()提供不同的功能,包括父子进程是否共享如虚拟内存、打开的文件描述符和子进程等资源。如果调用clone()时设置了一个CLONE_NEW*标志,一个与之对应的新的命名空间将被创建,新的进程属于该命名空间。可以使用多个CLONE_NEW*标志的组合。3.使用setns()关联一个已经存在的namespace

当一个namespace没有进程时还保持其打开,这么做是为了后续添加进程到该namespace。而添加这个功能就是使用setns()系统调用来完成,这使得调用的进程能够和namespace关联,docker exec就需要用到这个方法:int setns(int fd, int nstype);

·fd参数指明了关联的namespace,其指向了\proc\PID\ns目录下一个符号链接的文件描述符。可以通过打开这些符号链接指向的文件或者打开一个绑定到符号链接的文件来获得文件描述符。

·nstype参数运行调用者检查fd指向的命名空间的类型,如果这个参数等于数,将不会检查。当调用者已经知道namespace的类型时这会很有用。当nstype被赋值为CLONE_NEW*的常量时,内核会检查fd指向的namespace的类型。

要把namespace利用起来,还要使用execve()函数(或者其他的exec()函数),使得我们能够构建一个简单但是有用的工具,该函数可以执行用户命令。4.使用unshare()在已有进程上进行namespace隔离

unshare()和clone()有些像,不同的地方是前者运行在原有进程上,相当于跳出原来namespace操作,Linux自带的unshare()就是通过调用unshare()这个API来实现的。$ unshare Usage: unshare [options] [args...] -h, --help usage information (this) -m, --mount unshare mounts namespace -u, --uts unshare UTS namespace (hostname etc) -i, --ipc unshare System V IPC namespace -n, --net unshare network namespace For more information see unshare(1).

由于Docker没有使用这个系统调用,所以不展开。除此之外,像fork()这样的函数也可以实现namespace隔离,但并不属于namespace API的一部分。有兴趣的读者可以扫描以下二维码阅读相关资料。1.3.2 认识Cgroups

Cgrous是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如CPU,内存,I/O等)的机制。最初由Google公司的工程师提出,后来被整合进Linux内核。Cgroups也是LXC为实现虚拟化所使用的资源管理手段,可以说没有Cgroups就没有LXC。

目前,Cgroups有一套进程分组框架,不同资源由不同子系统控制。一个子系统就是一个资源控制器,比如CPU子系统就是控制CPU时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群(control groups)都受到这个子系统的控制。

Croups各个子系统作用如下。

·Blkio:为块设备设定输入/输出限制,比如物理设备(磁盘、固态硬盘、USB等)。

·Cpu:提供对CPU的Cgroups任务访问。

·Cpuacct:生成Cgroups中任务所使用的CPU报告。

·Cpuset:为Cgroups中的任务分配独立CPU(在多核系统)和内存节点。

·Devices:允许或者拒绝Cgroups中的任务访问设备。

·Freezer:挂起或者恢复Cgroups中的任务。

·Memory:设定Cgroups中任务使用的内存限制,并自动生成由那些任务使用的内存资源报告。

·Net_cls:使用等级识别符(classid)标记网络数据包,可允许Linux流量控制程序(tc)识别从具体Cgroup中生成的数据包。

·Net_prio:设置进程的网络流量优先级。

·Huge_tlb:限制HugeTLB的使用。

·Perf_event:允许Perf工具基于Cgroups分组做性能监测。

这样说理解起来也很吃力,下面就通过命令来挂载Cgroupfs。# mount -t cgroup -o cpuset cpuset /sys/fs/cgroup/cpuset

这个动作一般情况下已经在Linux启动的时候做了。

查看Cgroupfs:# cpuset ls cgroup.clone_children cpuset.memory_pressure_enabled cgroup.procs cpuset.memory_spread_page cgroup.sane_behavior cpuset.memory_spread_slab cpuset.cpu_exclusive cpuset.mems cpuset.cpus cpuset.sched_load_balance cpuset.effective_cpus cpuset.sched_relax_domain_level cpuset.effective_mems docker cpuset.mem_exclusive notify_on_release cpuset.mem_hardwall release_agent cpuset.memory_migrate tasks cpuset.memory_pressure

在主流Linux发行版下,都可以通过/etc/cgconfig.conf或者cgroup-bin的相关指令来配置Cgroups。mount { cpuset = /sys/fs/cgroup/cpuset; momory = /sys/fs/cgroup/momory; } group cnsworder/test { perm { task { uid = root; gid = root; } admin { uid = root; gid = root; } } cpu { cpu.shares = 1000; } }

然后通过命令行把一个进程移动到这个Cgroups之中。# mount -t group -o cpu cpu /sys/fs/cgroup/cpuset # cgcreate -g cpu,momory:/cnsworder # chown root:root /sys/fs/cgroup/cpuset/cnsworder/test/* # chown root:root /sys/fs/cgroup/cpuset/cnsworder/test/task # cgrun -g cpu,momory:/cnsworder/test bash

关于Cgroups子系统,本书不再过多讲述,读者可以扫描以下二维码找到很不错的学习资料,了解更多内容。1.3.3 容器的创建

前面只是非常简单地介绍了namespace和Cgroups两个概念。实际上各个namespace的具体介绍与各个Cgroups子系统的介绍都没有深入讲解到,但通过前面两节的学习,相信读者已经大致有了容器创建过程的雏形。(1)系统调用clone()创建新进程,拥有自己的namespace。

该进程拥有自己的pid、mount、user、net、ipc和uts namespace。# pid =clone(fun,stack,flags,clone_arg);(2)将pid写入Cgroup子系统这样就受到Cgroups子系统控制。# echo$pid >/sys/fs/cgroup/cpu/tasks # echo$pid >/sys/fs/cgroup/cpuset/tasks # echo$pid >/sys/fs/cgroup/bikio/tasks # echo$pid >/sys/fs/cgroup/memory/tasks # echo$pid >/sys/fs/cgroup/devices/tasks # echo$pid >/sys/fs/cgroup/feezer/tasks(3)通过pivot_root系统调用,使进程进入一个新的rootfs,之后通过exec()系统调用,在新的namespace、Cgroups、rootfs中执行/bin/bash。fun(){ pivot_root("path_of_rootfs/",path); exec("/bin/bash"); }

通过上面的操作,成功地在一个容器中运行了/bin/bash。1.4 容器云

每一项技术成熟后都会衍生出一系列技术,例如当Docker推开容器世界的大门时,围绕容器技术的生态系统迅速发展起来。无论是个人还是企业,在使用上都有各种各样的需求,例如跨主机连接容器,各种类型的负载均衡,持续构建、集成和交付,以及大规模容器管理等。

虽然Docker提供了较为便捷的操作方式,但是在开发、生产环境中,网络、存储、集群和高可用等问题层出不穷。仅凭Docker是无法做到面面俱到的。于是从容器到容器云就成了容器技术的必然发展路径。

国内现在以Docker容器云为“卖点”的初创公司不在百家之下,国外更是不用言说。可见围绕Docker容器云还有很多需要开发者去完善的地方。如图1.8展示了目前Docker的生态圈的一部分。可以看到这些工具围绕Docker进行扩展补充,已经形成了非常发达的生态系统网络。图1.8 容器技术生态圈

完整来说,容器云是以容器为资源分割和调度的基本单位,通过容器封装软件运行环境,为用户提供一个集构建、发布和运行于一体的分布式应用平台。它与IaaS、PaaS等不同,容器云可以共享与隔离资源、编排与部署容器。在这一点上容器云与IaaS相似。但是容器云也可以渗透到应用支撑与运行时环境,在这一点上与PaaS类似。

当然容器云并不是特指以Docker为基础的容器技术。使用其他容器技术(CoreOS的Rocket项目)实现容器云也是可以的。

后来的微服务(Microservices)和Serverless可以说是在容器技术基础上的突破性发展。微服Microservices在软件架构上可以将容器用于部署。微服务并不是一个新东西,只是一个相比标准的Web服务超快的轻量级Web服务。这是通过将功能单元(也许是一个单一服务或API方法)打包到一个服务中,并内嵌其到一个轻量级Web服务器软件中实现的。Docker与微服务的联手可以说打开了又一扇大门。1.5 容器与Docker

关于容器是否是Docker的核心技术在业内一直存在争议。Docker的核心是对分层镜像的创新使用,还是统一了应用的打包分发和部署方式,一直没有定论。之所以有这样的争议,是因为Docker的创新不一定要依赖容器技术,像基于传统的hypervisor也可以做到。

而且官方对Docker核心技术功能的描述“Build,Ship and Run”中也确实没有体现与容器相关的内容。但是毫无疑问,容器成就了Docker,而Docker也极大地促进了容器技术的发展。

实际上,从Docker公司的表现来看,它不会单纯地只是做一个CaaS(容器即服务)服务商。当前的Docker更像是一艘巨轮,野心其实不小,如图1.9所示。这也是Rocket项目诞生的一个重要原因。至于Docker能否引领容器领域或者是另有枭雄杀出一条血路,我们不妨拭目以待。图1.9 当前Docker就像是一艘巨轮1.6 本章小结

通过本章的学习,读者对容器的基本概念有了大致了解,对容器的运行原理和调用方法有了基本认识,也对容器技术的历史有了认识,了解了Docker在容器技术中的位置。第2章将揭开Docker的神秘面纱,认识这位出身“寒门”的“灰姑娘”是如何成为万众瞩目的“公主”的。第2章 Docker简介

第1章已经大致了解了容器技术,在本章节中,我们将进一步认识Docker的架构,以及了解Docker与其他容器技术的区别。

从本章开始将进入本书的重点,本章先了解Docker的架构,主要内容包括:

·Docker定义。

·Docker的优缺点与目的。

·Docker与其他容器技术对比。

·Docker与虚拟机对比。

·Docker基本架构。2.1 什么是Docker

Docker是一个开源的应用容器引擎,开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到主流的Linux/macOS/Windows机器上,实现虚拟化。

Docker是一个重新定义了程序开发测试、交付和部署过程的开放平台。在Docker的世界里,容器就是集装箱,我们的代码都被打包到集装箱里;Docker就是集船坞、货轮、装卸、搬运于一体的平台,帮你把应用软件运输到世界各地,并迅速部署。2.1.1 Docker的历史

2010年,几个年轻人在旧金山成立了一个叫做PaaS平台的公司,起名为dotCloud。什么是PaaS呢?PaaS的全称是Platform as a Service,也就是平台即服务。

传统的软件产品开发过程一般是这样的:(1)制定产品定位和需求。(2)制作界面原型。(3)搭建开发环境和技术栈。(4)构建基础技术框架和服务。(5)构建测试环境。(6)实现产品功能。(7)迭代开发/测试。

但是如果使用的是PaaS平台,可以直接忽略(3)、(4)、(5)这3个步骤。无论选择哪个技术栈,PaaS都会为你提供相关的配套设置,包括语言环境、运行环境、存储和各种基础服务。

dotCloud就是一个比较完善的PaaS平台。它把需要花费大量时间的手工工作和重复劳动抽象成组件和服务,并放到了云端,还提供了各种监控、警告和控制功能,方便开发者管理和监控自己的产品。

但是事实上开发者对开发环境和开发工具非常敏感并要求极高。PaaS的概念虽好,但是由于认知、理念和技术的局限性,市场的接受度并不高,市场的规模也不够大。此外,IBM、微软、Amazon、Google、VMware等巨头相继进场,可谓强敌林立,在这种情况下,dotCloud可以说举步维艰。

于是dotCloud决定把核心引擎开源,这个基于Linux Container技术的核心管理引擎一经开源立刻引起业界广泛关注。这个容器管理引擎大大降低了容器技术的使用门槛,轻量级、可移植、虚拟化、与语言无关,写了程序放上去做成镜像可以随处部署和运行,开发、测试和生产环境统一了,还能进行资源管控和虚拟化,就连众多巨头们也纷纷表示要接入或支持这个引擎。这个引擎就是Docker,用Go语言写成。

2013年10月dotCloud公司更名为Docker股份有限公司,2014年8月Docker宣布把PaaS的业务dotCloud出售给位于德国柏林的平台即服务提供商cloudControl,使得Docker公司集中更多的精力放到了Docker相关的研发上。

在随后的几年里,Docker快速发展成为了容器领域的“领头羊”。从Docker 1.9.0版本(2015年)开始,执行驱动默认改为libcontainer,这意味着Docker迈向了更广阔的舞台,也为2016年的发展奠定了技术基础。

时间迈入2016年,Docker 1.10.0发布,Docker Engine支持配置热更新,容器与Docker Daemon的耦合性大大降低。该版本Docker还划时代地支持了User namespace与seccomp,安全性极大提高,随着Registry升级,Docker的安全性已经十分接近虚拟机技术。

与此同时,传统的容器管理工具LXC也开始退出Docker的舞台,LXC伴随Docker接近三年的时间,终于被更完善的容器管理方案取代,同时Docker的飞速发展以及追求卓越的野心也一览无余。

Docker 1.11.0的发布,则改变了Docker原来的架构:由原来单一的二进制文件docker,拆分为4个不同的二进制文件构成,即docker、containerd、docker-containerd-shim和docker-runc。从这个版本开始,Docker在用户“毫无知觉”的情况下全面升级,成为首个完全兼容OCI(开放式容器协议)标准的运行时。该版本之后,Docker Engine完全基于runC和containerd。

Docker Engine负责镜像管理,containerd管理容器,包括容器的启动、停止、暂停和销毁。Docker Engine将镜像交付到containerd运行,containerd则使用runC来运行容器。鉴于容器运行时与引擎隔离,Engine能够重启和升级,无须重启容器。

此后又是一个划时代版本Docker 1.12,从这个版本开始,Docker原生支持编排功能,Swarm集群蜕变为SwarmKit,融入Docker Engine,内置负载均衡功能,还实现新的plugin命令来管理各种插件等。

总结Docker四年发展历程,不难发现Docker的野心。第一年专注软件构建,对接构建下游,营造镜像生态,良好的体验很快吸引了大批开发者;第二年瞄准服务容器管理,发布调度平台,打造交付流程,同时收紧了部分功能,加强控制容器市场;第三年大力整合企业资源,完善平台功能,着手应用编排,推出面向企业的Docker Cloud平台;到了第四年,在DevOps理念下,Docker一方面往上原生集成编排,挤掉Kubernetes和Mesos,另一方面往下,迈向OS化,发布libnetwork强化网络管理,排除第三方工具。

更多历史趣闻,读者可以扫描以下二维码继续阅读。2.1.2 Docker的现状

截至2016年08月,Docker已经成长为云计算相关领域最受欢迎的开源项目,Amazon、Google、IBM、Microsoft、Red Hat和VMware分别表示已经支持Docker技术。

有Linux的地方,就可以运行Docker,2016年6月Docker更是登录了Mac OS与Windows平台。

如图2.1所示,截至2016年10月1日,Docker在Github共有1507名开发者参与到了开发中,提交了接近三万次的commit。Docker的生态圈也非常活跃,在Github公开项目中,至少有11万个项目与Docker相关。图2.1 Docker项目在Github上十分活跃

如图2.2所示,在Docker 2016年度报告中,使用Docker的用户约九成是进行应用开发,接近八成是网页应用。从调查看,用户在开发和运维过程中获益最多,这也体现了Docker的理念。图2.2 78%是网页应用

如图2.3所示,在集成了Swarm之后的新版本Docker中,Docker启动一个新容器比Kubernetes快5倍,遍历所有容器比Kubernetes快7倍。图2.3 Docker与Kubernetes比较2.1.3 Docker的未来

Docker公司目前发力的三大方向都有了长足进步,即发展核心能力(libcontainer)、跨业务管理(libswarm)和容器间消息(libchan)。与此同时,通过收购Orchard labs,Docker公司表达了利用自身生态系统的意愿。但是,这不能仅仅关注Docker公司,这个项目的贡献者还来自于一些大牌公司,如谷歌、IBM和Red Hat。在Docker首席技术官Solomon Hykes的掌舵下,Docker公司和Docker项目的技术领先有着明确的联系。在项目初始的18个月里,它已经显示出通过自己的输出来快速前进的能力,并且没有减弱的迹象。

许多围绕Docker的创业公司试图找出已经由虚拟机普及而驱动的企业预期和现有Docker生态系统之间的差距(和机会)。在网络存储和细粒度的版本管理(用于容器中的内容)领域,现有Docker生态系统做得并不好,这就为初创企业和在职人员提供了机会。

随着时间的推移,虚拟机和容器(Docker中的“运行(run)”部分)之间的区别很可能变得不再那么重要,这将使注意力转到“构建(build)”“交付(ship)”方面。

值得注意的是,Docker公司绝对不会只想做一个引擎组件,集成Swarm可以说是Docker向Google这些巨头发出的挑战,Docker公司更倾向于平台化,企图打造工程技术界的“软件市场”。在这一点上,相信其他竞争者不会妥协,所以Docker容器技术的未来将与Docker公司的未来紧密关联。可见的未来里,Docker公司的策略依旧会是破坏向后的兼容性,因为其对Docker引擎本身的定位就是产品而非社区自有的服务组件。但是,不管结局如何,有一点可以肯定,那就是Docker必然给软件行业带来一次不寻常的革命,也许Docker不是笑到最后的赢家,但至少它是目前可见的最有力的竞争者。2.2 Docker的功能及优缺点

说了那么多,Docker到底可以用来做什么,或者说为什么要使用Docker?Docker与LXC或其他容器技术相比,优势在哪里?与虚拟机技术相比,Docker有哪些优势与不足?以上问题读完本节可以得到答案。2.2.1 Docker在解决什么

从表面看,最直观的一点是,以前开发软件时,各种依赖环境都要考虑到,开发好之后迁移到另一台机器上却不能运行,而Docker解决了运行环境和配置、依赖等问题,使软件发布迁移容易了许多。

第二点就是更轻量的虚拟化,节省了虚拟机的性能损耗,却得到了和虚拟机差不多的隔离环境。

第三点,用第1章提到的集装箱做比喻,在一艘大船上,集装箱可以把货物规整地摆放起来并且各种各样的货物被集装箱标准化了,集装箱和集装箱之间不会互相影响,因此就不需要专门运送水果的船和专门运送工业品的船了。只要这些货物在集装箱里封装好,那么就可以用一艘大船把它们都运走。在这一点上,Docker还解决了软件调度分发的问题。

第四点,更高的资源利用率。服务自身和依赖环境对资源的浪费,以及服务没有利用到的空闲资源往往是资源利用率低下的罪魁祸首。现实情况下资源被拆分成一台台计算机,服务也要跟着拆分。当服务的拆分不能保证和资源拆分相同的粒度时,空闲资源就产生了。

服务拆分的粒度越粗,与资源不匹配的矛盾会越激烈;拆分粒度越细,带来的资源浪费也就越多。另一方面,服务内聚提高会带来更高的耦合度和风险,反之会带来更高的部署和维护成本等。而Docker结合微服务带来了一个希望,以极小的代价换取极大的资源利用率。

总结起来就是,Docker带来了更高效的服务部署、启动方式、简化配置,在容器中开发完成后快速部署于各主流系统,解决了依赖问题;对CPU、内存、网络和文件系统的隔离使其成为可替代虚拟机技术的选项之一,机器资源利用率的提高,不需要为虚拟一个环境而耗费大量资源。

由于Docker本身带来了这两点好处,通过Docker和相关的生态系统,可以更简单地实现对系统的监控,把管理对象由“机器”改为抽象的“资源”,基于对资源的抽象,提供更灵活的服务部署、调度机制。这也改变了传统应用交付的方式,软件的开发和管理从部门间的装配和调试转换为部件的简单替换。软件的管理和共享从代码层次向应用层次上升,给了我们更多的选择自由性,使软件架构更加灵活。

其实,与其纠结于Docker在解决什么,不如拆分成两个问题:我们要做什么?Docker能帮我们做什么?2.2.2 为什么选择Docker

Docker作为一种新兴的虚拟化方式,与传统的虚拟化方式相比优势明显。

首先,Docker容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。其次,Docker对系统资源的利用率很高,一台普通的主机上可以同时运行数千个Docker容器。

容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。传统虚拟机方式运行10个不同的应用就要启动10个虚拟机,而Docker只需要启动10个隔离的应用即可。

对开发和运维人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。开发人员使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。

而这正是Docker可以做到的,Docker容器的运行不需要额外的hypervisor支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。

Docker容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人计算机、服务器等。这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个平台上。使用Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。2.2.3 Docker的缺点

Docker虽然日趋完善,但在某些方面依旧有着很明显的短板。最大的问题是安全性,Docker原来使用LXC作为默认的执行引擎,从Docker0.9之后采用libcontainer作为默认的执行引擎。Docker需要一个root权限的守护进程一直在主机上运行,不可避免会出现安全漏洞。

Docker对namespace过分信任,而namespace的攻击面比一般的Hypervisor要大,Xen在Linux里面有129个CVEs(Common Vulnerabilities and Exposures),与之相比它却有1279个。当然,这在某些情况下也是可以接受的,如在Travis CI里面以公有的方式来构建,但是在私有情况下和多用户的环境下,就显得比较危险了。

除此之外,Docker的网络一直是广大开发者不满的一个地方,尽管Docker在网络管理方面做了很多努力,但是容器技术的网络问题由来已久,这方面的薄弱不是Docker一己之力就能解决的。2.3 Docker和虚拟机

Docker与虚拟机经常被拿来作比较,相信在第1章中对容器技术的介绍已经使读者对容器的概念有了基本认识。相信读者也接触过虚拟机,两者的区别和关系,个人觉得并非是竞争,而是互补。2.3.1 Docker与虚拟机的区别

虚拟机和Docker最明显的差别是虚拟机需要安装操作系统(安装Guest OS)才能执行应用程序,而Docker内不需要安装操作系统。Docker技术不是在OS外来建立虚拟环境,而是在OS内的核心系统层来打造虚拟执行环境,通过共享宿主机OS的做法,取代一个一个Guest OS的功用。Docker也因此被称为是操作系统虚拟化技术。

如图2.4所示,因为Docker技术采取共享宿主机OS的做法,而不需在每一个Docker容器内执行Guest OS,因此建立Docker容器不需要等待操作系统开机时间,也不需要加载操作系统的额外进程。图2.4 容器技术与虚拟机技术对比

虚拟机(Virtual Machine)从操作系统层下手,目标是建立一个可以用来执行整套操作系统的沙盒独立执行环境。而Docker则是直接将一个应用程序所需的相关程序代码、函式库、环境配置文件都打包起来建立沙盒执行环境。

从隔离上来讲,虚拟机是用来进行硬件资源划分的完美解决方案,它利用了硬件虚拟化技术,通过一个Hypervisor层来实现对资源的彻底隔离;而容器则是操作系统级别的虚拟化,利用内核的特性实现,不需要外部辅助。2.3.2 Docker与虚拟机的优缺点

Docker虽然在很多方面优于虚拟机,但是作为一项传统的虚拟技术——虚拟机并非在Docker面前一无是处。

如表2.1中总结了使用Docker容器技术与传统虚拟机技术的特性比较。表2.1 Docker容器技术与虚拟机技术对比

在某些地方,例如Docker还无法胜任的地方,虚拟机还会继续发光发热,也许有一天容器会成为最流行的虚拟化技术,但不管如何虚拟机技术都不会消失。2.4 Docker与runC

在2013年Docker刚发布的时候,它是基于LXC的开源容器管理引擎。Docker把LXC复杂的容器创建与使用方式简化为自己的一套命令体系。

随着Docker的发展,原有的LXC不能满足Docker的需求(比如跨平台),于是Docker公司把底层实现都抽象化,底层容器的实现方式变成了一种可变的方案,这就是libcontainer的诞生。从此之后,无论是使用namespace、Cgroups技术或是使用systemd等其他方案,只要实现了libcontainer定义的一组接口,Docker都可以运行。2.4.1 libcontainer与runC

在DockerCon 2015期间,Docker牵头成立了OCI(Open Container Initiative开放容器计划)组织,这个组织的目的是建立起一个围绕容器的通用标准。

容器格式标准是一种不受上层结构绑定的协议,即不限于某种特定操作系统、硬件、CPU架构、公有云等,这样做的目的是减少因为行业内的恶性竞争,提供一个标准,允许任何人在遵循该标准的情况下开发应用容器技术,这使得容器技术有了一个更广阔的发展空间,OCI下的容器技术不属于任何公司或个人。

早期libcontainer是Docker公司控制的一个开源项目,随着OCI的成立,Docker把libcontainer项目移交给了OCI组织,目前可以在https://github.com/opencontainers/runc中查看libcontainer的源代码,目前libcontainer作为runC项目的一个子项目。

runC就是在libcontainer的基础上进化而来,Docker已经表明未来会使用runC替代libcontainer作为容器runtime的工具。

从名字上可以看出runC是一个runtime工具,而libcontainer只是一个lib库,不是runtime管理工具。runC通过调用libcontainer提供的接口来管理容器。早期runC没有出来之前,libcontainer有一个内置的小工具nsinit,可以用这个内置小工具来管理容器。后来runC基于这个小工具做了改动,并改名为runC。随着runC的不断发展,目前runC已经成为一个功能强大的runtime工具。当前,我们只需要知道runC的核心依旧是libcontainer就可以了。2.4.2 runC的使用

前面说过容器是提供一个与宿主机系统共享内核但与系统中的其他进程资源相隔离的执行环境。runC通过调用libcontainer包对namespaces、Cgroups、capabilities以及文件系统的管理和分配来“隔离”出一个上述执行环境,相当于一个去除了如镜像、Volume等高级特性的“简化版”Docker,runC以最朴素简洁的方式达到符合OCF标准的容器管理实现。

因为Docker是按照OCF(开放容器格式)开发的,所以runC可以读取运行Docker的容器。

runC运行时需要有rootfs,最简单的就是本地已经安装好了Docker,通过docker pull下载一个基本的镜像:$ docker pull busybox

使用docker create创建一个容器再使用docker export导出容器:$ docker export$(docker create busybox) > busybox.tar

接下来解压到rootfs目录:$ mkdir rootfs $ tar -C rootfs -xf busybox.tar

这样就可以用runC来启动一个基于OCF的容器了(这里runC并不依赖Docker,使用Docker只是为了方便建立一个rootfs)。

一个OCF容器应该包含config.json和runtime.json以及rootfs三大部分,所以还需要用runc spec命令来生成一份配置文件:$ runc spec注意:如果还没有安装runC,那么需要按照如下步骤安装。// 先在在 GOPATH/src 目录下创建一个文件夹名为 'github.com/opencontainers' 。 $ cd github.com/opencontainers $ git clone https://github.com/opencontainers/runc $ cd runc $ make $ sudo make install

完成上述步骤,就可以使用runC启动一个容器了:$ runc start2.4.3 runC原理

前面提到,runC就是libcontainer加上cli。(cli的开发包也是托管在Github上面的一个开源项目,地址为github.com/codegangsta/cli)。

libcontainer是Docker中用于容器管理的包,它基于Go语言实现,通过管理namespaces、Cgroups、capabilities以及文件系统来进行容器控制。runC的start实际上是调用libcontainer的方法实现的。

runC在Github的地址为https://github.com/opencontainers/runc。

先从main.go看起,在该文件中可以看到runC的基本命令只有常用的几个管理容器的命令,包括启动、创建、停止、删除、恢复、迁移等。// 代码地址:https://github.com/opencontainers/runc/blob/master/main.go#L93 app.Commands = []cli.Command{ checkpointCommand, createCommand, deleteCommand, eventsCommand, execCommand, initCommand, killCommand, listCommand, pauseCommand, psCommand, restoreCommand, resumeCommand, runCommand, specCommand, startCommand, stateCommand, updateCommand, }

因为runC核心部分还是libcontainer,所以runC实际上还是通过libcontainer的接口管理容器的。

而libcontainer的原理和LXC有些类似,但是比LXC更强大、整合度更高。libcontainer把容器技术的各种工具(namespace、cgroup、rootfs等)整合抽象,并向上层开放接口,使得像如Docker等工具可以轻松与内核打交道,如图2.5展示了libcontainer与其他技术在和Linux内核通信过程的异同。图2.5 Docker如何和Linux内核打交道

创建容器的时候,Docker收集信息存到config中,然后调用libcontainer的接口来实现容器的创建。runC也一样,不过把Docker自动收集信息这一步变成了手动操作,用户需要编写配置文件才能通过libcontainer启动一个容器(上文通过runc spec生成的是标准配置文件,事实上很多时候需要手动修改配置)。2.5 Docker基本架构

Docker是一个构建、发布、运行分布式应用的平台,Docker平台由Docker Engine(运行环境+打包工具)、Docker Hub(API+生态系统)两部分组成。Docker的底层是各种OS以及云计算基础设施,而上层则是各种应用程序和管理工具,每层之间都是通过API来通信的。2.5.1 Docker Client介绍

如图2.6所示,Docker引擎可以直观理解为就是在某一台机器上运行的Docker程序,实际上它是一个C/S结构的软件,有一个后台守护进程在运行,每次运行docker命令的时候实际上都是通过RESTful Remote API来和守护进程进行交互的,即使是在同一台机器上也是如此。图2.6 Docker模块工作流程

在使用docker version查看版本时,会看到有两大部分:Client和Server,其实这就是图2.6中的docker CLI(Client)和docker daemon(server)。$ docker version Client: Version: 1.12.1 API version: 1.24 Go version: go1.6.3 Git commit: 23cf638 Built: Thu Aug 18 05:02:53 2016 OS/Arch: linux/amd64 Server: Version: 1.12.1 API version: 1.24 Go version: go1.6.3 Git commit: 23cf638 Built: Thu Aug 18 05:02:53 2016 OS/Arch: linux/amd642.5.2 Docker daemon介绍

如前面所说,daemon就是一个守护进程,它实际上就是驱动整个Docker的核心引擎,在Docker0.9版本之前的Docker客户端和服务端是统一在同一个二进制文件中的,后来为了更好地对Docker模块进行管理,划分为四个二进制文件,分别是docker、containerd、docker-containerd-shim和docker-runc。

划分开之后,守护进程与容器管理不再互相牵制,这也使得Docker支持热更新,更人性化。2.5.3 Docker镜像

Docker镜像是Docker系统中的构建模块(Build Component),是启动一个Docker容器的基础。

下面通过一个官方提供的示意图(如图2.7所示)来帮助理解镜像的概念。图2.7 镜像是什么

Docker镜像采用分层的结构构建,最底层是bootfs,这是一个引导文件系统,一般用户很少会直接与其交互,在容器启动之后会自动卸载bootfs,bootfs之上是rootfs,rootfs是Docker容器在启动时内部可见的文件系统,就是日常所见的“/”目录。

Docker镜像使用到了联合挂载技术和写时复制技术,关于这些内容会在第5章有详细介绍。利用这两项技术,Docker可以只在文件系统发生变化时才会把文件写到可读写层,一层层叠加,这样不仅有利于版本管理,还利于存储管理。2.5.4 Docker容器

在Docker的世界中,容器是一个核心,容器是一个基于Docker镜像创建,包含为了运行某一特定程序所有需要的OS、软件、配置文件和数据,是一个可移植的运行单元。不过在宿主机看来,它只是一个简单的用户进程而已。关于容器的知识,在第8章会有详细介绍,在这里读者只需要知道容器是从镜像创建的运行实例,它是独立的一个沙盒即可。

容器很好地诠释了集装箱的理念,开发人员不用关心容器内部是什么应用,只管传输、运行即可,这是一种标准化的集装和运输方式,正是因为Docker把容器技术进行了体验友好的封装,才使得容器技术迅速推广普及。2.5.5 Docker仓库

相信大家对Github这个网站不会陌生,Github上有着海量的代码仓库,类似的,在Docker中,当开发者想要构建一个镜像或运行一个容器时,一般要先有一个现成的镜像才可以执行构建或者运行,而本地又没有该特定镜像时怎么办呢?Docker提出了Registry的概念,用户可以上传自己的镜像到Registry上,如果是公开的,那么全世界的用户都可以拉取这个镜像来操作,可以说Registry就是一个“软件商店”。类比传统运输业,Registry类似一种船坞、中转站一样,是一个集中存放“集装箱”(镜像)的地方。

Docker官方的Registry地址是https://hub.docker.com/。

除了这个官方的地址,用户还可以搭建自己的私有Registry用来存储非公开的镜像等,关于这部分内容会在后面详细讲解。2.6 本章小结

本章从Docker的历史讲起,使读者认识Docker的发展历程,然后解释Docker到底解决了什么,以至于短短几年内在云计算领域迅速崛起。然后又把Docker与虚拟机技术进行了比较,对比了两者的优缺点。之后对Docker的新引擎libcontainer做了剖析,使读者了解libcontainer的工作原理,最后还对Docker的整体架构做了诠释,在后续的章节中,将逐步对Docker的各个部分做详细讲解。第3章 安装Docker

经过前面两章概念性极强的阅读,相信读者已经对Docker有了一定认识,如果读者看不懂,或者带有大量疑问也不用担心,因为前两章主要是以一个“目录”的形式给读者们一个了解Docker技术原理的途径。如果读者有兴趣可以深入了解,如果没兴趣也不影响后面对Docker的使用。

从本章开始,将进入有趣的实践部分了。截至2016年10月,Docker已经原生支持Linux、Windows、Mac OS三大平台。本章将介绍在不同操作系统上安装Docker的方法。3.1 Linux系统

Docker基于Linux容器技术,面向服务器端,所以对Linux的支持无疑是最好的,主流的Linux系统都可以安装Docker。

Docker只能安装运行在64位计算机上(社区有对32位的支持),Linux内核版本必须大于3.10,内核小于3.10的系统会因为缺少Docker容器运行所需的功能而有错误。3.1.1 一键安装脚本

Docker官方提供了便捷的安装脚本,通过脚本自动完成安装。官网脚本一共有3种版本供用户选择,分别是最新的稳定版本、测试版本和实验版本。(1)安装稳定版本$ curl -sSL https://get.docker.com/ | sh // 或者 $ wget -qO- https://get.docker.com/ | sh(2)安装测试版本$ curl -fsSL https://test.docker.com/ | sh // 或者 $ wget -qO- https://test.docker.com/ | sh(3)安装实验版本$ curl -fsSL https://experimental.docker.com/ | sh // 或者 $ wget -qO- https://experimental.docker.com/ | sh

如果脚本在用户的Linux机器上无法运行,或者出现其他错误,可以继续往下看,下文有非脚本的手动安装教程。

如果安装时出现如下没有aufs的提示,用户可以安装内核扩展(Ubuntu系列)。$ sudo apt-get install linux-image-extra-'uname -r'

或者自己下载aufs编译安装,再或者等待10秒,安装脚本会使用替代方案安装Docker。$ sudo curl -sSL https://get.docker.com/ | sh modprobe: FATAL: Module aufs not found in directory /lib/modules/ 4.4.0-2-**-amd64 Warning: current kernel is not supported by the linux-image-extra-virtual package. We have no AUFS support. Consider installing the packages linux-image-virtual kernel and linux-image-extra-virtual for AUFS support. + sleep 10

具体发行版安装会有细小差别,如果不能完成自动安装可以使用下面方法手动安装Docker。3.1.2 Debian发行版

如前面所说,安装前确保机器为64位计算机,并且Linux内核在3.10以上。1.查看内核版本

要查看当前的内核版本,只需要打开一个终端,使用uname-r查看内核版本:$ uname -r 3.13.0-85-generic

如果内核版本不达到要求,需要升级内核。目前Debian一般都不用升级内核。$ sudo apt-get update $ sudo apt-get dist-upgrade $ sudo reboot2.更新APT源

打开一个终端,安装apt-transport-https包,使得APT支持HTTPS协议的源。$ sudo apt-get update && sudo apt-get install apt-transport-https ca-certificates

添加Docker源的gpg密钥。$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D3.添加Docker的官方APT软件源

Debian每次发行都有一个代号,使用下面命令可查看当前操作系统的代号。这里以Debian 8.0为例,返回的系统代号是wheezy。$ lsb_release -c Codename: jessie

·Debian testing代号为stretch/Sid。

·Debian 8.0代号为Jessie。

·Debian 7.7代号为Wheezy。

获得系统代号之后,通过命令创建/etc/apt/sources.list.d/docker.list文件(如果不存在就新建),并写入源的地址内容。注意修改为自己操作系统对应的代号。

创建/etc/apt/sources.list.d/docker.list文件(这里使用编辑器Vim,如果不熟悉Vim的操作,读者可以选择自己喜欢的编辑器进行编辑)。$ sudo vim /etc/apt/sources.list.d/docker.list

Debian Wheezy如下:deb https://apt.dockerproject.org/repo debian-wheezy main

Debian Jessie如下:deb https://apt.dockerproject.org/repo debian-jessie main

Debian Stretch/Sid如下:deb https://apt.dockerproject.org/repo debian-stretch main

添加成功后,更新APT软件包缓存。$ sudo apt-get update

校验软件包缓存结果。$ apt-cache policy docker-engine4.安装Docker

安装Docker之前,如果用户以前装过Docker,那么需要先完全卸载Docker再安装:$ apt-get purge "lxc-docker*" $ apt-get purge "docker.io*"

一切没问题之后,执行安装。$ sudo apt-get install docker-engine5.启动Docker$ sudo service docker start6.确认Docker运行正常$ sudo docker run --rm hello-world

返回Hello World表示运行正常。7.为非root用户授权

如果没有Docker用户组就建立一个Docker用户组(默认安装后自动创建)。$ sudo groupadd docker

增加当前用户到Docker组,需要注销来生效。$ sudo gpasswd -a${USER} docker

重启Docker服务。$ sudo service docker restart

这样,执行Docker命令就不必使用sudo申请权限了。3.1.3 Ubuntu发行版

Docker目前支持的最低Ubuntu版本为12.04LTS,但推荐用户至少使用14.04LTS版本。1.查看内核版本

要查看当前的内核版本,只需要打开一个终端,使用uname-r查看内核版本。$ uname -r 3.13.0-85-generic

如果内核版本不达到要求,需要升级内核。$ sudo apt-get update $ sudo apt-get install -y linux-images-generic-lts-raring linux-headers- generic-lts-raring $ sudo reboot2.更新APT源

打开一个终端,安装apt-transport-https包,使得APT支持HTTPS协议的源。$ sudo apt-get update && sudo apt-get install apt-transport-https ca-certificates

添加Docker源的gpg密钥。$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D3.添加Docker的官方APT软件源

Ubuntu/Debian每次发行都有一个代号,使用下面命令可查看当前操作系统的代号。这里以Ubuntu 14.04为例,返回的系统代号是trusty。$ lsb_release -c Codename: trusty

·Ubuntu 12.04(LTS)代号为precise。

·Ubuntu 14.04(LTS)代号为trusty。

·Ubuntu 15.04代号为vivid。

·Ubuntu 15.10代号为wily。

·Ubuntu 16.04(LTS)代号为xenial。

获得系统代号之后,通过命令创建/etc/apt/sources.list.d/docker.list文件(如果不存在就新建),并写入源的地址内容。注意修改为自己操作系统对应的代号。

创建/etc/apt/sources.list.d/docker.list文件(这里使用编辑器Vim,如果不熟悉Vim的操作,可以选择自己喜欢编辑器进行编辑)。$ sudo vim /etc/apt/sources.list.d/docker.list

Ubuntu 12.04(LTS)如下:deb https://apt.dockerproject.org/repo ubuntu-precise main

Ubuntu 14.04(LTS如下):deb https://apt.dockerproject.org/repo ubuntu-trusty main

Ubuntu 15.04如下:deb https://apt.dockerproject.org/repo ubuntu-vivid main

Ubuntu 15.10如下:deb https://apt.dockerproject.org/repo ubuntu-wily main

Ubuntu 16.04(LTS)如下:deb https://apt.dockerproject.org/repo ubuntu-xenial main

添加成功后,更新APT软件包缓存。$ sudo apt-get update

校验软件包缓存结果:$ apt-cache policy docker-engine4.安装Docker

安装Docker之前,如果用户使用的是Ubuntu 12.04可以先升级系统。$ sudo apt-get install linux-image-generic-lts-trusty $ sudo reboot

确保基本安装条件满足,如果用户以前装过Docker,那么需要先完全卸载Docker再安装。$ apt-get purge "lxc-docker*" $ apt-get purge "docker.io*"

然后再执行如下安装步骤。$ sudo apt-get update $ sudo apt-get install docker-engine 正在读取软件包列表... 正在分析软件包的依赖关系树... 正在读取状态信息... 将会同时安装下列软件: aufs-tools cgroupfs-mount 下列【新】软件包将被安装: aufs-tools cgroupfs-mount docker-engine 升级了 0 个软件包,新安装了 3 个软件包,要卸载 0 个软件包,有 6 个软件包未被升级。 需要下载 14.6 MB 的归档。 解压缩后会消耗 73.7 MB 的额外空间。 获取:1 http://cn.archive.ubuntu.com/ubuntu xenial/universe amd64 aufs- tools amd64 1:3.2+20130722-1.1ubuntu1 [92.9 kB] 获取:2 http://cn.archive.ubuntu.com/ubuntu xenial/universe amd64 cgroupfs- mount all 1.2 [4,970 B] 获取:3 https://apt.dockerproject.org/repo ubuntu-xenial/main amd64 docker- engine amd64 1.11.2-0~xenial [14.5 MB] 已下载 14.6 MB,耗时 3分 52秒 (62.5 kB/s) 正在选中未选择的软件包 aufs-tools。 (正在读取数据库 ... 系统当前共安装有 195748 个文件和目录。) 正准备解包 .../aufs-tools_1%3a3.2+20130722-1.1ubuntu1_amd64.deb ... 正在解包 aufs-tools (1:3.2+20130722-1.1ubuntu1) ... 正在选中未选择的软件包 cgroupfs-mount。 正准备解包 .../cgroupfs-mount_1.2_all.deb ... 正在解包 cgroupfs-mount (1.2) ... 正在选中未选择的软件包 docker-engine。 正准备解包 .../docker-engine_1.11.2-0~xenial_amd64.deb ... 正在解包 docker-engine (1.11.2-0~xenial) ... 正在处理用于 libc-bin (2.23-0ubuntu3) 的触发器 ... 正在处理用于 man-db (2.7.5-1) 的触发器 ... 正在处理用于 ureadahead (0.100.0-19) 的触发器 ... ureadahead will be reprofiled on next reboot 正在处理用于 systemd (229-4ubuntu6) 的触发器 ... 正在设置 aufs-tools (1:3.2+20130722-1.1ubuntu1) ... 正在设置 cgroupfs-mount (1.2) ... 正在设置 docker-engine (1.11.2-0~xenial) ... 正在处理用于 libc-bin (2.23-0ubuntu3) 的触发器 ... 正在处理用于 systemd (229-4ubuntu6) 的触发器 ... 正在处理用于 ureadahead (0.100.0-19) 的触发器 ... + sudo -E sh -c docker version Client: Version: 1.11.2 API version: 1.23 Go version: go1.5.4 Git commit: b9f10c9 Built: Wed Jun 1 22:00:43 2016 OS/Arch: linux/amd64 Server: Version: 1.11.2 API version: 1.23 Go version: go1.5.4 Git commit: b9f10c9 Built: Wed Jun 1 22:00:43 2016 OS/Arch: linux/amd64 If you would like to use Docker as a non-root user, you should now consider adding your user to the "docker" group with something like: sudo usermod -aG docker yourusername Remember that you will have to log out and back in for this to take effect!5.启动Docker$ sudo service docker start6.确认Docker运行正常$ sudo docker run --rm hello-world

返回Hello World表示运行正常。7.为非root用户授权

如果没有Docker用户组就建立一个Docker用户组(默认安装后自动创建)。$ sudo groupadd docker

增加当前用户到Docker组,需要注销来生效:$ sudo gpasswd -a${USER} docker

重启Docker服务:$ sudo service docker restart

这样,执行Docker命令就不必使用sudo申请权限了。3.1.4 Centos/Fedora发行版

Docker(重新编译自RHEL7)已收录在CentOS-Extras软件库内。用户只需执行以下安装命令即可。[root@VM_75_19_centos ~]# sudo yum install docker 已加载插件:fastestmirror, langpacks Loading mirror speeds from cached hostfile 正在解决依赖关系 --> 正在检查事务 ---> 软件包 docker.x86_64.0.1.10.3-46.el7.centos.10 将被 安装 --> 正在处理依赖关系 docker-common = 1.10.3-46.el7.centos.10,它被软件包 docker-1.10.3-46.el7.centos.10.x86_64 需要 --> 正在处理依赖关系 oci-systemd-hook >= 1:0.1.4-4,它被软件包 docker-1.10.3-46.el7.centos.10.x86_64 需要 --> 正在处理依赖关系 oci-register-machine >= 1:0-1.7,它被软件包 docker-1.10.3-46.el7.centos.10.x86_64 需要 --> 正在处理依赖关系 docker-selinux >= 1.10.3-46.el7.centos.10,它被软件包 docker-1.10.3-46.el7.centos.10.x86_64 需要 --> 正在检查事务 ---> 软件包 docker-common.x86_64.0.1.10.3-46.el7.centos.10 将被 安装 ---> 软件包 docker-selinux.x86_64.0.1.10.3-46.el7.centos.10 将被 安装 ---> 软件包 oci-register-machine.x86_64.1.0-1.7.git31bbcd2.el7 将被 安装 ---> 软件包 oci-systemd-hook.x86_64.1.0.1.4-4.git41491a3.el7 将被 安装 --> 解决依赖关系完成 依赖关系解决 ======================================================================= Package 架构 版本 源 大小 ======================================================================= 正在安装: docker x86_64 1.10.3-46.el7.centos.10 extras 9.5 M 为依赖而安装: docker-common x86_64 1.10.3-46.el7.centos.10 extras 61 k docker-selinux x86_64 1.10.3-46.el7.centos.10 extras 78 k oci-register-machine x86_64 1:0-1.7.git31bbcd2.el7 extras 929 k oci-systemd-hook x86_64 1:0.1.4-4.git41491a3.el7 extras 27 k 事务概要 ======================================================================= 安装 1 软件包 (+4 依赖软件包) 总下载量:11 M 安装大小:48 M Is this ok [y/d/N]: y Downloading packages: (1/5): docker-common-1.10.3-46.el7.centos.10.x86_64.rpm | 61 kB 00:00:00 (2/5): docker-selinux-1.10.3-46.el7.centos.10.x86_64.rpm | 78 kB 00:00:00 (3/5): oci-register-machine-0-1.7.git31bbcd2.el7.x86_64.rpm | 929 kB 00:00:00 (4/5): oci-systemd-hook-0.1.4-4.git41491a3.el7.x86_64.rpm | 27 kB 00:00:00 (5/5): docker-1.10.3-46.el7.centos.10.x86_64.rpm | 9.5 MB 00:00:01 ----------------------------------------------------------------------- 总计 7.9 MB/s | 11 MB 00:00:01 Running transaction check Running transaction test Transaction test succeeded Running transaction 正在安装 : 1:oci-register-machine-0-1.7.git31bbcd2.el7.x86_64 1/5 正在安装 : docker-selinux-1.10.3-46.el7.centos.10.x86_64 2/5 正在安装 : 1:oci-systemd-hook-0.1.4-4.git41491a3.el7.x86_64 3/5 正在安装 : docker-common-1.10.3-46.el7.centos.10.x86_64 4/5 正在安装 : docker-1.10.3-46.el7.centos.10.x86_64 5/5 验证中 : docker-common-1.10.3-46.el7.centos.10.x86_64 1/5 验证中 : docker-1.10.3-46.el7.centos.10.x86_64 2/5 验证中 : 1:oci-systemd-hook-0.1.4-4.git41491a3.el7.x86_64 3/5 验证中 : docker-selinux-1.10.3-46.el7.centos.10.x86_64 4/5 验证中 : 1:oci-register-machine-0-1.7.git31bbcd2.el7.x86_64 5/5 已安装: docker.x86_64 0:1.10.3-46.el7.centos.10 作为依赖被安装: docker-common.x86_64 0:1.10.3-46.el7.centos.10 docker-selinux.x86_64 0:1.10.3-46.el7.centos.10 oci-register-machine.x86_64 1:0-1.7.git31bbcd2.el7 oci-systemd-hook.x86_64 1:0.1.4-4.git41491a3.el7 完毕! [root@VM_75_19_centos ~]#

如果用户想采用一个较新版本的Docker,则有两个选择:(1)使用来自Fedora的组件。$ sudo tee /etc/yum.repos.d/docker.repo <<-'EOF' [virt7-docker-fedora-candidate] name=virt7-docker-fedora-candidate baseurl=http://cbs.centos.org/repos/virt7-docker-fedora-candidate/x86_64/os/ enabled=1 gpgcheck=0 EOF(2)使用来自RHEL的组件。$ sudo tee /etc/yum.repos.d/docker.repo <<-'EOF' [virt7-docker-el-candidate] name=virt7-docker-el-candidate baseurl=http://cbs.centos.org/repos/virt7-docker-el-candidate/x86_64/os/ enabled=1 gpgcheck=0 EOF注意:在系统上同时启用这两个软件库会混淆来自不同源头的组件而导致无法预知的后果。同时或许需要停用CentOS-Extras,以确保安装的组件是来自虚拟化SIG软件库。$ sudo yum install docker --disablerepo=extras

安装Docker后,必须引导该服务才能应用它。$ sudo systemctl start docker

若要开机时引导Docker服务:$ sudo systemctl enable docker

或者:$ sudo chkconfig docker on

可使用如下命令查看一下使用仓库安装的Docker信息。[root@VM_75_19_centos ~]# docker --version Docker version 1.10.3, build d381c64-unsupported

下面尝试使用官方的脚本安装,CentOS 7.1安装Docker。[root@VM_75_19_centos ~]# curl -sSL https://get.docker.com/ | sh + sh -c 'sleep 3; yum -y -q install docker-engine' warning: /var/cache/yum/x86_64/7/docker-main-repo/packages/docker-engine-selinux-1.12.1-1.el7.centos.noarch.rpm: Header V4 RSA/SHA512 Signature, key ID 2c52609d: NOKEY docker-engine-selinux-1.12.1-1.el7.centos.noarch.rpm 的公钥尚未安装 导入 GPG key 0x2C52609D: 用户ID : "Docker Release Tool (release docker) " 指纹 : 5811 8e89 f3a9 1289 7c07 0adb f762 2157 2c52 609d 来自 : https://yum.dockerproject.org/gpg setsebool: SELinux is disabled. If you would like to use Docker as a non-root user, you should now consider adding your user to the "docker" group with something like: sudo usermod -aG docker your-user Remember that you will have to log out and back in for this to take effect! [root@VM_75_19_centos ~]#

查看安装的Docker信息如下:[root@VM_75_19_centos ~]# docker info Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 1.12.1 Storage Driver: devicemapper Pool Name: docker-253:1-32927-pool Pool Blocksize: 65.54 kB Base Device Size: 10.74 GB Backing Filesystem: xfs Data file: /dev/loop0 Metadata file: /dev/loop1 Data Space Used: 11.8 MB Data Space Total: 107.4 GB Data Space Available: 19.54 GB Metadata Space Used: 581.6 kB Metadata Space Total: 2.147 GB Metadata Space Available: 2.147 GB Thin Pool Minimum Free Space: 10.74 GB Udev Sync Supported: true Deferred Removal Enabled: false Deferred Deletion Enabled: false Deferred Deleted Device Count: 0 Data loop file: /var/lib/docker/devicemapper/devicemapper/data WARNING: Usage of loopback devices is strongly discouraged for production use. Use '--storage-opt dm.thinpooldev' to specify a custom block storage device. Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata Library Version: 1.02.107-RHEL7 (2015-10-14) Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: bridge null host overlay Swarm: inactive Runtimes: runc Default Runtime: runc Security Options: seccomp Kernel Version: 3.10.0-327.el7.x86_64 Operating System: CentOS Linux 7 (Core) OSType: linux Architecture: x86_64 CPUs: 1 Total Memory: 993.1 MiB Name: VM_75_19_centos ID: A7RO:EEJV:V4K7:464M:PMPW:LLQA:CWCJ:L3Q6:V4OR:736I:ZQS2:7S3Z Docker Root Dir: /var/lib/docker Debug Mode (client): false Debug Mode (server): false Registry: https://index.docker.io/v1/ WARNING: bridge-nf-call-iptables is disabled WARNING: bridge-nf-call-ip6tables is disabled Insecure Registries: 127.0.0.0/8 [root@VM_75_19_centos ~]#

可以看到,从官方脚本安装的Docker比仓库里的要新,读者可以按情况安装。

在CentOS 6.5上安装Docker需要采用EPEL软件库。启用EPEL后,才能继续以下的安装程序。

要在CentOS 6上安装Docker,可利用以下指令安装docker-io组件。$ sudo yum install docker-io

如果不能直接安装docker-io,可利用EPEL软件库。$ rpm -i Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6- 8.noarch.rpm $ yum update -y

安装Docker后,必须引导该服务才能应用它。$ sudo service docker start

若要开机时引导Docker服务:$ sudo chkconfig docker on

查看版本信息:[root@VM_75_19_centos ~]# docker --version Docker version 1.7.1, build 786b29d/1.7.1

使用官方脚本安装:[root@VM_75_19_centos ~]# curl -sSL https://get.docker.com/ | sh + sh -c 'sleep 3; yum -y -q install docker-engine' If you would like to use Docker as a non-root user, you should now consider adding your user to the "docker" group with something like: sudo usermod -aG docker your-user Remember that you will have to log out and back in for this to take effect! [root@VM_75_19_centos ~]#

查看版本:[root@VM_75_19_centos ~]# docker --version Docker version 1.7.1, build 786b29d

目前CentOS 6.5的Linux内核版本是2.6.32:[root@VM_75_19_centos ~]# uname -a Linux VM_75_19_centos 2.6.32-504.30.3.el6.x86_64 #1 SMP Wed Jul 15 10:13:09 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

虽然可以安装,但是并不能使用Docker的全部功能。关于非root使用Docker的方法和前面一样,不再赘述。3.1.5 Arch Linux发行版

使用Arch Linux的用户不在少数,可以使用Arch Linux社区发布的Docker软件包进行安装,名字为docker,或者使用AUR包,名字为docker-git。

docker软件包将会安装最新正式版本的Docker。

docker-git则是由当前master分支构建的包,属于test版本。

Docker依赖于几个指定的安装包,核心的几个依赖包为bridge-utils、device-mapper、iproute2、sqlite。所以社区包安装很简单:$ sudo pacman -S docker

这样就安装了你所需要的一切。

如果想使用AUR的包,则执行:$ sudo yaourt -S docker-git

这里假设用户已经安装好了yaourt,如果之前没有安装构建过这个包,请参考Arch User Repository。

启动Docker。$ sudo systemctl start docker

设置开机启动:$ sudo systemctl enable docker

如果执行Docker info可以返回正确信息,那么Arch Linux已经成功安装并运行Docker了。3.1.6 Suse/openSUSE发行版

Docker支持openSUSE 12.3或更高版本。由于Docker的限制,Docker只能运行在64位的主机上。

Docker不被包含在openSUSE 12.3和openSUSE 13.1的官方镜像仓库中,因此需要添加OBS的虚拟化仓库来安装Docker包。

可执行下面的命令来添加虚拟化仓库。

openSUSE 12.3如下:$ sudo zypper ar -f \ http://download.opensuse.org/repositories/Virtualization/openSUSE_12.3/ \ Virtualization

openSUSE 13.1如下:$ sudo zypper ar -f \ http://download.opensuse.org/repositories/Virtualization/openSUSE_13.1/ \ Virtualization

在openSUSE 13.2版本以后就不需要添加额外的库了。

安装Docker包。$ sudo zypper in docker

启动Docker进程。$ sudo systemctl start docker

设置开机启动Docker。$ sudo systemctl enable docker

如果执行Docker info可以返回正确信息,那么openSUSE已经成功安装并运行Docker了。3.2 Windows与Mac OS系统

在Docker支持Windows平台之后,用户可以有两种方式安装Docker,一是传统的安装Linux虚拟机,然后在虚拟机里安装Docker;另一种是直接安装Docker for Windows。显然后一种原生应用更吸引人,但是Docker for Windows只支持Windows 10的64位专业版(企业版)或者Windows Server 2016。

本书不讲述使用Docker Toolbox安装Docker的方法,因为Docker Toolbox本质就是虚拟机,Docker Toolbox先在虚拟机里安装Linux,然后再在Linux上安装Docker。关于Docker Toolbox的文档,读者可以在https://docs.docker.com/toolbox/overview/上找到。

Mac OS版的Docker出现比Windows版早,目前Docker for Mac OS要求Mac OS版本大于10.10.3 Yosemite。因为用到新处理器的特性,还要求是2010年之后的Mac机器。3.2.1 在Windows上安装原生Docker

如果是Windows 10的64位专业版或企业版用户,那么可以直接安装原生Docker应用。

先从官网下载安装文件,打开https://docker.com之后往下拉就可以看到下载链接(如图3.1所示),其中有Windows和Mac OS版本,这里是稳定版的Docker,如果想体验测试版,可以选择Beta下载。

稳定版下载网址为https://download.docker.com/win/stable/InstallDocker.msi。

测试版下载网址为https://download.docker.com/win/beta/InstallDocker.msi。

下载之后双击打开,界面如图3.2所示,选择同意就可以安装了。图3.1 下载链接图3.2 安装界面

安装之后,打开Docker,可以看到状态栏有一个鲸鱼图标,表示Docker已经在运行了。如图3.3所示为打开Docker之后的界面。图3.3 Docker界面

选择About Docker可以查看Docker的版本,也可以在cmd中查看。PS C:\Users\samstevens> docker --version Docker version 1.12.0, build 8eab29e, experimental PS C:\Users\samstevens> docker-compose --version docker-compose version 1.8.0, build d988a55 PS C:\Users\samstevens> docker-machine --version docker-machine version 0.8.0, build b85aac1

在Windows下使用Docker和Linux完全一样,这得益于前面提到的libcontainer的封装抽象。下面通过一个Hello-World来验证Docker是否能正常运行。PS C:\Users\samstevens> docker pull hello-world PS C:\Users\samstevens> 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. 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.

运行正常,通过Docker可以在Windows上快速搭建一个基于Linux的Nginx环境。PS C:\Users\samstevens> docker run -d -p 80:80 --name webserver nginx Unable to find image 'nginx:latest' locally latest: Pulling from library/nginx fdd5d7827f33: Pull complete a3ed95caeb02: Pull complete 716f7a5f3082: Pull complete 7b10f03a0309: Pull complete Digest: sha256:f6a001272d5d324c4c9f3f183e1b69e9e0ff12debeb7a092730d638 c33e0de3e Status: Downloaded newer image for nginx:latest dfe13c68b3b86f01951af617df02be4897184cbf7a8b4d5caf1c3c5bd3fc267f

打开浏览器,输入http://localhost可以看到Nginx已经成功运行,如图3.4所示。图3.4 Nginx容器启动成功

在Windows下右击图标,在弹出的快捷菜单中提供了自动启动、自动检查更新、与Docker容器共享本地驱动器、使用VPN、管理Docker的CPU和内存使用、重启Docker、重置Docker等功能,如图3.5所示。在最新的Beta 26中还提供了Windows和Linux容器之间切换。

如图3.6所示,还可以在下面设置中设置仓库镜像地址,避免因为网络问题无法拉取镜像,详细设置方法见第7章。图3.5 右键快捷菜单

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

下载完整电子书

若在网站上没有找合适的书籍,可联系网站客服获取,各类电子版图书资料皆有。

客服微信:xzh432

登入/注册
卧槽~你还有脸回来
没有账号? 忘记密码?