Docker 初学者指南
每家公司都依赖软件进行创新,而容器的发明是软件开发领域最大的创新之一。容器改变了如今软件的构建和交付方式。Docker 公司正是走在这条路上,让每个人都能使用容器。它凭借其强大的功能,让开发人员无后顾之忧。Docker 还通过消除开发和运营团队之间经常发生冲突的隔阂,促进了 DevOps 在企业中的应用。
今天,我们将介绍 Docker 的一些基础知识及其他内容。
Docker容器
现在,我们将从高层次概述为什么需要 Docker,以及它能为您做些什么。首先,我先来分享一下我是如何接触 Docker 的。在我之前的一个项目中,我需要搭建一个端到端的技术栈,其中包含各种不同的技术,例如使用 Node.js 的 Web 服务器、MongoDB 等数据库、Redis 等消息系统以及 Ansible 等编排工具。在开发包含所有这些不同组件的应用程序时,我们遇到了很多问题。首先,需要考虑的是它们与底层操作系统的兼容性,我们必须确保所有这些不同的服务都与我们计划使用的操作系统版本兼容。
有时,这些服务的某些版本与操作系统不兼容。我们不得不回头寻找另一个与所有这些不同服务兼容的操作系统。其次,我们必须检查服务与操作系统上的库和依赖项之间的兼容性。我们遇到过这样的问题:一个服务需要一个依赖库的版本,而另一个服务却需要另一个版本。
我们的应用程序架构随着时间的推移而发生变化,我们不得不升级这些组件到新版本,或者更改数据库等等。每次发生变化时,我们都必须经历同样的流程,检查不同公司和底层基础设施之间的兼容性。这种兼容性矩阵问题通常被称为“地狱矩阵”。
其次,每当有新的开发人员加入时,我们都发现搭建新环境非常困难。新开发人员必须遵循大量的说明,运行数百条命令才能最终完成环境的搭建。他们必须确保使用的操作系统和每个组件的版本都正确。而且,每个开发人员每次都必须自己完成所有设置。此外,我们还有不同的开发测试和生产环境。
一个开发人员可能习惯使用一个操作系统,而其他开发人员可能习惯使用另一个操作系统。因此,我们无法保证我们构建的应用程序在不同环境中能够以相同的方式运行。所有这些都让我们的工作变得非常困难。
所以我需要一种能够帮助我们解决兼容性问题的方法,允许我们在不影响其他组件的情况下修改或更改这些组件,甚至可以根据需要修改底层操作系统。最终,我找到了 Docker。
借助 Docker,我能够在单独的容器中运行每个组件,每个组件都拥有各自的库和依赖项,所有这些都运行在同一个虚拟机和操作系统上,但位于不同的环境或容器中。我们只需构建一次 Docker 配置,所有开发人员现在都可以通过一个简单的 Docker run 命令开始工作,而无需考虑他们运行的底层操作系统。他们只需确保系统上安装了 Docker 即可。
那么容器是什么?
容器是完全隔离的环境。它们可以拥有自己的进程或服务、自己的网络接口、自己的挂载点,就像虚拟机一样,只不过它们共享同一个操作系统内核。我们稍后会解释这意味着什么。但同样需要注意的是,容器并非 Docker 的新技术。
容器技术已经存在大约十年了。容器的类型包括 LXC、LXD、LXCFS 等。Docker 使用的是 LXC 容器。由于这些容器的级别非常低,因此设置起来非常困难。而 Docker 提供了一个高级工具,它拥有多项强大的功能,让像我们这样的最终用户能够轻松上手。
Docker 如何工作?
为了理解 Docker 的工作原理,我们首先回顾一下操作系统的一些基本概念。Ubuntu、Fedora、CentOS 等操作系统都由两部分组成:操作系统内核和一套软件。操作系统内核负责与底层硬件交互,而操作系统内核本身(在本例中为 Linux)保持不变,其上的软件才是这些操作系统的不同之处。
软件可能由不同的用户界面驱动程序、编译器、文件管理器、开发工具等组成。因此,您拥有一个在所有操作系统之间共享的通用 Linux 内核,以及一些用于区分不同操作系统的自定义软件。
我们之前说过,Docker 容器共享底层内核。共享内核究竟是什么意思?假设我们有一个安装了 Docker 的 Ubuntu 操作系统。Docker 可以在其上运行任何类型的操作系统。只要它们都基于相同的内核,在本例中是 Linux。如果底层操作系统是 Ubuntu,Docker 可以运行基于其他发行版(如 Debian、Fedora、Susi 或 CentOS)的容器。每个 Docker 容器仅包含我们之前讨论过的附加软件,这使得这些操作系统有所不同。
Docker 利用 Docker 主机的底层内核,该内核可与上述所有操作系统兼容。那么,如果操作系统不与 Windows 共享内核,那还有什么意义呢?因此,您无法在装有 Linux 操作系统的 Docker 主机上运行基于 Windows 的容器。要做到这一点,您需要在 Windows Server 上运行 Docker。
你可能会问,这难道不是一个缺点吗?不能在操作系统上运行另一个内核吗?答案是否定的。
因为与虚拟机管理程序不同,Docker 并非旨在在同一硬件上虚拟化和运行不同的操作系统和内核。Docker 的主要目的是将应用程序容器化,并将它们交付和运行。
虚拟机和容器之间的区别
这就引出了虚拟机和容器之间的区别,这是我们经常讨论的问题,尤其是那些有虚拟化背景的人。正如您在右侧看到的,就 Docker 而言,我们有底层硬件基础设施,然后是操作系统,以及安装在操作系统上的 Docker。Docker 可以管理仅使用库和依赖项运行的容器。
对于虚拟机来说,底层硬件上安装的是操作系统,然后是类似 ESX 或某种虚拟化技术的虚拟机管理程序,最后才是虚拟机。如你所见,每个虚拟机内部都有自己的操作系统,然后是依赖项,最后是应用程序。由于运行多个虚拟操作系统和内核,这种开销会导致底层资源利用率更高。虚拟机还会占用更多磁盘空间,因为每个虚拟机都很重,通常以 GB 为单位,而 Docker 容器则轻量级,通常以 MB 为单位。这使得 Docker 容器启动速度更快,通常只需几秒钟,而我们所知的虚拟机启动需要几分钟,因为它需要启动整个操作系统。
还需要注意的是,Docker 的隔离性较差,因为容器之间共享更多资源(例如内核),而虚拟机彼此之间完全隔离。由于虚拟机不依赖于底层操作系统或内核,因此您可以在同一个虚拟机管理程序上运行不同类型的操作系统,例如基于 Linux 或基于 Windows 的操作系统。然而,在单个 Docker 主机上却无法做到这一点。因此,以上就是两者之间的一些区别。
那么,如何实现呢?目前,市面上有很多容器化版本的应用程序。大多数组织都已将其产品容器化,并在名为 Docker Hub 或 Docker Store 的公共 Docker 镜像仓库中提供。例如,您可以找到最常用操作系统、数据库以及其他服务和工具的镜像。找到所需的镜像后,即可在主机上安装 Docker。启动应用程序堆栈非常简单,只需运行 Docker run 命令并传入镜像名称即可。
在这种情况下,运行 Docker run Ansible 命令将在 Docker 主机上运行 Ansible 实例。同样,使用 Docker Hub 命令运行 MongoDB、Redis 和 Node.js 实例。运行 Node.js 时,只需指向主机上代码仓库的位置即可。如果需要运行 Web 服务的多个实例,只需根据需要添加任意数量的实例,并在前端配置某种负载均衡器即可。如果其中一个实例发生故障,只需销毁该实例并启动一个新实例即可。还有其他解决方案可用于处理此类情况,我们稍后会讨论。我们一直在讨论镜像和容器。
让我们了解一下两者的区别。镜像是一个包或模板,就像您在虚拟化世界中可能使用过的虚拟机模板一样。它用于创建一个或多个容器。容器是运行镜像的实例,这些实例彼此隔离,拥有各自的环境和进程集。
正如我们之前所见,许多产品已经 Docker 化。如果您找不到所需的镜像,可以自行创建镜像并将其推送到 Docker Hub 仓库,使其可供公众使用。
回顾一下,传统上,开发人员开发应用程序。然后,他们将其交给运维团队在生产环境中部署和管理。运维团队会提供一系列说明,例如如何设置主机、主机上需要安装哪些先决条件以及如何配置依赖项等信息。
运维团队会使用这份指南来设置应用程序。由于运维团队并非独立开发应用程序,因此设置起来非常困难。遇到问题时,他们会与开发人员合作解决。使用 Docker,设置基础设施的大部分工作现在以 Dockerfile 的形式由开发人员完成。开发人员之前构建的用于设置基础设施的指南现在可以轻松地合并到 Dockerfile 中,用于创建应用程序的镜像。
此镜像现在可以在任何容器平台上运行,并且保证在所有地方都能以相同的方式运行。因此,运维团队现在可以直接使用该镜像来部署应用程序。由于该镜像在开发人员构建时就已经可以运行,并且运维团队不会对其进行修改,因此它在部署到生产环境中时仍能以相同的方式运行。要了解更多关于容器的信息,请查看我的其他课程“ Docker 入门”