来 DTDS 全球数字人才发展峰会,与刘润、叶军、快刀青衣畅聊成长>> 了解详情
写点什么

Docker Compose 的 4 种错误使用方式

2021 年 2 月 20 日

Docker Compose的4种错误使用方式

本文最初发布于 Earthly 博客,经原作者授权由 InfoQ 中文站翻译并分享。


告诉我,这是不是听起来很熟悉?有人要把 docker-compose 介绍给你,你可能是自愿的,也可能是被迫的。你用了一段时间,但发现它很不灵活。我要告诉你,你可能用错了。


这可能有点夸张。我不认为存在 100%正确或错误的使用方法:自主构建和开发设置往往有各种奇怪的要求,所以标准可能不符合需求。如果你的情况并不完全相符,请带着适当的怀疑态度阅读本文。


本文介绍了我自己使用 docker-compose 犯的一些错误。


我将重点关注与集成测试相关的用例,以及使用 docker-compose 作为开发环境。对于生产使用,我认为 docker-compose 通常并不适合。

问题 1:使用主机网络


新用户遇到的第一个麻烦是 Docker 网络的使用。在你了解了 docker build docker run 的基础知识后,这是你需要学习的另一层知识……坦白说,为什么你还需要了解 Docker 网络呢?通过主机网络,一切工作正常,这对吗?错了!


使用主机网络意味着你必须为使用的各种微服务保留特定端口。如果你碰巧打开两个有端口冲突的栈,那你就倒霉了。如果你想打开同一个栈的两个版本,那也会倒霉。当某个服务有多个副本时,你想测试它的行为吗?这会非常艰难……


在默认情况下,docker-compose 在一个名为<project-name>_default 的独立网络上启动其容器(其中<project-name>为默认的目录名)。所以,你无需做任何特殊的事情就可以利用 Docker 网络。


这个网络立马能给你带来很多好处:


  • 它是一个比主机网络更加独立的网络——因此,系统环境的小问题就不太会导致 compose 设置的行为差异。你可以访问互联网,但是你希望从主机访问的任何端口都要使用端口绑定来声明。

  • 如果一个服务开始监听 0.0.0.0(容器应该这样),那么主机网络设置将在 WLAN 上打开那个端口。如果你使用 Docker 网络,它只会将该端口暴露给该网络。

  • 你可以通过使用服务的 compose name 作为主机名来实现服务之间的通信。因此,如果你有一个名为 db 的服务,在其内部有一个侦听端口 5432 的服务,那么你可以从任何其他服务通过 db:5432 访问它。这通常比 localhost:5432 更直观。而且,由于不存在本地主机端口冲突的风险,因此,在跨不同项目使用时,它可能会更加一致。

  • 大多数端口不需要向主机开放——这意味着,如果你需要通过--scale增加副本的话,它们不会竞争全局资源。

问题 2:强端口绑定到主机 0.0.0.0 上


这种做法随处可见,你肯定也见过很多,每个人都见过很多:将端口绑定为 8080:8080。乍一看,这似乎没什么问题。但魔鬼在细节中。这种极其常见的端口绑定不仅仅是将一个容器端口转发到本地主机——它还将其转发到系统上的每个网络接口上,包括用于连接互联网的任何接口。


换言之,你的开发容器很可能一直在监听你的无线局域网——当你在家、在办公室或在麦当劳时。它总是可以访问。这可能很危险。不要这样做。


“但是 Vlad,我用了 ufw,我的端口默认是不能访问的”。


这也许没错——但如果你在团队中使用这样的 docker-compose 设置,你的队友可能没有在他们的笔记本电脑上安装防火墙。


修复方法非常简单:只需在前面添加 127.0.0.1:,例如 127.0.0.1:8080:8080。这是告诉 docker 只向回环网络接口公开端口,不包括其他网络接口。

问题 3:使用 sleep 来协调服务启动


我要坦白一件事。关于这一点,我是百分百有错的。


这个问题之所以如此复杂,主要原因是 Docker 或 Docker Compose 没有提供支持解决这个问题。Docker-compose 文件格式的 2.1 版本中有一个名为 condition depends_on 选项,可以设置为 service_healthy。而且,每个服务都可以有一个 healthcheck 命令,可以告诉 docker-compose“健康”是什么意思。这在3.0版本中不再可用,也没有提供替换项


Docker 文档的基本建议是,服务要在其他服务暂时离线的情况下具有弹性,因为这在生产环境中可能会发生,例如出现短暂的网络不稳定,或者一个服务重新启动。这是无可争辩的。


当你运行一个集成测试,而用于初始化测试环境的例程(例如预先用一些测试数据填充数据库)在其他服务准备就绪之前无法恢复启动,就会变得有点麻烦。因此,关于“至少它在生产环境中会有弹性”的论点在这里并不适用,因为用测试数据填充数据库的代码从未在生产环境中使用。


对于这种情况,你需要等待服务就绪。Docker 建议使用wait-for-itDockerizewait-for。但是,请注意,端口就绪并不总是表示服务已经准备好可供使用。例如,在使用具有特定模式的特定 SQL DB 的集成测试中,当数据库初始化时,端口变为可用,但是,测试可能只有在特定模式迁移完成之后才能开始。你可能需要在前面进行特定于应用程序的检查。

问题 4:在 docker-compose 中运行数据库,但在主机上测试


有这样一种情况:你想运行一些单元测试,但这些测试依赖于一些外部服务。可能是数据库,可能是 Redis,也可能是另外一个 API。简单:让我们把这些依赖放在 docker-compose 中,并让单元测试连接到它们。


