Docker容器内使用Docker——DinD与DooD

2023-09-13 18:27:16

DinD与DooD简介

在部分场景中,我们需要在Docker容器内操作Docker镜像。如,容器内实现对资源的监控、服务的打包、自动化构建等操作,这些操作都需要能够与Docker服务端实现交互来实现的。

在Docker容器内操作Docker有两种模式,分别为DinD(Docker in Docker):在Docker容器内部运行独立的Docker进程;DooD(Docker outside of Docker):运行在Docker容器外部的Docker,即在容器内部操作外部的Docker服务端。

DinD与DooD对比:

DinDDooD
原理在Docker容器内部安装独立的Docker客户端与服务端,实现容器内独立的的Docker操作在Docker容器内部安装独立的Docker客户端,将外部Docker服务端的.sock文件挂载在容器内部,通过内部客户端与挂载的.sock文件实现Docker操作
优点Docker服务端之间相互隔离,无干扰,缓存,适合需要独立隔离的环境能在容器内部实现与外部Docker服务端的交互,能够利用外部Docker外部服务端现有的镜像,缓存等资源
缺点无法利用缓存,Docker容器销毁后环境镜像丢失容器内部的操作会对外部Docker造成影响。不同容器可以查看同一宿主机的Docker daemon守护进程,并且不同实例可以修改统一Docker daemon下的镜像,存在安全问题。多个实例之间存在环境的争抢问题。

DinD与DooD的应用场景

当我们需要在容器内实现对Docker外部资源的监控时,需要在容器内有一定的手段能够访问到外部的Docker服务端,实现与外部Docker服务端进行通讯,获取到Docker服务端到信息实现对资源的监控。如,常用的监控工具Prometheus,Docker监控管理面板Portainer这些都是可以通过DooD的方式实现内部容器监控外部Docker资源情况。
在一些场景中,我们需要实现CI/CD等自动化集成等操作如Jenkins时,如果采用容器的方式部署,需要在如集成容器内部进行容器打包的情况下,可以采用DinD或者DooD的模式,实现容器内部的镜像打包登操作。

DooD构建Docker镜像

由于Docker对容器来运行Docker的做法做出一定限制,所以无法直接在Docker容器内按照Docker。如我们参考Docker安装文档的方式在容器内部安装Docker,只会安装Docker客户端。

构建DooD镜像

以Ubuntu:22.04镜像为基镜像,参考Docker引擎安装官方文档,构建DooD镜像。

DooD镜像Dockerfile:

FROM ubuntu:22.04

RUN \
    # Add Docker's official GPG key:
    apt update && \
    apt install -y ca-certificates curl gnupg && \
    install -m 0755 -d /etc/apt/keyrings && \
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
    chmod a+r /etc/apt/keyrings/docker.gpg && \
    # Add the repository to Apt sources:
    echo \
        "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
        "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
        tee /etc/apt/sources.list.d/docker.list > /dev/null && \
    apt update && \
    # Install the Docker packages.
    apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

CMD [ "bash" ]

DooD镜像的构建命令:

docker build . \
    --file ./Dockerfile \
    --tag "ubuntu:dood"

运行DooD镜像

直接运行Docker

打包后直接运行DooD镜像:

docker run -it ubuntu:dood bash

调用Docker命令:

root@17f49a00974d:/# docker version
Client: Docker Engine - Community
 Version:           24.0.6
 API version:       1.43
 Go version:        go1.20.7
 Git commit:        ed223bc
 Built:             Mon Sep  4 12:31:44 2023
 OS/Arch:           linux/amd64
 Context:           default
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

如上命令所示,调用docker version后。Docker客户端日志信息输出正常,但是服务端却显示Cannot connect to the Docker daemon at unix:///var/run/docker.sock.。我们平常在Docker客户端执行的命令实际上是Docker的客户端进程,实际上Docker如打包镜像,运行容器,拉取镜像登操作都是由Docker服务端操作的,Docker客户端实现通过命令来调用服务端。

DooD模式运行Docker

通过.sock后缀可以看到,Docker的客户端和服务端实际上是通过socket机制进行的通讯。在采用DooD模式的情况下,我们可以讲外部的Docker服务端socket文件挂载在内部容器中,实现在容器内部,借助外部socket进行通讯,完成Docker调用。

DooD模式运行DooD镜像:

docker run -it -v /var/run/docker.sock:/var/run/docker.sock ubuntu:dood bash

调用Docker命令:

root@ff54c629edd0:/# docker version
Client: Docker Engine - Community
 Version:           24.0.6
 API version:       1.41 (downgraded from 1.43)
 Go version:        go1.20.7
 Git commit:        ed223bc
 Built:             Mon Sep  4 12:31:44 2023
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Desktop 4.17.0 (99724)
 Engine:
  Version:          20.10.23
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.18.10
  Git commit:       6051f14
  Built:            Thu Jan 19 17:32:04 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.18
  GitCommit:        2456e983eb9e37e47538f59ea18f2043c9a73640
 runc:
  Version:          1.1.4
  GitCommit:        v1.1.4-0-g5fd4c4d
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

