我们的愿景是让一个人编写一个docker-compose.yml 文件,指定开发所需的所有内容并将其提交到代码存储库。然后,每个开发人员只需运行docker-compose up 即可启动测试代码所需的所有容器。
然而,让docker-compose 设置实现最大性能需要大量工作。我们已经看到最好的团队在不到一分钟的时间内启动他们的开发环境,并在几秒钟内测试每个更改。考虑到每个开发人员每天花费在测试代码上的时间,小的改进可能会对开发人员的生产力产生巨大的影响。
来自xkcd
docker 构建需要很长时间。如果每次想要测试代码更改时都必须重建容器,那么您就有很大的潜力来加快开发周期。
使用非容器化应用程序的传统工作流程如下:
编码构建已经运行了多年,并且通过使用增量构建和编译语言热重载等技术,该过程得到了高度优化。它变得非常快。
当人们第一次采用容器时,他们倾向于采用现有的工作流程,只添加一个docker 构建步骤。他们的工作流程如下:
编码、构建、容器构建和运行如果做得不好,docker构建步骤会让所有优化都白费。另外,它还增加了一堆额外耗时的工作,例如使用apt-get 重新安装依赖项。所有这些加起来使我们的测试过程比使用docker 之前慢得多。
一种选择是启动docker compose 中的所有依赖项,但在本地运行您正在处理的代码。这模仿了开发非容器化应用程序的工作流程。
只需在localhost 上公开您的依赖项并将您正在使用的服务指向localhost: 端口地址即可。
然而,这并不总是可行,特别是如果您正在处理的代码依赖于容器映像中内置的内容,而这些内容无法从笔记本电脑轻松访问。
如果必须构建docker 映像,则最大化缓存可以将10 分钟的docker 构建变成写入dockerfile 时的1 分钟。
生产dockerfile 的典型模式是通过将各个命令链接到run 语句中来减少层数。然而,图像大小在开发过程中并不重要。在开发过程中,您需要尽可能多的层。
您的生产dockerfile 可能如下所示:
run \\ go get -d -v \\ go install -v \\ go build 这对开发不利,因为每次重新运行命令时,docker 都会重新下载所有依赖项并重新安装它们。增量建设效率更高。
相反,您应该有一个专门针对您的开发环境的dockerfile。将所有内容分解为非常小的步骤并规划dockerfile,以便最后执行基于频繁更改的代码的步骤。
更改最不频繁的事情(例如拉取依赖项)应该首先进行。这样在重建dockerfile 时就不必构建整个项目。您只需要构建刚刚修改的一小部分。
通常,最佳选择是使用主机卷将代码直接加载到容器中。这使您能够以本机速度运行代码,同时仍在包含运行时依赖项的docker 容器中运行。
主机卷将笔记本电脑上的目录镜像到正在运行的容器中。当您在文本编辑器中编辑文件时,更改会自动同步到容器,然后可以立即执行。
大多数语言都有一种方法来监视您的代码并在代码发生更改时自动重新运行它。例如,nodemon 是一种监视javascript 代码的方法。查看这篇文章教程,了解如何进行设置。
最初需要一些工作,但结果是,您可以在1-2 秒内看到代码更改的结果,而docker 构建可能需要几分钟。
如果您使用主机卷,您可能已经注意到在windows 和mac 上读写文件非常慢。对于读取和写入大量文件的命令(例如具有复杂依赖项的node.js 和php 应用程序)来说,这是一个已知问题。
这是因为docker 运行在windows 和mac 上的虚拟机上。在进行主机卷挂载时,您必须经过大量转换才能将笔记本电脑上的文件夹挂载到容器中,有点像网络文件系统。这增加了在linux 上本地运行docker 时不存在的显着负载。
关键问题之一是文件系统安装默认保持强一致性。一致性是一个广泛的主题,可以写得很详细,但简而言之,它意味着特定文件的所有读者和作者都同意任何文件修改发生的顺序,以便(最终,在一定程度上)达成一致与文档的内容。
问题在于,强制执行强一致性的成本相当高,并且需要所有文件编写者确保他们不会不恰当地破坏彼此的更改。
尽管强一致性有时特别重要,例如在生产环境中运行数据库时。好消息是,在开发环境中,这不是必需的。您的代码文件将只有一个编写者(您自己)和一个来源(您的代码库)。因此,冲突并不像生产中那样令人担忧。
正是由于这个原因,docker 实现了在挂载卷时放宽一致性保证的能力。在docker compose 中,只需将缓存关键字添加到卷挂载即可获得显着的性能保证。 (不要在生产环境中这样做.)
volumes: – \’./app:/usr/src/app/app:cached\’
docker 的下一版本内置了mutagen,作为卷缓存模式的替代方案。如果您有兴趣,只需等待docker 发布下一个版本即可尝试,但您也可以直接下载mutagen 项目并使用,无需等待。
对于像node这样的语言,大多数文件操作往往都在包目录中(例如node_modules)。因此,从卷中排除这些目录可以显着提高性能。
在下面的示例中,我们有一个卷将代码加载到容器中。然后,node_modules 目录将被其自己的干净专用卷覆盖。
volumes: – \’./usr/src/app\’ – \’/usr/src/app/node_modules\’ 这个额外的卷加载告诉docker 对node_modules 目录使用标准卷,这样当npm install 运行时,它就不会使用比较主机加载缓慢。为了使这项工作正常进行,当容器首次启动时,我们在入口点上运行npm install 来安装依赖项并填充node_modules 目录。像这样:
entrypoint: – \’sh\’ – \’-c\’ – \’npm install ./node_modules/.bin/nodemon server.js\’ 可以在此处找到克隆和下载上述示例代码的完整说明。
env 文件将环境变量与主docker compose 配置分开。这有助于:
将密钥不保存在git 历史记录中可以让每个开发人员更轻松地进行略有不同的设置。例如,每个开发人员可能拥有唯一的访问密钥。将配置保存在.env 文件中意味着他们不必修改提交的docker-compose.yml 文件,也不必在更新该文件时处理冲突。要使用env 文件,只需添加.env 文件,或使用env_file 字段显式设置路径。
覆盖文件允许您进行基本配置,然后在不同的文件中指定修改。如果您使用docker swarm 并拥有生产yaml 文件,这非常有用。您可以将自己的生产环境配置存储在docker-compose.yml 中,然后在覆盖文件中指定开发环境所需的任何更改,例如使用主机卷。
如果您使用的是docker compose v2,则可以使用extends 关键字在多个位置导入yaml 片段。例如,您可能有一个定义,即您公司的所有服务在开发环境的docker compose 文件中都有这5 个特定配置项。您可以定义一次,然后使用extends 关键字将其放置在需要的地方,这提供了一些模块化功能。我们必须在yaml 中执行此操作,这很痛苦,但我们可以少编写一个程序来生成它,这仍然很好。
compose v3 删除了对extends 关键字的支持。但是,您可以使用yaml 锚点获得类似的结果。
我们与一些使用blimp 的工程团队合作,他们的开发环境的docker compose 文件中有数百个容器。如果他们使用单个巨大的docker compose 文件,则需要数千行无法维护的yaml 代码。
作为扩展,可以编写脚本来生成基于一些高级规范的docker compose 文件。这对于拥有非常大的开发环境的工程团队来说很常见。
docker-compose up 只能工作一半的时间吗?您是否必须使用docker-compose restart 来启动崩溃的服务?
大多数开发人员想要编写代码而不是进行devops 工作。调试糟糕的开发环境可能会非常令人沮丧。
docker-compose up 每次都应该可以正常工作。
这里的大多数问题都与服务以错误的顺序启动有关。例如,你的web应用程序可能依赖于数据库,如果web应用程序启动时数据库还没有准备好,它就会崩溃。
dependent_on 使您能够控制启动顺序。默认情况下,depends_on 将等待创建依赖项,而不是等待“健康”状态的依赖项。但是,docker compose v2 支持将depends_on 与健康检查结合起来。 (不幸的是,这个功能在docker compose v3 中被删除了。您可以使用wait-for-it.sh 等脚本手动实现类似的功能)
docker 文档建议不要使用depends_on 和wait-for-it.sh 等选项。此外,我们同意,要求容器具有特定的启动顺序是生产环境中架构脆弱的标志。然而,作为一名试图完成工作的开发人员,修复整个工程组织中的每个容器可能是不可行的。所以对于一个开发环境来说,我们认为这是可以的。
确保docker 拥有平稳运行所需的资源而不完全压垮您的笔记本电脑可能很棘手。如果您觉得您的开发工作流程因docker 未以峰值容量运行而缓慢,那么需要考虑以下几点。
docker desktop 需要大量ram 和cpu,特别是当它是mac 和windows 上的虚拟机时。默认的docker desktop 配置通常不会分配足够的ram 和cpu,因此我们通常建议调整设置以过度分配。在开发时,我倾向于为docker 分配大约8gb ram 和4 个cpu(当我不使用docker desktop 时,我会关闭它以使其可行)
人们在使用docker 时经常会无意中泄漏资源。人们拥有数百或数千个卷、旧容器映像以及如果不小心有时仍会运行的容器并不罕见。这就是为什么我们建议偶尔运行docker system prune 来删除当前未使用的任何卷、容器和网络。这释放了大量资源。
最后,在某些情况下,即使使用上述提示,也可能无法在笔记本电脑上运行您需要的所有容器。如果是这种情况,请查看blimp,这是一种在云上运行docker compose 文件的简单方法。
为了改善docker compose 上的开发人员体验,我鼓励您
使用主机卷最小化容器重建致力于维护可维护的组合文件,就像代码一样。让您的指导可靠并仔细管理资源。原文链接:
https://blimpup.io/blog/common-docker-compose-mistakes/
用户评论
无所谓
docker compose 太难了,每次遇到错误都抓狂!这个文章刚好可以收藏一下,方便以后查阅。
有13位网友表示赞同!
何必锁我心
这几个错误真常见,尤其是那个端口冲突,我经常遇到。
有15位网友表示赞同!
墨染天下
感谢分享!文章里的例子很实用,让我对docker compose的理解更深入了一些。
有14位网友表示赞同!
歇火
学习docker compose真是一件头疼的事,希望这篇文章能帮助我少走弯路。
有18位网友表示赞同!
身影
收藏了,以后遇到问题直接来这里找答案!
有10位网友表示赞同!
娇眉恨
文章内容很清晰,解释也很到位,推荐给正在学习docker compose的朋友们。
有6位网友表示赞同!
空谷幽兰
终于找到一篇靠谱的docker compose错误排查指南了,赞一个!
有9位网友表示赞同!
绝版女子
docker compose的错误千奇百怪,这篇文章总结了几个常见的,非常有用。
有16位网友表示赞同!
心安i
端口冲突,服务依赖,网络问题…这些都是docker compose新手容易犯的错误。
有15位网友表示赞同!
将妓就计
这篇文章太及时了,我最近刚开始学习docker compose,正好需要这样的帮助。
有6位网友表示赞同!
花开丶若相惜
希望以后能看到更多关于docker compose的文章,帮助大家解决更多问题。
有19位网友表示赞同!
作业是老师的私生子
docker compose真是一款好用的工具,但是想要用好它还需要不断学习和练习。
有5位网友表示赞同!
还未走i
这几个错误太坑了,还好有这篇文章来指点迷津!
有5位网友表示赞同!
失心疯i
docker compose的错误解决起来很麻烦,这篇文章总结了几个常见的错误,可以帮助我们快速排查问题。
有9位网友表示赞同!
站上冰箱当高冷
文章里的错误解析非常详细,配图也很直观,帮助我理解了错误的原因。
有14位网友表示赞同!
敬情
docker compose的错误排查确实需要一定的技巧,这篇文章很有参考价值。
有14位网友表示赞同!
裸睡の鱼
学习docker compose的路上,总会有各种各样的错误出现,这篇文章就是我的救星!
有17位网友表示赞同!
苍白的笑〃
终于找到一篇讲解docker compose常见错误的文章了,感谢作者的分享!
有15位网友表示赞同!
∞◆暯小萱◆
文章里的错误解决方法非常实用,可以帮助我们快速修复问题。
有16位网友表示赞同!
安陌醉生
强烈推荐这篇关于docker compose错误的文章,新手必看!
有9位网友表示赞同!