查看原文
其他

Docker 开发环境的滑坡

​Micah Adams CSDN云计算 2020-10-16

作者 | Micah Adams

 责编 | 徐威龙

封图| CSDN 下载于视觉中国

最近,我构建了一个本地开发环境,该环境使用 Docker 进行一些关键的集成测试。 在我要完成这项工作时,我意识到在开始这项工作之前,我没有考虑到这么做的一些意义深远影响,如:
  • 它要求开发人员在其本地计算机上安装 docker 和 docker-compose (命令行工具)。
  • 为了让环境可以正常使用,需要大量的配置。
  • 我需要编写 shell 脚本来“缓解”某些配置问题。
  • 我编写的 shell 脚本最终也有些局限ーー它在某些环境中工作得很好,但是如果你在 Windows 系统上工作,你就得靠自己了。
  • 我一天中的大部分时间都要用来排查一些数据库连接问题,结果发现我容器的数据库没有配置正确。
在这方面投入了大量的时间,最终使我的团队受益,并最终帮助我们解决了集成测试中遇到的一些难题。但是更让我感兴趣的是它所带来的麻烦,更不用说在最终合并之前我提交的 pull 请求时引发的热烈讨论了。
此外,这种环境最终只有一个目的——提供集成测试环境,而不是像我最初希望的那样,提供一套完整的开发环境。最终的结果是,我们将这个环境从开发人员的机器上移开,并最终将其部署到云提供商的一个容器化列表中,以创建一个集成测试资源。
我的努力基本上是失败的,尤其是考虑到我最初的动机。
难道我误入歧途了?我所有的努力工作只换来一个花哨的测试环境? 
我决定更深入地研究基于容器的开发环境的问题,从那以后我所学到的东西极大地改变了我将来处理这个问题的方式。


容器的当前状态

 

大量的调查向我们证明,使用 Docker 的人数在持续增加,特别是随着基础设施的增长和变得更加复杂之后。2018 年 6 月 来自 DataDog的一项调查显示,大约25% 的公司使用 Docker 部署了某种形式的基础设施。从 2017 年到 2018 年,部署的规模增加了75% 。根据这些消息来源, Docker “革命”正在全面展开,没有减缓或停止的迹象。(我仍然很好奇 这75% 中的大多数公司在他们的部署中使用了什么?抱歉,我跑题了。)
调查内容:https://portworx.com/wp-content/uploads/2019/05/2019-container-adoption-survey.pdf
来自 DataDog 的调查:https://www.datadoghq.com/docker-adoption/
2018 年的 DataDog 调查也提到了使用最广泛的 Docker 镜像是“ Nginx,Redis 和 Postgres”。这对我来说很有意义,因为运行应用程序依赖项的容器似乎是容器的第一步。Docker Compose 为多容器应用程序提供了一个相对简单的工具; 它似乎也是一个很好的工具,允许开发人员为自己的环境运行特定的、底层的基础设施。也就是说,你要为你的项目设置了一个 `docker-compose.yml` 文件即可。 
这 25% 的公司在生产环境中运行 Docker,究竟有多少公司使用 Docker 作为开发工具呢?2019 年 Stack Overflow 调查报告显示,38.4% 的受访者使用容器进行开发工作,但目前约有一半的受访者没有使用任何容器技术。我想知道是否有一种方法可以进一步理解为什么开发人员不像我最初想象的那样经常使用 Docker。我决定再深入挖掘一下,粗略地研究一下开发人员对 Docker 的看法。
许多开发人员讨厌自己的 Docker 环境,这是有充分理由的——引入容器似乎会减慢开发人员与他们所构建的环境之间的反馈周期。容器化开发环境似乎也为操作员创建了一个不必要的抽象,这个操作员需要能够直接深入到代码、执行期函式库、甚至较低级别的操作系ーー所有这些都是在构建一个特性的过程中。
支持将 Docker 作为开发工具的人声称,这样做有明显的的好处。使用容器的开发环境也会导致整个开发团队实现对等。
如果每个人都使用容器作为他们的数据库、缓存或其他杂项基础设施,那么设置编写代码应该和运行 `docker-compose up` 一样简单,你就可以拥有一个完整的开发环境。假设你的团队愿意在本地运行容器,那么你将永远不会在开发环境和生产环境之间造成差异。
当运行 `brew upgrade`对其进行升级时,不会有啥意外——容器将始终与你的需求保持同步。 
坦白地说,我同情这两个群体。作为一个开发者,一只脚坚定地站在房子的运营方面,我认为运行容器的好处是巨大的。然而,我并不认为这些好处完全适用于开发人员工作流。我相信在开发环境中使用 Docker 的经验之间存在差异,因为 Docker 不是开发人员的工具。
然而,我不认为这意味着开发团队不应该考虑利用一些 Docker 来满足他们自己的需求。但是我觉得将 Docker 作为另一个操作工具来处理可以帮助减轻在本地开发环境中运行 Docker 的痛苦。
 