这很好——但请注意,你的测试不再仅仅是单元测试,它们现在是集成测试了。除术语之外,现在还需要考虑一个重要的区别:你需要考虑测试环境的设置和清理。通常,最好在测试代码之外执行设置/清理操作——主要原因是可能有多个不同的包依赖于这些外部服务。但你的情况可能不太一样。


如果你最终将测试设置和清理分开,那么你需要多做一些工作,将集成测试容器化。


容器化测试意味着:


  • 你在同一个 Docker 网络上,所以连接设置与你在 compose 中运行服务时相同。配置变得更简洁。

  • 在设置和清理过程中,你可以重用用于等待其他服务就绪的代码。

  • 集成测试不依赖于任何其他的本地系统配置或环境设置,例如你的 JFrog 凭证或任何构建依赖项。容器是隔离的。

  • 如果另一个团队需要针对测试所依赖的服务的更新版本运行你的测试,那么你只需要共享集成测试镜像——不需要他们编译或设置一个构建工具链。

  • 如果你最终使用了多个单独的集成测试容器,那么你通常可以并行地运行所有这些容器。


使用容器化集成测试的一个技巧是,为它们使用一个独立的 docker-compose 定义。例如,如果你的大部分服务都存在于 docker-compose.yml 中,那么可以添加一个包含集成测试定义的 docker- composition .test.yml 文件。这意味着 docker-compose up 会提供你常用的服务,而 docker-compose -f docker-compose.yml -f docker-compose.test.yml up 会启动集成测试。要了解完整的实现示例,请参阅 Ardan Labs 提供的这个优秀的docker-compose集成测试库


说这是错误有点不公平。在许多情况下,不容器化是更可取的。举个简单的例子,许多语言都与 IDE 深度集成,这使得在语言和 IDE 之间插入容器几乎不可能。有很多正当的理由不这样做。

小结


对本地开发来说,Docker Compose 是一个非常棒的工具。尽管它有一些缺陷,但通常,它会给许多工程团队带来很多生产力方面的好处,尤其是在与集成测试一起使用时。


原文链接:


https://blog.earthly.dev/youre-using-docker-compose-wrong/

2021 年 2 月 20 日 15:452200
用户头像

发布了 363 篇内容, 共 158.3 次阅读, 收获喜欢 814 次。

关注

评论

发布
暂无评论
发现更多内容

树莓派小车系列-直播

波叽波叽啵😮一口盐汽水喷死你

树莓派 ffmpeg 云直播 盐汽水 raspberry

译文MapReduce:大型集群上的简化数据处理

海神名

mapreduce 译文 MIT 分布式计算

Netty 源码解析(五): Netty 的线程池分析

猿灯塔

File类的文件操作

Howe

Java File 文件 io

源码浅析 - CocoaLumberjack 3.6 之 DDLog

Edmond

ios log4j CocoaLumberjack SourceCode DDLog

高仿瑞幸小程序 02 创建Tabbar

曾伟@喵先森

小程序 微信小程序 前端 瑞幸

Java并发编程系列——线程池

孙苏勇

Java Java并发 并发编程 多线程 线程池

企业如何选择物联网中台

老任物联网杂谈

物联网中台 IOT Platform 物联网平台

游戏夜读 | 做游戏选什么专业?

game1night

缘起:很久很久以前

escray

学习 测试驱动开发实战营

哲少荐书:这才是心理学

Jackey

心理学 读书

架构师们必备的三三制需求分析思维模型

常平

我的关注清单

lmymirror

知识管理 关注清单 RSS

科学治疗“知识焦虑症”

陈驰远

个人成长 知识管理

轻轻一扫,立刻扣款,付款码背后的原理你不想知道吗?

楼下小黑哥

支付宝 微信支付 支付系统 付款码

虚拟化Pod性能比物理机还要好,原因竟然是这样!

亨利笔记

Kubernetes 容器 k8s vSphere pod

python中的GIL锁和互斥锁问题

半面人

Python

百度开源项目

Bruce Duan

大家看看我这个斜杠青年够斜吗?

伯薇

个人成长 斜杠青年 能力提升 好奇心 T型人才

CEPH OSD Down故障分析与处理

木子

下一个阶段,就真的容易了吗?

ke_lv

生活

DDD 实践手册(3. Entity, Value Object)

Joshua

系统设计 领域驱动设计 系统架构 架构模式

每天一道 python 面试题 - Python中的元类(metaclass) 详细版本

志学Python

python 爬虫 python元类

阿里29大开源项目看看你都用过哪些

Bruce Duan

电商总裁被降级除名公司合伙人,土豆网创始人被前妻起诉,程序员该如何选择女朋友?

陆陆通通

程序员 蒋凡 女朋友 阿里 婚姻

[计算机网络1]我所知道的关于TCP的一切

海神名

TCP 计算机网络 网络协议 原理

我看拼多多黄峥:旧世界瓦解冰消

池建强

拼多多 黄峥

思维偏差与产品设计的关联思考

石君

产品设计 思维方式 安全产品设计

用 Vim 编辑 Markdown 时直接粘贴图片

mzlogin

vim markdown

leetcode20.有效的括号

Damien

算法 LeetCode

实战营第一战:FizzBuzz

escray

学习 CSD 认证实战营

「中国技术开放日·长沙站」现场直播

「中国技术开放日·长沙站」现场直播

Docker Compose的4种错误使用方式-InfoQ