我如何在 Docker 中运行 Docker 以及它的结果

大家好! 在他的 以前的文章,我承诺会谈论在 Docker 中运行 Docker 以及使用本课的实际方面。 是时候兑现你的承诺了。 经验丰富的开发人员可能会反对那些需要在 Docker 内部使用 Docker 的人只需将 Docker 守护进程套接字从主机转发到容器中,这在 99% 的情况下就足够了。 但不要急于向我扔 cookie,因为我们将讨论在 Docker 内部实际运行 Docker。 该解决方案有许多可能的应用,本文将介绍其中之一,因此请坐下来,将手臂伸直在身前。

我如何在 Docker 中运行 Docker 以及它的结果

开始

这一切都始于 5 月的一个下雨的夜晚,当时我正在清理在 Digital Ocean 上以 24 美元租用的机器,由于 Docker 已用其映像和容器填满了所有 XNUMX GB 的可用磁盘空间,因此该机器被冻结。 具有讽刺意味的是,所有这些图像和容器都是暂时的,只需要在每次发布新版本的库或框架时测试我的应用程序的性能。 我尝试编写 shell 脚本并设置 cron 计划来清理垃圾,但这并没有帮助:每次它都不可避免地以我的服务器磁盘空间被耗尽和服务器挂起(最多)而告终。 在某个时候,我看到一篇关于如何在容器中运行 Jenkins 以及如何通过转发到容器中的 docker 守护进程套接字创建和删除构建管道的文章。 我喜欢这个想法,但我决定更进一步,尝试在 Docker 中直接运行 Docker。 当时,在我看来,下载 Docker 镜像并为在另一个容器(我们称之为暂存容器)内测试所需的所有应用程序创建容器是一个完全合乎逻辑的解决方案。 这个想法是使用 -rm 标志启动一个暂存容器,该容器在停止时会自动删除整个容器及其所有内容。 我修改了 Docker 本身的 Docker 镜像(https://hub.docker.com/_/docker),但事实证明它太麻烦了,我从来没有设法让它按照我需要的方式工作,我想自己一路走下去。

实践。 视锥细胞

我开始让容器按照我需要的方式工作,并继续我的实验,最终长出了无数的花蕾。 我自虐的结果是下面的算法:

  1. 我们以交互模式启动 Docker 容器。

    docker run --privileged -it docker:18.09.6

    注意容器的版本,向右或向左移动,你的 DinD 就会变成南瓜。 事实上,当新版本发布时,事情经常出问题。
    我们必须立即进入外壳。

  2. 我们试图找出哪些容器正在运行(答案:无),但无论如何让我们运行命令:

    docker ps

    你会有点惊讶,但事实证明 Docker 守护进程甚至没有运行:

    error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 
    192.168.65.1:53: no such host

  3. 我们自己运行一下:

    dockerd &

    另一个令人不愉快的惊喜:

    failed to start daemon: Error initializing network controller: error obtaining controller instance: failed 
    to create NAT chain DOCKER: Iptables not found

  4. 安装 iptables 和 bash 软件包(在 bash 中工作比在 sh 中工作更愉快):

    apk add --no-cache iptables bash

  5. 让我们启动 bash。 最后我们回到了平常的外壳

  6. 让我们尝试再次启动 Docker:

    dockerd &

    我们应该看到一长串日志,结尾为:

    INFO[2019-11-25T19:51:19.448080400Z] Daemon has completed initialization          
    INFO[2019-11-25T19:51:19.474439300Z] API listen on /var/run/docker.sock

  7. 按 Enter 键。 我们又回到了狂欢之中。

从现在开始,我们可以尝试在 Docker 容器内启动其他容器,但如果我们想在 Docker 容器内启动另一个 Docker 容器,或者出现问题导致容器崩溃怎么办? 一切重新开始。

自己的 DinD 容器和新实验

我如何在 Docker 中运行 Docker 以及它的结果
为了避免一遍又一遍地重复上述步骤,我创建了自己的 DinD 容器:

https://github.com/alekslitvinenk/dind

有效的 DinD 解决方案使我能够在 Docker 内递归运行 Docker 并进行更多冒险实验。
我现在将描述一个这样的(成功的)运行 MySQL 和 Nodejs 的实验。
最不耐烦的人也能看到这里的情况

让我们开始吧:

  1. 我们以交互模式启动 DinD。 在此版本的 DinD 中,我们需要手动映射子容器可以使用的所有端口(我已经在处理这个问题了)

    docker run --privileged -it 
    -p 80:8080 
    -p 3306:3306 
    alekslitvinenk/dind

    我们进入 bash,从中我们可以立即开始启动子容器。

  2. 启动MySQL:

    docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql

  3. 我们以与本地连接数据库相同的方式连接到数据库。 让我们确保一切正常。

  4. 启动第二个容器:

    docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server

    请注意,端口映射将准确无误 8080:8080,因为我们已经将主机到父容器的端口 80 映射到端口 8080。

  5. 我们在浏览器中访问本地主机,确保服务器响应“Hello World!”

就我而言,嵌套 Docker 容器的实验结果非常积极,我将继续开发该项目并将其用于暂存。 在我看来,这是一个比 Kubernetes 和 Jenkins X 更轻量级的解决方案。但这是我的主观意见。

我想这就是今天文章的全部内容。 在下一篇文章中,我将更详细地描述在 Docker 中递归运行 Docker 并将目录深入到嵌套容器中的实验。

PS 如果您觉得这个项目有用,请在 GitHub 上给它一个 star,fork 它并告诉您的朋友。

Edit1 更正了错误,重点关注 2 个视频

来源: habr.com

添加评论