容器是开发人员友好的抽象吗?

 

一个容器,就 Docker  而言: 

是一种标准的软件单元,可以将代码及其所有依赖关系打包,使应用程序能够快速可靠地从一个计算环境运行到另一个计算环境上。

下面是一个稍微明晰一些的定义:

容器是应用层的一个抽象,它将代码和依赖关系打包在一起。

听起来不错,对吧? 
是的,特别是当你试图部署代码的时候,你会发现的确如此。换句话说,如果我主要关心的是让我们的代码在任何地方都能毫无意外地运行,那么容器似乎是目前最好的抽象——我并不真的需要了解我们正在运行的代码,相反,我需要对我们将如何运行它有一个可预测性。作为一个操作人员,这点非常棒。
但是,作为一个开发人员,这种抽象可能会带来一些麻烦。容器并不真正关心自己在运行什么。操作系统是有目的地抽象出来的,运行容器所必需的任何依赖项也是如此。应用程序层本身和底层操作系统一样短暂,访问这些抽象层需要了解 Docker 希望以何种方式运行代码。 
尽管我已经谈到了容器的预期用途,但我认为说容器只是团队运营的东西的说法是错误的。我认为开发人员可以从容器化开发环境中受益。问题在于构建一个真正的开发人员友好的、基于容器的工作流并不容易。
 

基于 docker 的开发环境的常见缺陷


最后,我选择在自己的开发工作中多次使用 Docker。这对我来说很有效,尤其是对于我每天所做的工作来说。在 Test Double,更重视 Dev Ops 和 SRE,我在这里每天都和容器打交道。
当然,这可能不适合你的团队。但是,如果你确实希望在开发环境中使用 Docker 进行,我会提醒你注意一些我亲身经历过的常见陷阱。
  • 假设容器化只有优点 

在容器化的开发环境中,最大的陷阱可能是假设你在部署中获得的好处与开发人员在本地体验到的好处是一样的。
类似地,假设一个团队希望与 Docker 密切合作,这种假设可能不适用于你的团队。如果你的开发人员与操作工作相对孤立,那么他们可能不希望每天都在本地使用容器,这可能不是一个严谨的假设。但是,如果你处在一个开发人员正在进行一些操作工作的团队中工作,那么假设你提供了仅仅是容器化开发环境的其他替代方案,那么这对你的团队有好处。
在本地运行容器会消耗大量资源。仅在我的机器上,在一个典型的工作日,Docker 就要消耗大约 36GB 的存储空间。我不会说对于我的特定品牌和型号的工作站来说系统使用量是非常大的,但是我可以很容易地看出,当我在工作流中包含更多的容器时,系统使用量会大大增加。在我的活动监视器中,Docker 也是占用 CPU、内存和磁盘资源最多的。 
更重要的是,尽管这可能不会给我的机器带来沉重的负担,但这并不意味着它与其他机器很好地匹配,而且最终决定将如此多的资源分配给 Docker 应该取决于开发人员自己的个人偏好。也就是说,你的笔记本电脑不是服务器,它可能不需要根据服务器标准构建的容器资源。
但是,即使超出了系统资源,开发人员环境也不能很好地与运行你的代码的系统保持一致。在过去,这种差异是如此之大,以至于我们经常不得不进入一个与我们的生产服务器完全一样的环境,而且我们中的一些人(不幸的是,包括我自己在内)如果出现严重错误的话,甚至不得不在这些系统上进行实时代码更改! 
开发人员需要专注于编写可维护、可靠和经过良好测试的代码。我认为,在有限的环境中工作可以有更好的代码实践和决策ーー你不得不依赖于编写整洁的、可维护和可操作的代码,而不是希望服务器以这种方式配置来处理性能瓶颈和低效的实现。 
开发人员在工作时已经有很多需要构建和维护的上下文。如果你的本地 Docker 环境将这种上下文作为为判断容器是否正在运行,那么从长远来看,只会让你失望了。
类似地,要求开发人员使用 `docker run` 命令启动容器会增加上下文切换的开销。在本地环境中开发时,开发人员已经建立了某种模式,而使用容器不仅与这些模式背道而驰,还需要对 `docker` CLI 本身有更多的掌握,这就给开发人员实现目标制造了阻力。当我不得不使用 Docker 容器来调试某些东西时,我也不禁感到有点奇怪。它有点像我之前提到过的一个错误: 进入生产服务器。
这种启发式方法与其他服务紧随其后。如果你所在的团队都在使用微服务,而其他团队需要各种各样的服务来构建自己的特性,那么你应该谨慎地将这些镜像作为容器提供。在这些情况下,团队在自己的环境中支持服务本身实际上可能比用容器模糊服务更有益。
对于这些特定的内部服务,可能值得对为此服务提供的文档进行审计,而不是对其进行容器化。维护不良的文档与容器结合在一起会产生诸多认知失调,从而导致放弃 Docker 环境的挫败感。我们所有人都应该更仔细地查看我们的文档,并经常对其进行审计,而不是构建新的东西。 
我上面提到的调查结果显示,Nginx、 Redis 和 Postgres 在拥抱的团队中非常受欢迎。很明显,为什么这些东西如此受欢迎。除非你的团队从事编写自己的 RDBMS 或 web 服务器 / 负载平衡器的业务,否则你将通过在堆栈中利用类似这样的开放源码应用程序而获益匪浅。
直到彻底的容器化,你的运营团队可能无法获得与开发团队在决定将其包含在技术栈中获得的相同收益。通过容器化这些依赖关系,运营团队可以从一种类似的加速器中受益,这种加速器无需编写自己的 RDBMS 即可为开发人员提供帮助。
容器化 Postgres 提供了大量用于部署,监视和扩展此关键依赖性的选项。它还减少了一些更新,升级和管理该系统的开销。这对运营团队来说非常有用,但这是否符合开发人员的需求? 
总而言之,即使简单地运行 `docker-compose up -d` 后台启动并运行容器,它也不能很好地与绝大多数开发人员用于本地运行环境的心智模型协同工作。这两种工作流程之间有着本质的差异。
开发人员希望能够深入挖掘他们需要的抽象概念,而要求团队使用一个全新的工具,用一种完全不同的方法来运行他们的本地环境,是一个很高的要求。具体来说,开发人员需要能够运行数据库迁移、跳转到数据库 CLI 并跟踪数据库日志。对于堆栈中的任何关键组件也是如此。
这并不是说没有开发人员乐意在本地使用 Docker 。但是我敢打赌,使用 Docker 的开发人员已经知道如何让它在他们的工作流中无缝地工作,不管他们是刚刚做了一个习惯性的改变,还是他们已经编写了脚本,以便更好地与他们自己的环境一起工作。
 

