在Docker容器内运行Docker是否可行?

331
我正在Docker容器中运行Jenkins。我想知道在Jenkins容器中也成为Docker宿主机是否可行?我的想法是,从Jenkins内部启动一个新的Docker容器来构建每个集成测试(例如启动数据库、消息代理等)。这些容器应该在集成测试完成后关闭。这样,在另一个Docker容器中运行Docker容器是否有避免的原因?

21
另一种可能性是将宿主机上的Docker套接字作为一个卷挂载到容器中。这样可以创建“兄弟”容器,并且具有重复使用缓存的优点。 - Adrian Mouat
8
我发现,当从主机使用Docker套接字时,如果想要挂载外部卷,必须将卷路径相对于主机设置,因为那里是Docker守护程序运行的位置。除非路径重合,否则将其相对于启动容器的容器设置并不一定有效。 - Jakob Runge
5个回答

378

在可能的情况下,应该避免在 Docker 容器内运行 Docker(即所谓的 dind)。(以下提供源代码。)相反,您希望设置一种方式,使您的主容器能够生成并与同级容器进行通信。

Jérôme Petazzoni - 使 Docker 可以在 Docker 容器内运行的功能的作者 - 实际上发布了一篇博客文章,不建议进行此操作。他描述的用例与 OP 的确切用例相匹配,都是需要在其他 Docker 容器中运行作业的 CI Docker 容器。

Petazzoni 列出了 dind 有问题的两个原因:

  1. 它与 Linux 安全模块(LSM)不兼容。
  2. 它创建了文件系统不匹配,从而为父容器中创建的容器创建问题。

从那篇博客文章中,他描述了以下替代方案,

[The] simplest way is to just expose the Docker socket to your CI container, by bind-mounting it with the -v flag.

Simply put, when you start your CI container (Jenkins or other), instead of hacking something together with Docker-in-Docker, start it with:

docker run -v /var/run/docker.sock:/var/run/docker.sock ...

Now this container will have access to the Docker socket, and will therefore be able to start containers. Except that instead of starting "child" containers, it will start "sibling" containers.


9
您需要将用户添加到“docker”组中:sudo usermod -aG docker $USER。之后您需要重新登录。 - predmijat
3
如何在容器内重新登录? - thiagowfx
1
@AlexanderMills,这是一样的,因为当你在MacOS机器上运行Docker时,你的Docker套接字也位于/var/run/docker.sock - Bruce Sun
3
Windows怎么办?我没有/var/run/docker.sock - Abdelhafid
7
Jérôme Petazzoni因为出现了新的工具,例如sysbox,使得使用Docker更加方便,从而改变了他的观点(2020年)。他更新了与答案相关联的博客文章以反映这一变化。 - volkit
显示剩余13条评论

76

我之前回答过一个类似的问题,关于如何在Docker内部运行另一个Docker容器

要在Docker内运行Docker是完全可能的。主要是需要使用额外特权(从--privileged=true开始)运行外部容器,然后在该容器中安装Docker。
查看此博客文章以获取更多信息:Docker-in-Docker
这种方法的一个潜在用例在这篇文章中描述。该博客介绍了如何在Jenkins Docker容器中构建Docker容器。
但是,Docker内部不是解决此类问题的推荐方法。相反,推荐的方法是创建“同级”容器,如在此帖子中所述
因此,许多人认为在Docker内运行Docker是解决此类问题的良好解决方案。现在,趋势是改用“兄弟”容器。有关更多信息,请参见此页面上@predmijat的答案

请注意避免在 Docker 中使用 Docker,有关详细信息请参见下面的注释。 - Dan Poltawski
请注意,Docker Swarm 不支持此功能。 - Sam

20

在 Docker 中运行 Docker-in-Docker(DinD)是可以的,事实上 Docker 公司为此提供了官方 DinD 镜像

然而需要注意的是,这需要一个特权容器,根据您的安全需求可能不是可行的选择。

使用同级容器运行 Docker 的替代解决方案(也称为 Docker-out-of-Docker 或 DooD)不需要特权容器,但由于您从与其运行环境不同的上下文中启动容器(即您从容器内部启动容器,但它在主机层级而不是容器内部运行),因此具有一些缺点。

我写了一篇博客,介绍了 DinD 与 DooD 的优缺点这里

话虽如此,Nestybox(我刚刚创立的初创公司)正在开发一种可以安全运行真正的 Docker-in-Docker 的解决方案(不使用特权容器)。您可以访问www.nestybox.com进行了解。


10
可以在Docker中运行Docker,需要将Unix套接字/var/run/docker.sock作为卷连接到父容器中,它是Docker守护程序默认监听的地址,使用命令-v /var/run/docker.sock:/var/run/docker.sock。有时,Docker守护程序的套接字可能存在权限问题,您可以通过写入sudo chmod 757 /var/run/docker.sock来解决。
此外,还需要以特权模式运行Docker,命令如下:
sudo chmod 757 /var/run/docker.sock

docker run --privileged=true -v /var/run/docker.sock:/var/run/docker.sock -it ...

1
docker:未找到命令 - Proximo
2
@Proximo 你必须在容器内安装它。 - Felipe Martins Melo

1
我过去几天一直在尝试像你一样在容器内运行容器,费了很多时间。到目前为止,大多数人建议我做一些事情,比如使用docker的DIND镜像,但这对我的情况不适用,因为我需要主容器是Ubuntu操作系统,或者运行一些特权命令并将守护程序套接字映射到容器中(这对我从来没有起作用)。
我找到的解决方案是在我的Ubuntu 20.04系统上使用Nestybox,它效果最好。如果您的本地系统是Ubuntu(他们最好支持),则非常简单易行,因为容器运行时专门设计用于此类应用程序。它还具有最灵活的选项。截至2022年11月,Nestybox的免费版本可能是最好的方法。强烈建议您尝试它,而不必去烦恼其他人建议的繁琐设置。他们有许多预构建的解决方案,以一个简单的命令行来满足这些特定需求。
Nestybox提供了专门的运行时环境,用于新创建的Docker容器,他们还提供了一些带有Docker和systemd的Ubuntu/常见操作系统镜像。 他们的目标是使主要容器与虚拟机完全相同,并且安全。您甚至可以直接通过SSH登录到您的Ubuntu主容器,但无法访问主机中的任何内容。从主容器中,您可以像在本地系统上一样创建各种类型的容器。systemd对于在容器内方便设置Docker非常重要。
执行sysbox的一个简单常用命令:
    dock run --runtime=sysbox-runc -it any_image

如果您认为这就是您正在寻找的内容,您可以在他们的Github上了解更多信息: https://github.com/nestybox/sysbox

快速链接到有关如何部署简单的sysbox运行时环境容器的说明:https://github.com/nestybox/sysbox/blob/master/docs/quickstart/README.md


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接