如上命令所示,通过挂载/var/run/docker.sock文件后启动DooD镜像,调用Docker命令不仅打印出容器内部Docker客户端的日志,也打印出了外部Docker服务端的日志。此时,我们在容器内部调用Docker命令,实际上就是交由外部的Docker服务端来进行操作,所以在容器内部的Docker操作会同步到外部宿主机中。

DinD构建Docker镜像

通过官方dind镜像使用dind模式的docker

由于Docker的限制,不可以直接在Docker里面安装Docker服务端,但是Docker官方有提供构建好的DinD镜像docker:dind

由于docker本质上是一种隔离技术,在Docker容器内部仍需要访问到外部的Linux资源。在DinD模式下运行Docker,也需要访问到外部Linux内核中的资源,有些资源需要root权限才可以访问。所以在启动DinD镜像时,需要添加--privileged参数,开启Docker容器到特权模式,否则容器内部无法访问特定资源。

启动官方DinD镜像:

docker run -it --privileged docker:dind bash

本地构建DinD镜像

由于Docker本身只是一种服务隔离技术,并不是传统意义上的虚拟机,并不能完全的虚拟化模拟软硬件资源,在容器的运行中还是需要访问外部资源,且由于Docker底层采用UnionFS文件系统。所以无法通过安装的方式安装Docker服务端。Docker提供有二进制免安装文件,通过二进制免安装文件,可以在一定程度上不完全依赖外部的环境,实现Docker内部访问Docker资源。

访问GitHub的docker镜像构建仓库阅读代码可知,Docker官方的dind镜像也是通过二进制文件实现的。

Docker在使用时,需要依赖一些证书和库,所以我们可以参考Docker引擎安装官方文档添加必要的仓库但不执行后续的Docker安装操作,然后安装二进制运行依赖库即可。在ubuntu:22.04镜像中,只需要额外安装iptables库即可。

下载解压二进制Docker文件

Docker官方提供了Docker的二进制文件供无网络或免安装环境下使用,可在Docker官网提供的下载地址下载对应版本的Dokcer二进制包tgz文件。

以docker-24.0.6.tgz为例,进行下载解压

# Docker二进制文件下载
wget https://download.docker.com/linux/static/stable/x86_64/docker-24.0.6.tgz

# Docker二进制文件解压
docker -xzvf docker-24.0.6.tgz
  • Docker软件分为客户端进程和服务端进程,Docker的二进制软件同样也有服务端进程dockerdcontainerd
    • dockerdcontainerd进程需要以守护进程的方式在后端运行
    • dockerd进程依赖于containerdrunc进程
      • 需要先以nohup command &的方式启动containerdrunc进程
      • 确保依赖库安装后,依赖进程启动后,以nohup command &方式启动dockerd进程
  • dockerd服务端守护进程启动后,即可通过docker二进制文件操作docker

构建DinD镜像

ubuntu:22.04镜像为基,构建dind镜像

DinD镜像Dockerfile:

FROM ubuntu:22.04

COPY ./docker /data/docker

WORKDIR /data/docker

RUN \
    # Add Docker's official GPG key:
    apt update && \
    apt install -y ca-certificates curl gnupg && \
    install -m 0755 -d /etc/apt/keyrings && \
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
    chmod a+r /etc/apt/keyrings/docker.gpg && \
    # Add the repository to Apt sources:
    echo \
        "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
        "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
        tee /etc/apt/sources.list.d/docker.list > /dev/null && \
    apt update && \
    apt install -y iptables

# Add docker to environment
ENV PATH="/data/docker:${PATH}"

CMD [ "bash" ]

DinD镜像打包命令:

docker build . \
    --file ./Dockerfile \
    --tag "ubuntu:dind"

运行DinD镜像

DinD镜像的运行需要在特权模式下运行。同时,启动容器后,需要依次以守护进程的方式启动runccontainerddockerd等进程,才可以以DinD的模式访问Docker。

特权模式启动dind镜像:

docker run -it --privileged ubuntu:dind bash

启动守护进程:

nohup runc &
nohup containerd &
nohup dockerd &

运行Docker命令:

root@a09d8ec17a42:/data/docker# docker version
Client:
 Version:           23.0.6
 API version:       1.42
 Go version:        go1.19.9
 Git commit:        ef23cbc
 Built:             Fri May  5 21:13:15 2023
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          23.0.6
  API version:      1.42 (minimum version 1.12)
  Go version:       go1.19.9
  Git commit:       9dbdbd4
  Built:            Fri May  5 21:14:22 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.6.21
  GitCommit:        3dce8eb055cbb6872793272b4f20ed16117344f8
 runc:
  Version:          1.1.7
  GitCommit:        v1.1.7-0-g860f061
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

