容器并不能解决一切问题

时间:2022-10-12 10:57:08

容器化在开发和运维领域掀起了一场风暴。在过去,部署是高度依赖于特定技术的,通常需要对每个项目进行大量不可重复的工程工作。你是否部署到 VPS?你是否在分发虚拟机镜像?静态可执行文件?需要特定解释器的脚本? 根据你对这些问题的回答,你可能已经使用了 Capistrano、Puppet、shell 脚本、Ansible、deb 或 rpm 包、cloud-init 脚本、专有云技术、upstart、systemd、init 等很多技术。在部署阶段,系统管理和开发之间的界限就变得模糊了,DevOps 的原则就诞生了。随着 DevOps 开始成熟,业界发展出了应用开发的最佳实践,比如 12 因素应用程序方法论,但许多实现细节仍然是依赖于特定技术的。

1、进入 Docker


容器并不能解决一切问题

使用 Docker 打包和部署

然后 Docker 出现了,并通过如下简单的规则使应用程序的部署产品化:如果你的应用程序可以打包成一个容器,那么它就可以部署在任何地方。容器并不是什么新鲜事——毕竟,谷歌已经使用它们很多年了。Unix 黑客也曾出于类似目的使用 Solaris Zones 和 FreeBSD jail。然而,在 Docker 出现之前,还没有一个很好的方式可以轻松地将应用程序打包到一个可移植的容器中。Docker 彻底改变了我们部署应用程序的方式。

Docker 解决了许多重要的部署问题,所以接下来要问的问题是 Docker 是否为开发提供了任何优势。拥有一个看起来(至少大体看起来)像生产环境的开发环境有很多好处。如果你在生产环境中部署 Docker 容器,那么在开发过程中在容器中运行代码也是合理的。此外,Docker 还解决了版本依赖关系的问题。例如,如果你有一个应用程序需要 MySQL 5.3,而另一个应用程序需要 MySQL 5.7,那么你就不需要在本地运行两个版本,也不需要在各自的虚拟机中运行每个版本。你可以为每个版本使用一个容器,它们可以在几秒钟内启动和停止。

使用 Docker Compose 进行开发

容器并不能解决一切问题

2013 年底,Docker Compose(当时称为 fig)进入了这个领域。Docker Compose 有一个简单的前提:与使用一次性脚本启动和停止应用程序及其在开发中的依赖不同,你把它们描述为 YAML 文件中的 Docker 容器,并让 Docker Compose 管理它们的生命周期。它提供了一些额外的细节,如为 12 因素应用程序提供日志采集、环境变量以及基本容器网络。简而言之,Docker Compose 对那些想要使用容器化的方法开发 12 因素应用程序的开发人员来说是一种完美工具。

乍一看,Docker Compose 似乎是本地开发的理想解决方案——在许多情况下,它确实是。然而,就像它的名字一样,它只关注那些一切都在 Docker 内部运行的开发工作流。在某些情况下,这样做很好。例如,如果你在 Node.JS 中编写一个依赖于 Postgres 的 API,那么你可以在 nodejs 容器中运行代码(可能在它前面有一个文件监视器),在 Postgres 容器中运行 Postgres。然而,并不是所有的开发工作流都可以被容器化。无论是为了性能、易于与主机操作系统特性集成,还是其他许多原因,有时最好将开发环境的某些部分作为本地进程运行,而将其他部分作为容器运行。你仍然需要拼凑一个解决方案,以将非 Docker 部分与一些 Docker 容器进行集成。

此外,考虑到 Docker 依赖于 Linux 内核特定的特性来实现容器,macOS、Windows、FreeBSD 和其他操作系统的用户仍然需要虚拟化层。我们想要通过使用容器来摆脱的一系列复杂的网络、文件同步和虚拟机管理等问题仍然存在。当然,它们通常是可以工作的——直到出现问题,这时我们就只剩下谷歌、Stack Overflow 和 GitHub 来帮助我们找到解决方案。

2、现代开发:云和微服务



容器并不能解决一切问题

云原生开发的复杂性

快进到 2021 年,大多数生产级应用也依赖于云基础设施,这些基础设施不能作为本地 Docker 容器运行,因此我们面临一系列新的问题,每个问题都需要权衡:

  • 我们是否将云服务存根?这种方法成本低、性能好,但除了非常简单的服务外,维护本地存根所需工程量很高。
  • 每个开发人员是否都有自己的每个云资源实例?这通常代价高昂,公司必须支付很高的成本来保留很少使用的基础设施。无服务器产品通常比预留产品有更好的成本模型,但仍然必须考虑成本。
  • 开发人员是否共享共同的开发基础设施?在此选项中,基础设施成本降低了,但通常需要额外的工程量,以便多个应用程序可以共享相同的数据库和其他有状态服务而不会发生冲突。换句话说,每个应用程序都必须支持多租户。

以上选项在不同的场景中都是可行的,但这里要说的是采用 Docker 或者 Docker Compose 并不能解决问题——甚至不能指出哪个选项是最好的!现代开发环境编排器必须具有云感知能力并支持不同的运行时架构。目前,基础设施即代码工具最接近解决这个问题,但由于它们专注于生产部署,因此无法与本地开发环境顺利集成。

除了云服务,微服务还具有它们自身的复杂性,这些复杂性是“仅仅使用 Docker”无法解决的。任何采用了微服务策略的大型组织都会迅速发展到任何开发人员都可以在其笔记本电脑上运行该组织所有服务的地步。像 Telepresence 这样的工具有助于将本地容器连接到远程 Kubernetes 集群中运行的容器,但我们仍然缺乏能够跨本地和远程环境透明地处理服务发现、代理和身份验证等问题的高级工具。而且,现有的工具大多是以 kubernetes 为中心的,这给很多开发人员增加了使用难度。

3、下一步是什么?


我们的行业在过去十年中取得了令人难以置信的进步,这在一定程度上要归功于 Docker、Docker Compose 和 Kubernetes 等技术。然而,我们仍在研究如何在我们所处的多样化环境中进行开发。下一代开发工具必须能够处理本地进程、Docker 容器、云服务,甚至其他团队的微服务的构建和运行。针对所有这些问题,我们还没有答案,但我们正在构建 exo,以帮助像我们这样的开发者克服本地开发的复杂性。