本节书摘来自异步社区《Docker容器:利用Kubernetes、Flannel、Cockpit和Atomic构建和部署》一书中的第1章,第1.1节,作者: 【美】Christopher Negus(克里斯托弗•尼格斯)著,更多章节内容可以访问云栖社区“异步社区”公众号查看
第1章 使用Docker对应用进行容器化
Docker为应用程序的打包和运行提供了一种优雅的方式。使用喜欢的Linux系统,几分钟之内就能将Docker安装好并作为服务运行起来。构建、运行、停止、启动、调查、修改或者用其他的方式操作容器非常容易,说实话,很棒。
Docker的简单易用使其成为当今最流行的开源项目之一。但是作为数据中心容器化核心的Docker却引起了极大的震动,其潜力无异于重新发明了个人和公司(或大或小)创建、测试、部署和管理其最关键应用程序的方式。
使用容器化技术也可以让应用程序向云环境的部署变得更为高效。就像容器本身一样,运行容器的操作系统也能够被瘦身。因为容器已经持有应用程序运行所需的大部分依赖,所以这些用于容器的新型宿主机操作系统就不再需要包含所有依赖了。
本书不仅介绍什么是Docker以及Docker的工作方式,还揭示了特定用途下扩展Docker的若干方法。尽管一个容器的创建和部署是很简单的,但要让多个容器协同工作、访问其他容器的资源,以及访问运行容器的宿主机的资源,则需要更高的复杂性。本书给出了几种创建和部署这些复杂容器集的不同方法。
本书并不只停留在理论层面,其探讨的容器及容器相关工具的各个方面都备有说明这些特性工作方式的实际例子。读者可以自己先尝试一下,然后按照自己使用Docker的方式修改和扩展这些实例。
然而,在开始本书的学习之前,读者需要弄清楚关注容器的原因。
1.1 了解容器化应用的优缺点
Docker提供了一种创建和运行已经在容器中进行了配置的应用程序的方法。想要真正理解它,先了解容器化应用不是什么是很有帮助的。
1.1.1 容器化应用不是直接在宿主机上运行的应用
运行应用程序的传统方法会将应用程序直接安装到宿主计算机的文件系统上并从那里运行它。从应用程序的视角看来,其环境包含宿主机的进程表、文件系统、IPC设施、网络接口、端口及设备。
要让应用程序运行起来,通常需要安装与应用程序搭配的额外软件包。一般来说,这不是问题。但有些情况下,可能想在同一个系统上运行相同软件包的不同版本,这就可能会引起冲突。
应用程序与应用程序之间也会以某种方式发生冲突。如果应用程序是服务,它可能会默认绑定特定的网络端口。在服务启动时,它可能还会读取公共配置文件。这会导致无法在同一宿主机上运行该服务的多个实例,或者至少非常棘手;这还让那些想要绑定到同一端口的其他服务难以运行。
直接在宿主机上运行应用程序还有一个缺点,那就是难以迁移应用程序。如果宿主机需要关机或者应用程序需要更多计算能力——超出宿主机所能提供的,那么从宿主计算机上获取所有依赖并将其迁移到另一台宿主机上绝非易事。
1.1.2 容器化应用不是直接在虚拟机上运行的应用
创建虚拟机来运行应用程序能够克服直接在宿主机操作系统上运行应用程序所具有的缺点。虽然虚拟机位于宿主机上,但它作为独立的操作系统运行,它包括自己的内核、文件系统、网络接口等。这样可以很容易将几乎所有东西保存在独立于宿主机的操作系统中。
因为虚拟机是独立的实体,所以不会出现那种直接在硬件上运行应用程序所产生的缺乏灵活性的弊端。可以在宿主机上启动10个不同的虚拟机来运行应用程序10次。虽然每个虚拟机上的服务监听了同一个端口号,但是因为每个虚拟机拥有不同的IP地址,所以并不会引起冲突。
同样地,如果需要关闭宿主计算机,可以将虚拟机迁移到其他宿主机上(如果虚拟化环境支持迁移)或者直接关闭虚拟机并在新宿主机上再次启动它。
一个虚拟机运行一个应用程序的实例的缺点是耗费资源。你的应用程序可能只需要几兆字节磁盘空间来运行,但是整个虚拟机却要耗费许多GB的空间。再者,虚拟机的启动时间和CPU占用几乎肯定会比应用程序自身消耗的高得多。
容器提供了另一种在宿主机上或虚拟机内直接运行应用程序的方式,这种方式能使应用程序更快、可移植性更好,并且更具可扩展性。
1.1.3 了解容器的优点
就运行应用程序而言,容器有望灵活高效地使用资源。
灵活性来自容器可以包含其所需的全部文件。如同运行于虚拟机中的应用程序,其可以拥有自己的配置文件和依赖库,还可以拥有自己的网络接口——这些网络接口不同于宿主机上配置的那些网络接口。因此,与在虚拟机上运行应用程序一样,容器化应用比直接安装的应用程序更容易迁移,而且因为应用程序运行所栖身的每个容器均拥有独立的网络接口,所以也不会争用同一端口号。
就启动时间、磁盘空间占用和处理能力而言,容器既没有运行独立的操作系统,也没有包含运行整个操作系统所需的大量软件。这是因为容器只包含运行应用程序所需的软件,以及其他想随容器一起运行的工具和少量描述容器的元数据。
与虚拟机不同,Docker容器并不包含独立的内核(kernel)。Docker容器中运行的命令会出现在宿主机的进程表中,多数情况下,看起来非常像系统中运行的其他进程。然而,这两种环境中应用程序运行的差异与这两个应用程序所看到的不同世界有着极大的关系。
文件系统:容器拥有自己的文件系统,默认情况下,它无法看到宿主机系统的文件系统。该规则的一个例外是,有些文件(如/etc/hosts和/etc/resolv.conf)可能会被自动挂载到容器中。另一个例外是,当运行容器镜像时,可以显式地将宿主机的目录挂载到容器中。
进程表:Linux宿主机上可能运行着成百上千的进程。然而,默认情况下,容器内的进程无法看到宿主机的进程表,容器拥有自己的进程表。因此,你启动容器时所运行的应用程序,其进程在容器内被分配的PID为1。从容器内,进程无法看到宿主机上运行的其他进程——如果这些进程没有在容器内启动的话。
网络接口:默认情况下,Docker守护进程通过DHCP从一组私有IP地址集中确定IP地址。除了使用DHCP,Docker也支持其他网络模式,例如,允许容器使用其他容器的网络接口,直接使用宿主机的网络接口,或者不使用网络接口。依据你的选择,你可以将容器内的端口暴露给宿主机的同一端口或不同端口。
IPC设施:容器内运行的进程不能与宿主机系统上运行的进程间通信(IPC)设施直接交互。你可以将宿主机上的IPC设施暴露给容器,但这不是默认的。每个容器都有自己的IPC设施。
设备:容器内的进程无法直接看到宿主机系统上的设备。不过,当容器启动时可以设置一个特殊权限选项来授予该项权限。
如你所见,Docker容器可以在宿主机的视线内运行,但其运行方式限制了容器越过边界所能看到的宿主机内容(除非明确地开放了那些视图)。
1.1.4 了解容器化应用面临的挑战
容器化应用面临的挑战在于它们不同于那些不在容器中的应用程序。每个Linux系统中,用于启动和停止服务以及查看出错消息的设施已就位。Linux还提供了监控服务和轮换日志文件的方法。
对于运行虚拟机而言,整个虚拟化平台(如OpenStack和Red Hat企业虚拟化)被构建来启动、停止和使用虚拟机。虽然管理容器组的工具已在努力构建中,但大多数尚处于萌芽阶段。诸如Kubernetes和OpenShift这样的项目正在完成部署和管理容器组的框架。
Docker容器被打包为容器镜像。为了能将容器镜像保存在registry中并用docker命令管理它们,人们已经进行了大量的工作。然而,用于管理Docker镜像的工具远未像用来管理Linux软件包(如基于Linux RPM或Deb的系统)的工具那样成熟。
能够验证镜像来自何处的工具、确定镜像是否被篡改的工具以及查看容器中具体安装了哪些软件包和这些软件包的版本的工具才刚刚开发。目前,要意识到,多数情况下很难完全保证从Docker Hub Registry上随便获取的镜像可以安全使用。
使用容器的另一个挑战来自这样一个事实:就其本质而言,容器默认情况下无法看到其他容器。因此,要是你想让自己的容器与其他容器紧密配合要怎么办呢?例如,你可能有一个Web服务器,你想让这个服务器访问你的数据库服务器。
让容器看到彼此的一些解决方案是Docker中能让你将容器连接到一起的特性,以及让你在pod的容器之间识别出服务的使用方和提供方的Kubernetes的特性。更多容器管理工具正被推出来解决这些问题。但切记,它们尚处于早期开发阶段,而且容器管理的几乎各个领域都有多个工具在开发,有时还相互矛盾。