如上命令所示,我们即打印了Docker的客户端和服务端信息。同时,当我们拉取镜像操作时,也可以看到,外部的Docker并不会发生变化,即通过DinD模式成功运行Docker,实现与外部环境的隔离。

更多推荐

【腾讯云 Cloud Studio 实战训练营】基于Python实现的快速抽奖系统

文章目录⭐️CloudStudio-简介🌟操作步骤🌟注册CloudStudio🌟创建工作空间🌟启动对应的开发环境⭐️抽奖系统项目介绍⭐️抽奖系统代码结构图⭐️项目基础类-文件检查🌟base.py基础类文件检查示例如下:🌟common模块的error.py脚本的代码如下:🌟utils.py模块check_f

CRM软件系统趣味性——游戏化销售管理

对于企业销售来说,高薪酬也伴随着更高的压力与挑战。高强度的单一工作会让销售人员逐渐失去对工作的兴趣,导致售状态缺少动力和激情,工作开展愈加困难。您可以通过CRM系统进行游戏化销售管理,让销售人员重新干劲满满。游戏并不是纯粹的娱乐,它其实还是提升个人竞争意识、团队协作的一种方式,因此,将它一味的妖魔化是不可取的。也正因如

Linux 中nc指令的使用总结

nc指令概述用法一:端口扫描用法二:命令行中发送和接收数据用法三:建立双方通信nc指令概述nc是Linux系统中的netcat命令之简称,它是一个强大的网络工具,可以用于创建TCP/UDP套接字连接。常见的其用法模板可定位:nc[选项][地址][端口],它的用法如下图所示:知道你英语差了一丢丢,小鸽鸽给你准备了中文版:

【C++】string类模拟实现下篇(附完整源码)

目录1.resize2.流插入<<和流提取>>重载2.1流插入<<重载2.2流提取<<3.常见关系运算符重载4.赋值重载4.1浅拷贝的默认赋值重载4.2深拷贝赋值重载实现4.3赋值重载现代写法5.写时拷贝(了解)6.源码6.1string.h6.2test.cpp1.resize下面我们来实现一下resize():re

【C++ 程序设计】实战:C++ 实践练习题(21~30)

目录21.计算并输出1到9之间奇数之和22.多层嵌套计算23.循环结构:打印变量a、b、c24.函数调用:全局变量、局部变量25.找到数组中不等于最大值和最小值的元素26.计算:平方根、平方、立方根、立方27.找出三个整型数中的最大值28.初始化一个5x5的二维数组a,根据表达式(i+1)*(j+1)将数组元素设置为i

【UML】软件工程中常用图:类图、部署图、时序图、状态图

作者简介:前言:UML中的很多东西平时都听过、用过,诸如类图、时序图等,本文将详细详细讲一下UML中常用的几类图,并且会引入一个完整的例子来讲解,UML在工程上到底该怎么合理使用。目录1.概述1.1.什么是UML?1.2.UML用在何处?2.静态结构2.1.类图2.2.部署图3.描述动态3.1.顺序图3.2.状态图4.

【UML】详解UML类图

目录1.概述2.权限3.关系3.1.连线关系3.2.依赖3.3.泛化(继承)3.4.实现3.5.关联3.6.聚合3.7.组合1.概述UML是什么?书面化一点的说法是:UML(UnifiedModelingLanguage),统一建模语言,是一种用于软件工程和系统设计的标准图形化建模语言。它旨在帮助开发人员、设计师和分析

8年经验之谈 —— App测试常用的两种工具

一、监控工具DDMS的全称是DalvikDebugMonitorService,是Android开发环境中的Dalvik虚拟机调试监控服务。提供测试设备截屏、查看特定进程正在运行的线程以及堆信息、Logcat、广播状态信息、模拟电话呼叫、模拟接收及发送SMS、虚拟地理坐标等服务。启动DDMSEclipse中启动方法:1

Java 泛型

一、泛型简介Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。下面给一个Java泛型的简单例子:publicstatic<E>voidprintArray(E[]in

【产品运营】如何提升B端产品竞争力(下)

“好产品不是能力内核,做好产品的流程才是”一、建立需求池和需求反馈渠道需求池管理是B端产品进化最重要的环节,它的重要性远超产品设计、开发等其他环节。维护需求池有主动和被动两种。主动维护是产品经理在参与售前、迭代、交付、售后、竞品分析、老板沟通等活动时自己发掘、记录需求,主动收集需求的渠道很多,但不同渠道收集到的需求质量

两届 TOKEN 2049 之间,孙宇晨和波场的布局与野心

2022年在新加坡举办的TOKEN2049大会上,波场TRON创始人、火币全球顾问委员会成员孙宇晨作为特邀嘉宾出席,并曾提出“波场TRON下一步的发展目标是成为主流金融机构”的生态愿景,揭示了波场生态的全新发展方向,以及孙宇晨作为区块链和加密技术的长期布道者,对加密行业未来发展趋势的展望。时隔一年,2023TOKEN2

热文推荐