前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在您的CI或测试环境中使用Docker-in-Docker?三思而后行

在您的CI或测试环境中使用Docker-in-Docker?三思而后行

作者头像
天地一小儒
发布2022-12-28 13:59:42
6870
发布2022-12-28 13:59:42
举报
文章被收录于专栏:信且诚心之动

转译于~jpetazzo/Using Docker-in-Docker for your CI or testing environment? Think twice.

Docker-in-Docker的主要目的是帮助开发Docker本身。许多人使用它来运行CI(例如使用Jenkins),这看起来很好,但它们会遇到许多“有趣”的问题,可以通过将Docker套接字绑定到Jenkins容器来避免。

让我们看看这意味着什么。如果您想要没有详细信息的简短解决方案,只需滚动到本文的底部即可。☺

Docker-in-Docker:好的

两年多以前,我在Docker中贡献了-privileged标志 并编写了第一版dind。目标是帮助核心团队更快地开发Docker。在Docker-in-Docker之前,典型的开发周期是:

  • hackity hack
  • 建立
  • 停止当前运行的Docker守护程序
  • 运行新的Docker守护进程
  • 测试
  • 重复

如果你想要一个漂亮的,可重现的构建(即在一个容器中),它会有点复杂:

  • hackity hack
  • 确保可运行的Docker版本正在运行
  • 使用旧Docker构建新的Docker
  • 停止Docker守护进程
  • 运行新的Docker守护进程
  • 测试
  • 停止新的Docker守护进程
  • 重复

随着Docker-in-Docker的出现,这被简化为:

  • hackity hack
  • 构建+一步完成
  • 重复

好多了,对吧?

Docker-in-Docker:糟糕的

然而,与流行的看法相反,Docker-in-Docker并非100%由闪光,小马和独角兽制成。我的意思是,有一些问题需要注意。

一个是关于像AppArmor和SELinux这样的LSM(Linux安全模块):当启动容器时,“内部Docker”可能会尝试应用会使“外部Docker”发生冲突或混淆的安全配置文件。这实际上是最难解决的问题。试图合并-privileged 标志的原始实现。我的更改在我的Debian机器和Ubuntu测试虚拟机上工作(并且所有测试都会通过),但它会在迈克尔克罗斯比的机器上崩溃并烧毁 (如果我记得很好的话,它就是Fedora)。我不记得问题的确切原因,但可能是因为迈克是一个聪明的人SELINUX=enforce (我使用的是AppArmor)并且我的更改没有将SELinux配置文件考虑在内。

Docker-in-Docker:丑陋的

第二个问题与存储驱动程序相关联。在Docker中运行Docker时,外部Docker运行在普通文件系统(EXT4,BTRFS,你有什么)之上,但内部Docker运行在写时复制系统(AUFS,BTRFS,Device Mapper等)之上。 。,取决于外部Docker设置使用的内容)。有许多组合不起作用。例如,您无法在AUFS之上运行AUFS。如果在BTRFS之上运行BTRFS,它应该首先工作,但是一旦嵌套子卷,删除父子卷将失败。Device Mapper不是命名空间,因此如果Docker的多个实例在同一台机器上使用它们,它们将能够看到(并影响)彼此的图像和容器支持设备。没有bueno。

许多问题都有解决方法; 例如,如果你想在内部Docker中使用AUFS,只需 /var/lib/docker将其升级为一个卷,你就可以了。Docker为Device Mapper目标名称添加了一些基本的命名空间,因此如果Docker的多次调用在同一台机器上运行,它们就不会互相踩踏。

然而,设置并不完全是直截了当的,正如您可以 GitHub 上的存储库中的那些问题中看到的 那样 。 dind

Docker-in-Docker:它变得更糟

那么构建缓存呢?那个人也会变得非常棘手。人们常常问我:“我正在运行Docker-in-Docker; 我如何使用位于主机上的图像,而不是在内部Docker中再次拉动所有图像?“

一些喜欢冒险的人试图/var/lib/docker 从主机绑定到Docker-in-Docker容器。有时它们/var/lib/docker与多个容器共享。

Sterling Archer建议你不要共享/ var / lib / docker,thx

Docker守护程序明确设计为具有独占访问权限/var/lib/docker。没有别的东西可以触摸,戳或隐藏任何隐藏在那里的Docker文件。

这是为什么?这是dotCloud时代的经验教训之一。dotCloud容器引擎通过让多个进程/var/lib/dotcloud同时访问来工作。聪明的技巧,如原子文件替换(而不是就地编辑),通过咨询和强制锁定来编写代码,以及像SQLite和BDB这样的安全系统的其他实验只能让我们到目前为止; 当我们重构我们的容器引擎(最终成为Docker)时,一个重大的设计决策就是在一个守护进程下收集所有容器操作,并完成所有并发访问的废话。

(不要误解我的意思:完全有可能做一些好的,可靠的,快速的,涉及多个进程和最先进的并发管理;但我们认为它更简单,更容易编写和维护,与Docker的单一演员模型一起使用。)

这意味着如果您/var/lib/docker在多个Docker实例之间共享目录,那么您将度过一段美好时光。当然,它可能会起作用,特别是在早期测试期间。“看哪,我可以docker run ubuntu!”但是尝试做更多的事情(从两个不同的实例中拉出相同的图像......)并观察世界燃烧。

这意味着,如果您的CI系统进行构建和重建,每次重新启动Docker-in-Docker容器时,您可能正在调整其缓存。这真的不酷。

解决方案

我们在这里退一步吧。你真的想要Docker-in-Docker吗?或者你只是希望能够从CI系统运行Docker(特别是:构建,运行,有时推送容器和图像),而这个CI系统本身就在容器中?

我敢打赌,大多数人都想要后者。您想要的只是一个解决方案,以便像Jenkins这样的CI系统可以启动容器。

最简单的方法是将Docker套接字暴露给CI容器,方法是将其与-v标志绑定。

简单地说,当您启动CI容器(Jenkins或其他)时,不要与Docker-in-Docker一起攻击某些东西,而是启动它:

代码语言:javascript
复制
docker run -v /var/run/docker.sock:/var/run/docker.sock ...

现在这个容器可以访问Docker套接字,因此可以启动容器。除了不启动“子”容器,它将启动“兄弟”容器。

尝试使用docker官方图像(包含Docker二进制文件):

代码语言:javascript
复制
docker run -v /var/run/docker.sock:/var/run/docker.sock \
           -ti docker

这看起来像Docker-in-Docker,感觉就像Docker-in-Docker,但它不是Docker-in-Docker:当这个容器创建更多容器时,这些容器将在顶级Docker中创建。您将不会遇到嵌套副作用,并且将在多个调用之间共享构建缓存。

⚠️这篇文章的旧版本建议将docker二进制文件从主机绑定到容器。这不再可靠,因为Docker Engine不再作为(几乎)静态库分发。

如果您想使用Jenkins CI系统中的Docker,您有多种选择:

  • 使用基本映像的打包系统安装Docker CLI(即如果您的映像基于Debian,请使用.deb包),
  • 使用Docker API。

译者总结

与其在容器里创建容器,不如在容器里挂载容器

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-06-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Docker-in-Docker:好的
  • Docker-in-Docker:糟糕的
  • Docker-in-Docker:丑陋的
  • Docker-in-Docker:它变得更糟
  • 解决方案
  • 译者总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档