本博文介绍Docker in Docker问题背景与构建方式。
一、Docker in Docker原理
Docker-in-Docker的方式主要是为了帮助核心团队更快地进行 Docker 开发。在 Docker-in-Docker 之前,典型的开发周期是:
- 黑客攻击
- 建造
- 停止当前运行的 Docker 守护进程
- 运行新的 Docker 守护进程
- 测试
- 重复
如果你想要一个漂亮的、可重复的构建(即在容器中),那就有点复杂了:
- 黑客攻击
- 确保 Docker 的可用版本正在运行
- 用旧的 Docker 构建新的 Docker
- 停止 Docker 守护进程
- 运行新的 Docker 守护进程
- 测试
- 停止新的 Docker 守护进程
- 重复
Docker-in-Docker 并非 100% 有几个问题需要注意。
- 关于 LSM(Linux 安全模块),AppArmor 和 SELinux:当启动容器时,“内部 Docker”可能会尝试应用会与“外部 Docker”冲突或混淆的安全配置文件。这实际上是尝试合并 -privileged 标志的原始实现时最难解决的问题。在Debian 机器和 Ubuntu 测试 VM 上有效(并且所有测试都通过了),但它会在 Michael Crosby 的机器(如果我没记错的话是 Fedora)上崩溃。可能是可以使用配置 SELINUX=enforce运行,而我的更改没有考虑 SELinux 配置文件。
- 存储驱动程序有关。当你在 Docker 中运行 Docker 时,外部 Docker 运行在普通文件系统(EXT4、BTRFS、你有什么)之上,但内部 Docker 运行在写时复制系统(AUFS、BTRFS、设备映射器等)之上.,取决于外部 Docker 设置使用的内容)。有很多组合是行不通的。例如,您不能在 AUFS 之上运行 AUFS。如果你在 BTRFS 之上运行 BTRFS,它首先应该可以工作,但是一旦你有嵌套的子卷,删除父子卷就会失败。 Device Mapper 没有命名空间,因此如果 Docker 的多个实例在同一台机器上使用它,它们都将能够看到并影响彼此的镜像和容器支持设备。许多这些问题都有解决方法;例如,如果您想在内部 Docker 中使用 AUFS,只需将 /var/lib/docker 提升为卷即可。 Docker 为 Device Mapper 目标名称添加了一些基本的命名空间,这样如果 Docker 的多个调用在同一台机器上运行,它们就不会相互影响。
- 对于构建缓存也存在很大问题。如果运行 Docker-in-Docker;如何使用位于我的主机上的images,而不是在内部 Docker 中再次拉取所有内容?”,或许你尝试将 /var/lib/docker 从主机绑定挂载到 Docker-in-Docker 容器中。有时他们与多个容器共享 /var/lib/docker。但是对于Docker 守护进程被明确设计为具有对 /var/lib/docker 的独占访问权限。任何其他东西都不应触及、戳或挠隐藏在那里的任何 Docker 文件。这是为什么?这是从 dotCloud 时代吸取的教训之一。 dotCloud 容器引擎通过让多个进程同时访问 /var/lib/dotcloud 来工作。例如像原子文件替换(而不是就地编辑),或者是代码中添加咨询和强制锁定,以及对 SQLite 和 BDB 等安全系统的试验;当我们重构我们的容器引擎(最终成为 Docker)时,一个重大的设计决策就是将所有容器操作集中在一个守护进程下,并完成所有并发访问的请求。如果您在多个 Docker 实例之间共享 /var/lib/docker 目录,获取它可能会起作用,尤其是在早期测试期间。但是尝试做一些更复杂的事情(从两个不同的实例中提取相同的镜像…..)。如果您的 CI 系统进行构建和重建,每次您将重新启动 Docker-in-Docker 容器时,您都可能会破坏它的缓存.
Docker run Docker的方式有三种
因为在特权模式下运行容器。Nestybox尝试通过使用sysbox Docker运行时来解决该问题。如果使用Nestybox sysbox运行时创建容器,则它可以在能够运行systemd,docker,kubernetes的容器内创建虚拟环境,而无需特权访问基础主机系统。解释sysbox需要足够的理解力,因此我不在本文的讨论范围之内。请参考此页面以全面了解sysbox。
Sysbox 是一个 OCI 运行时,可以用来代替 runc,或者作为 runc 的补充。它可以运行通常需要特权标志的“系统容器”,而无需特权标志;并在这些容器之间以及这些容器与其宿主之间提供足够的隔离。Sysbox 还提供了运行容器中容器的优化。具体来说,当并排运行多个 Docker 实例时,可以使用一组共享的镜像“播种”它们。这节省了大量磁盘空间和大量时间,我认为这在运行时会产生巨大的差异,例如容器中的 Kubernetes 节点。(在容器中运行 Kubernetes 节点对于 CI/CD 尤其有用,当您想要部署 Kubernetes 暂存应用程序或在其自己的集群中运行测试时,无需在专用机器上部署完整集群的基础架构成本和时间开销。)
步骤1:安装sysbox运行时环境。请参阅此页面以获取有关安装sysbox运行时的最新官方说明。 sysbox:https://github.com/nestybox/sysbox 第2步:一旦拥有sysbox运行时可用,您要做的就是使用sysbox运行时标志启动docker容器,如下所示。在这里,我们使用的是官方docker dind映像。 docker run --runtime=sysbox-runc --name sysbox-dind -d docker:dind 步骤3:现在将exec会话带到sysbox-dind容器。 docker exec -it sysbox-dind /bin/sh
如果您只是希望能够从 CI 系统运行 Docker(特别是:构建、运行,有时推送容器和映像),而该 CI 系统本身位于容器中?您想要的只是一个解决方案,以便您的 CI 系统(如 Jenkins)可以启动容器。最简单的方法是将 Docker 套接字公开给 CI 容器,方法是使用 -v 标志绑定挂载它。简而言之,当您启动 CI 容器(Jenkins 或其他)时,不要使用 Docker-in-Docker 来破解某些东西,而是从以下内容开始:现在这个容器将可以访问 Docker 套接字,因此能够启动容器。除了启动“子”容器之外,它将启动“兄弟”容器。你可以是使用 docker 官方镜像(包含 Docker 二进制文件):
#启动的容器 docker run -it -d -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker docker(镜像ID) #进入容器并使用docker sudo docker exec -it 容器(ID) /bin/bash #使用的docker的相关指令docker pull docker pull busybox
这看起来像 Docker-in-Docker,感觉像 Docker-in-Docker,但它不是 Docker-in-Docker:当这个容器将创建更多容器时,这些容器将在顶级 Docker 中创建。您不会遇到嵌套副作用,并且构建缓存将在多个调用之间共享。
Dockerfile内容以从容器内部测试映像构建。
# 基础镜像 FROM ubuntu:18.04 # 安装依赖 RUN apt-get update && apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common # 安装秘钥 RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - # 添加仓库 RUN add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" # 安装docker RUN apt-get install docker-ce docker-ce-cli containerd.io -y
编译Dockerfile docker build -t images_name . Docker 的启动命令 docker container run -it -v /var/run/docker.sock:/var/run/docker.sock testabc:1.0 /bin/bash
此方法实际上在容器内部创建一个子容器。仅当您确实要在容器中包含容器和镜像时才使用此方法。否则,我建议您使用第一种方法。为此,您只需要使用带有dind
标签的官方docker镜像即可。该dind映像使用Docker所需的实用程序进行制作以在Docker容器中运行。
注意:这要求您的容器以特权模式运行。 步骤1:建立dind-test以docker:dind镜像命名的容器 docker run --privileged -d --name dind-test docker:dind 步骤2:使用exec登录到容器。 docker exec -it dind-test /bin/sh
现在,您可以尝试使用Dockerfile构建映像,如先前方法所示。关键注意事项
- 仅在必要时在Docker中使用Docker。在将任何工作流程迁移到Docker-in-Docker方法之前,请进行足够的测试。
- 如果您打算使用Nestybox(Sysbox),请确保已通过企业架构师/安全团队的测试和批准。
- 在特权模式下使用容器时,请确保您已获得企业安全团队有关计划执行的必要批准。
- 在带有kubernetes容器的Docker中使用Docker时,存在一些挑战。请参阅此博客以了解更多信息。
二、Docker in Docker实战
# 基础镜像 FROM silverlogic/python3.6 # 描述 MAINTAINER python3.6+mysql5.6+redis # 添加必要秘钥,以便添加apt库 archive.ubuntu.com RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5 # 换中国源,其中archive.ubuntu.com用于安装mysql RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak \ && echo "deb http://mirrors.163.com/debian/ stretch main non-free contrib" >> /etc/apt/sources.list \ && echo "deb http://mirrors.163.com/debian/ stretch-updates main non-free contrib" >>/etc/apt/sources.list \ && echo "deb-src http://mirrors.163.com/debian/ stretch main non-free contrib" >>/etc/apt/sources.list \ && echo "deb-src http://mirrors.163.com/debian/ stretch-updates main non-free contrib" >>/etc/apt/sources.list \ && echo "deb http://archive.ubuntu.com/ubuntu trusty universe" >>/etc/apt/sources.list \ && apt-get update # 安装mysql5.6 RUN { \ echo mysql-server mysql-server/root_password password '123456'; \ echo mysql-server mysql-server/root_password_again password '123456'; \ } | debconf-set-selections \ && apt-get install -y mysql-server-5.6 mysql-client-5.6 # 装redis RUN apt install -y redis-server # 启动命令 ENTRYPOINT service mysql start && redis-server # 让进程一直跑, 否则容器会exit
sudo docker build -t python3.6-mysql-redis .
# 创建+启动容器, 如果启动不了, 需要调试并修改dockerfile或启动脚本.需要外部连接的就用-p 暴露端口 sudo docker run -itd -p 3308:3306 --name py_mysql_redis py_mysql_redis # 进入bash sudo docker exec -it python3.6-mysql-redis bash # 在容器里测试是否成功: mysql -uroot -p123456 redis-cli python # 数据库端口暴露之后,在容器内部可以访问,但是外部还是无法连接 进到 docker 容器里面修改一下mysql账号允许从远程登录就行, #by 后面是密码, 可自行修改。也是远程登录的密码 两条命令如下: grant all privileges on *.* to 'root'@'%' identified by '123456' with grant option; #刷新配置 flush privileges;
博文参考
原文链接:https://blog.csdn.net/weixin_41605937/article/details/123291284?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171836840916800185858249%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171836840916800185858249&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-17-123291284-null-null.nonecase&utm_term=docker%E3%80%81%E5%A5%BD%E7%94%A8