围绕容器命令编写新颖的脚本

 
说到脚本,如果你正在构建一个这样的本地环境,并且你正在试图减少必须由 `docker run 处各种事情的开销,那么你最初的冲动 (像我一样) 可能是编写许多与基于容器的工作相关的死记硬背的任务。 
这种偏好并不一定是被误导的。毕竟,我们被教导用脚本去掉冗余的任务,这样我们就可以减少重复工作。但是要注意尤其在你的团队对容器了解不深的情况下,不要过多地使用脚本。 
我提到过使用 `Docker` CLI 会产生开销,但是如果有一个开发团队积极地使用容器,那么为他们提供使用 Docker 自己的工具的时间和培训可能会更有意义,而不是潜在地模糊 Docker 本身的内部工作。这确实是一个必须掌握的工具,但是通过避免围绕这些命令编写新颖的脚本,你可以减少在故障排除和对工具本身的更广泛理解上的认知压力。
为了强调我对定制容器包装程序的最高的关注,围绕容器的新颖脚本产生了更多的代码,从而需要维护更多东西。我要说的是,如果小组确定这对其工作流程是有利的,你可以继续这么做。尤其是在新人入职过程中,希望大家可以避免编写那些注定被遗弃或某种场景定制的特定脚本,从而耗费大把的时间。


除了 Docker 化,别无选择


如果你对容器化的开发环境感兴趣,我认为你应该花很多的时间为本地运行系统构建简单的替代方案。换句话说,不要认为在本地环境中使用 Docker 是一个非此即彼的决定。记录在标准本地部署中设置应用程序的步骤,以及为那些对运行容器感兴趣的人提供替代方案。让你的团队判断这个工作流程是否适合。 

总而言之,在不进行开发环境的权衡的情况下全部使用容器将给你的开发团队带来负担。
 

结束
 

没有正确搭建开发环境的统一的模式。虽然鼓励你的团队拥抱容器化可能会带来一些好处,但最终的目标还是应该放在改善开发人员的工作流程。如果我们为了技术抽象而牺牲了编写优秀代码的能力,那么我们就是在降低效率。

不管是选择传统的还是容器化的开发环境,都不应该让个人的喜好所左右,最终应该让整个团队一起做决定。如果你能和团队一起找出本地开发存在的痛点,就能够帮助你准确评估是采用本地开发还是容器化。

原文:https://blog.testdouble.com/posts/2020-02-11-the-slippery-slope-of-docker-dev-environments/
本文为 CSDN 翻译,转载请联系我们。

推荐阅读:真香,朕在看了!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存