当前位置:首页 » 硬盘大全 » docker元数据缓存区
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

docker元数据缓存区

发布时间: 2022-09-25 23:06:03

❶ Docker镜像存储格式分析

新版本的docker镜像存储其实是很绕的,各种ID和目录定义较多,不是很直观,本文较详细的分析一下镜像本地存储和在registry存储的格式。测试用的docker版本是20.10.9,存储引擎overlay2。

为了方便分析镜像层级结构,我们基于ubuntu加两个文件,使用 docker build -t myubuntu . 创建一个新镜像myubuntu。

镜像元数据存储在 /var/lib/docker/image/overlay2 :

imagedb目录存储的是镜像元数据。

镜像ID是从Image Json文件得到的,即 sha256sum(ImageJson)。

Layer DiffID是没有压缩的对应层的tar文件的sha256sum值。当然,打包和截包文件的适合得保证是可以可重复操作的,不然会导致Layer的DiffID出错(可以使用tar-split保存tar headers)。比如上面例子中ubuntu镜像只有一层,diff_ids列表只有 (history里面的CMD不占磁盘空间) "sha256:"。每一层的tar文件我们可以通过 docker save ubuntu -o ubuntu.tar 得到,解压ubuntu.tar后可以得到对应的层级的打包后的layer.tar文件,如下可以验证DiffID的值计算原理。

ChainID用于标识镜像层级栈,它的值由DiffID计算得来。ChainID对应的layer目录是 /var/lib/docker/image/overlay2/layerdb/sha256 ,这下面的目录就是ChainID,其中内容存储了镜像的层级栈关系。比如这一层的parent是什么,以及对应的镜像数据存储目录的cache_id。本身layerdb只是存储layer的元数据信息,并不存储实际镜像数据。

即最底层的ChainID跟DiffID一样,而其他层的ChainID则是通过计算从最底层到这层的Digest得到。

查看Image Json文件可以看到myubuntu相比ubuntu的diff_ids加了两层,imagedb目录下面也多了两个镜像元数据信息文件,对应新增加的两层镜像。

除了之前的350f...对应ubuntu,其中7c7e是one.txt那层,而a58f则是two.txt那层。

我们可以看下ChainID目录下的内容,可以看到除了ubuntu的基础层,其他层都有一个文件parent,值就是父层的diff_id,diff是diff_id值,cache-id则是镜像实际存储目录,位于 /var/lib/docker/overlay2/{cache-id} ,size是这一层实际增加文件的大小,tar-split.json.gz是打包这层镜像的配置(参考 https://github.com/vbatts/tar-split )。

CacheID是一个uuid值,每次都不一样。它对应的目录 /var/lib/docker/overlay2/${CacheID} ,该目录存储了镜像每层文件和下一层的链接等。验证一下:

其中diff目录下面便是这一层的文件。link是对应的diff目录的短链接,lower则是下一层diff目录的短链接。

在layerdb目录的size文件可以看到每一层的镜像大小,但是加起来跟 docker images 显示的大小会有点差距,比如myubuntu镜像每一层计算加起来是 4 + 65593591 + 4 = 65593599 / 1024 / 1024 = 62.55MiB ,实际显示是 65.6MB,这是因为 docker images 里面计算是按 65593599/1000/1000=65.59 计算的。

另外,因为镜像每层记录的是相对前一层的文件变化,即便删除了文件和软件包,新镜像大小也不会变小。除非使用 docker export 重新导出一个新镜像。

这个目录存储的是layer diffid和digest的关系,其中digest是镜像仓库里面的目录ID。

其中 v2metadata-by-diff存储了layer diffid对应在镜像仓库的信息,包括digest,sourcerepository等。

diffid-by-digest则是反过来的,文件名是仓库里面的layer digest,内容是layer diffid。因为我们新加的镜像myubuntu并没有push到仓库,所以这个目录下面没有信息。

我们创建一个本地的registry,然后对myubuntu另外打个tag, docker tag myubuntu 127.0.0.1:5000/myubuntu ,则respositories.json会多一条新的记录。此时,distribution目录还没有变化。

当我们执行 docker push 127.0.0.1:5000/myubuntu ,则会发现distribution的两个目录分别多了两条记录,对应的是myubuntu的 7c7e... 和 a58f... 两个diffid。此时repository.json里面 127.0.0.1:5000/myubuntu 会多一条带digest的记录,这就是镜像仓库里面对应的digest。其中push时显示的 digest:sha256:bb3c... 对应的是registry的manifest文件的digest,下一节分析。

registry中存储的镜像文件是经过gzip压缩,比如myubuntu本地大小是65.6MB,推到registry压缩后大小约27MB,压缩比还是不错的。registry存储目录如下,主要分为blobs和repositories两个目录。

repositories的一级子目录是镜像名,这里是myubuntu。下面对应三个子目录 _manifests,_layers, _uploads。

blobs存储的内容除了各镜像layer的压缩后的文件,还包括Manifest Json和Image Json文件(未压缩)。

选一个layer的压缩文件data解压看一下内容:

另外需要注意的是, docker pull 时前面显示的值是对应层在registry的压缩文件的digest值,并不是layer diffid,size也是registry存储的压缩文件大小。

❷ Docker的主要作用是什么

目前来看,Docker至少有以下应用场景:

1)测试:Docker 很适合用于测试发布,将 Docker 封装后可以直接提供给测试人员进行运行,不再需要测试人员与运维、开发进行配合,进行环境搭建与部署。

2)测试数据分离:在测试中,经常由于测试场景变换,需要修改依赖的数据库数据或者清空变动 memcache、Redis 中的缓存数据。Docker 相较于传统的虚拟机,更轻量与方便。可以很容易的将这些数据分离到不同的镜像中,根据不同需要随时进行切换。

3)开发:开发人员共同使用同一个 Docker 镜像,同时修改的源代码都被挂载到本地磁盘。不再因为环境的不同而造成的不同程序行为而伤透脑筋,同时新人到岗时也能迅速建立开发、编译环境。

4)PaaS 云服务:Docker 可以支持命令行封装与编程,通过自动加载与服务自发现,可以很方便的将封装于 Docker 镜像中的服务扩展成云服务。类似像 Doc 转换预览这样的服务封装于镜像中,根据业务请求的情况随时增加和减少容器的运行数量,随需应变。

具体到Docker技术在测试领域的应用,可以体现在:

1)快速搭建兼容性测试环境

从Docker的镜像与容器技术特点可以预见,当被测应用要求在各类Web服务器、中间件、数据库的组合环境中得到充分验证时,可以快速地利用基础Docker镜像创建各类容器,装载相应的技术组件并快速启动运行,测试人员省去了大量花在测试环境搭建上的时间。

2)快速搭建复杂分布式测试环境

Docker的轻量虚拟化特点决定了它可以在一台机器上(甚至是测试人员的一台笔记本电脑上)轻松搭建出成百上千个分布式节点的容器环境,从而模拟以前需要耗费大量时间和机器资源才能搭建出来的分布式复杂测试环境。

3)持续集成

Docker可以快速创建和撤销容器,在持续集成的环境中,可以频繁和快速地进行部署和验证工作。

❸ docker的容器常规操作

解释:创建一个容器,但容器处于停止状态

解释:启动容器

解释:
-t : 让Docker分配一个伪终端并绑定到容器的标准输入上
-i: 让容器的标准输入保持打开
-d: 让Docker容器在后台以守护态运行

解释:
-details:打印详细信息
-f,-follow:保持持续输出
-since string:输出从某个时间开始的日志
-tail string:输出最近的若干日志
-t,-timestamps:输出时间戳信息
-until string:输出某个时间之前的日志

解释:暂停容器,暂停后,容器处于paused状态

解释:将paused状态的容器恢复至运行状态

解释: 终止一个运行状态的容器,但是这个终止不是立即执行的。该命令会先向容器发送一个SIGTERM信号,等待一段超时时间(默认为10s)后,再发送SIGKILL信号终止容器,而终止容器的关键就在于SIGKILL信号。

解释: 终止一个运行状态的容器,但是这个终止是立即执行的。该命令直接发送SIGKILL信号强行终止容器。

解释: 重启容器

解释:进入容器。使用这个命令有时候并不方便,当多个窗口同时attach到同一个容器的时候,所有窗口都会同步显示;当某个窗口因命令阻塞时,其他窗口也无法执行操作;默认使用CTRL+q或者CTRL+p退出容器

解释:
-d,--detach:在容器中后台执行命令
--detach-keys="":指定将容器切回后台的案件
-e,--env=[]:指定环境变量列表
-i,--interactive=true|false:打开标准输入接收用户输入命令,默认值为false
--privileged=true|false:是否给执行命令以高权限,默认值为false
-t,--try=true|false:分配伪终端,默认值为false
-u,--user="":执行命令的用户名或ID

解释:
删除处于退出或者终止状态的容器
-f,--force=false:是否强行终止并删除一个处于运行状态的容器
-l,--link=false:删除容器的链接,但保留容器
-v,--volumns=false:删除容器挂载的数据卷

解释:导出容器。导出一个已经创建的容器到文件,不管此时这个容器是否处于运行状态。在这里如果把export换成save,再把af18换成镜像名称:tag,就是导出镜像的命令了。但是这两个命令的区别在于:docker export命令丢弃了原容器的历史信息及元数据,而docker save命令会保留原文件的历史信息。

解释:将导出的文件变成镜像。当然,这个也可以用docker load命令来执行。

解释:查看容器具体信息,比如:容器ID,创建时间,路径,状态,镜像,配置等

解释: 查看容器内进程信息

解释:查看容器的内存、CPU、存储、网络等使用情况
-a,-all:输出所有容器统计信息
-format string: 格式化输出信息
-no-stream:不持续输出,默认会自动更新持续实时结果
-no-trunc:不截断输出信息

解释:第一行命令为将test容器的temp文件夹复制到主机的data文件夹下
第二行的命令为将主机的data文件夹复制到test容器的tmp文件夹下

解释:查看容器内的数据修改

解释:查看test容器的端口映射情况

解释:修改容器的一些运行时配置。主要是一些资源限制配额。

❹ Dock基本原理

这篇文章希望能够帮助读者深入理解Docker的命令,还有容器(container)和镜像(image)之间的区别,并深入探讨容器和运行中的容器之间的区别。

当我对Docker技术还是一知半解的时候,我发现理解Docker的命令非常困难。于是,我花了几周的时间来学习Docker的工作原理,更确 切地说,是关于Docker统一文件系统(the union file system)的知识,然后回过头来再看Docker的命令,一切变得顺理成章,简单极了。

题外话:就我个人而言,掌握一门技术并合理使用它的最好办法就是深入理解这项技术背后的工作原理。通常情况 下,一项新技术的诞生常常会伴随着媒体的大肆宣传和炒作,这使得用户很难看清技术的本质。更确切地说,新技术总是会发明一些新的术语或者隐喻词来帮助宣 传,这在初期是非常有帮助的,但是这给技术的原理蒙上了一层砂纸,不利于用户在后期掌握技术的真谛。

Git就是一个很好的例子。我之前不能够很好的使用Git,于是我花了一段时间去学习Git的原理,直到这时,我才真正明白了Git的用法。我坚信只有真正理解Git内部原理的人才能够掌握这个工具。

镜像(Image)就是一堆只读层(read-only layer)的统一视角,也许这个定义有些难以理解,下面的这张图能够帮助读者理解镜像的定义。

从左边我们看到了多个只读层,它们重叠在一起。除了最下面一层,其它层都会有一个指针指向下一层。这些层是Docker内部的实现细节,并且能够 在主机(译者注:运行Docker的机器)的文件系统上访问到。统一文件系统(union file system)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。 我们可以在图片的右边看到这个视角的形式。

你可以在你的主机文件系统上找到有关这些层的文件。需要注意的是,在一个运行中的容器内部,这些层是不可见的。在我的主机上,我发现它们存在于/var/lib/docker/aufs目录下。

<pre class="prettyprint" style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; color: rgb(57, 57, 57); font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(250, 247, 239); text-decoration-style: initial; text-decoration-color: initial;">/var/lib/docker/
├── aufs
├── containers
├── graph
├── init
├── linkgraph.db
├── repositories-aufs
├── tmp
├── trust
└── volumes
7 directories, 2 files</pre>

容器(container)的定义和镜像(image)几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。

细心的读者可能会发现,容器的定义并没有提及容器是否在运行,没错,这是故意的。正是这个发现帮助我理解了很多困惑。

要点:容器 = 镜像 + 可读层。并且容器的定义并没有提及是否要运行容器。

接下来,我们将会讨论运行态容器。

一个运行态容器(running container)被定义为一个可读写的统一文件系统加上隔离的进程空间和包含其中的进程。下面这张图片展示了一个运行中的容器。

正是文件系统隔离技术使得Docker成为了一个前途无量的技术。一个容器中的进程可能会对文件进行修改、删除、创建,这些改变都将作用于可读写层(read-write layer)。下面这张图展示了这个行为。

我们可以通过运行以下命令来验证我们上面所说的:

<pre class="prettyprint" style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; color: rgb(57, 57, 57); font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(250, 247, 239); text-decoration-style: initial; text-decoration-color: initial;">docker run ubuntu touch happiness.txt</pre>

即便是这个ubuntu容器不再运行,我们依旧能够在主机的文件系统上找到这个新文件。

<pre class="prettyprint" style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; color: rgb(57, 57, 57); font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(250, 247, 239); text-decoration-style: initial; text-decoration-color: initial;">/var/lib/docker/aufs/diff/860a7b...889/happiness.txt</pre>

为了将零星的数据整合起来,我们提出了镜像层(image layer)这个概念。下面的这张图描述了一个镜像层,通过图片我们能够发现一个层并不仅仅包含文件系统的改变,它还能包含了其他重要信息。

元数据(metadata)就是关于这个层的额外信息,它不仅能够让Docker获取运行和构建时的信息,还包括父层的层次信息。需要注意,只读层和读写层都包含元数据。

除此之外,每一层都包括了一个指向父层的指针。如果一个层没有这个指针,说明它处于最底层。

Metadata Location:
我发现在我自己的主机上,镜像层(image layer)的元数据被保存在名为”json”的文件中,比如说:

<pre class="prettyprint" style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; color: rgb(57, 57, 57); font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(250, 247, 239); text-decoration-style: initial; text-decoration-color: initial;">/var/lib/docker/graph/e809f156dc985.../json</pre>

e809f156dc985...就是这层的id

一个容器的元数据好像是被分成了很多文件,但或多或少能够在/var/lib/docker/containers/<id>目录下找到,<id>就是一个可读层的id。这个目录下的文件大多是运行时的数据,比如说网络,日志等等。

现在,让我们结合上面提到的实现细节来理解Docker的命令。

docker create 命令为指定的镜像(image)添加了一个可读写层,构成了一个新的容器。注意,这个容器并没有运行。

Docker start命令为容器文件系统创建了一个进程隔离空间。注意,每一个容器只能够有一个进程隔离空间。

看到这个命令,读者通常会有一个疑问:docker start 和 docker run命令有什么区别。

从图片可以看出,docker run 命令先是利用镜像创建了一个容器,然后运行这个容器。这个命令非常的方便,并且隐藏了两个命令的细节,但从另一方面来看,这容易让用户产生误解。

题外话:继续我们之前有关于Git的话题,我认为docker run命令类似于git pull命令。git pull命令就是git fetch 和 git merge两个命令的组合,同样的,docker run就是docker create和docker start两个命令的组合。

docker ps 命令会列出所有运行中的容器。这隐藏了非运行态容器的存在,如果想要找出这些容器,我们需要使用下面这个命令。

docker ps –a命令会列出所有的容器,不管是运行的,还是停止的。

docker images命令会列出了所有顶层(top-level)镜像。实际上,在这里我们没有办法区分一个镜像和一个只读层,所以我们提出了top-level 镜像。只有创建容器时使用的镜像或者是直接pull下来的镜像能被称为顶层(top-level)镜像,并且每一个顶层镜像下面都隐藏了多个镜像层。

docker images –a命令列出了所有的镜像,也可以说是列出了所有的可读层。如果你想要查看某一个image-id下的所有层,可以使用docker history来查看。

docker stop命令会向运行中的容器发送一个SIGTERM的信号,然后停止所有的进程。

docker kill 命令向所有运行在容器中的进程发送了一个不友好的SIGKILL信号。

docker stop和docker kill命令会发送UNIX的信号给运行中的进程,docker pause命令则不一样,它利用了cgroups的特性将运行中的进程空间暂停。具体的内部原理你可以在这里找到: https://www.kernel.org/doc/Doc ... m.txt ,但是这种方式的不足之处在于发送一个SIGTSTP信号对于进程来说不够简单易懂,以至于不能够让所有进程暂停。

docker rm命令会移除构成容器的可读写层。注意,这个命令只能对非运行态容器执行。

docker rmi 命令会移除构成镜像的一个只读层。你只能够使用docker rmi来移除最顶层(top level layer)(也可以说是镜像),你也可以使用-f参数来强制删除中间的只读层。

docker commit命令将容器的可读写层转换为一个只读层,这样就把一个容器转换成了不可变的镜像。

docker build命令非常有趣,它会反复的执行多个命令。

我们从上图可以看到,build命令根据Dockerfile文件中的FROM指令获取到镜像,然后重复地1)run(create和start)、2)修改、3)commit。在循环中的每一步都会生成一个新的层,因此许多新的层会被创建。

docker exec 命令会在运行中的容器执行一个新进程。

docker inspect命令会提取出容器或者镜像最顶层的元数据。

docker save命令会创建一个镜像的压缩文件,这个文件能够在另外一个主机的Docker上使用。和export命令不同,这个命令为每一个层都保存了它们的元数据。这个命令只能对镜像生效。

docker export命令创建一个tar文件,并且移除了元数据和不必要的层,将多个层整合成了一个层,只保存了当前统一视角看到的内容(译者注:expoxt后 的容器再import到Docker中,通过docker images –tree命令只能看到一个镜像;而save后的镜像则不同,它能够看到这个镜像的历史镜像)。

docker history命令递归地输出指定镜像的历史镜像。

❺ Docker(5)——数据管理

docker 容器的文件系统在宿主机上存在的方式很复杂,这会带来下面几个问题:

为了能够 保存(持久化) 数据以及 共享 容器间的数据,docker 引入了数据卷(volume) 机制。数据卷是存在于一个或多个容器中的特定文件或文件夹,它可以绕过默认的联合文件系统,以正常的文件或者目录的形式存在于宿主机上。

其生存周期独立于容器的生存周期。

容器中主要有 两种 管理数据方式: 数据卷(Data Volumes) 数据卷容器(Data Volume Containers)

数据卷是一个可供容器使用的特殊目录,它绕过文件系统,可以提供很多有用的特性:

数据卷的使用类似 linux 下对目录或文件进行 mount 操作,目前Docker提供了 三种 不同的方式将数据从宿主机挂载到容器中,分别是

其中 volume 、 bind mount 比较常用, tmpfs mount 基本不会用.

volumes作为Docker管理宿主机文件系统的一部分 ,默认位于 /var/lib/docker/volumes 目录中,不是宿主机已有数据,而是新建的。

docker 专门提供了 volume 子命令来操作数据卷:

先创建一个名称为 hello 的数据卷并通过 ls 命令进行查看:

然后可以使用 inspect 命令看看数据卷hello的详细信息

该数据卷使用的 Driver 为默认的 local ,表示数据卷使用宿主机的本地存储;

Mountpoint 是 volumes 的挂载点,默认是本机 /var/lib/docker/volumes 下的一个目录。

所有Container的数据都保存在了这个目录下边,由于没有在创建时指定卷,所以Docker帮我们默认创建许多匿名卷。

使用 -v 选项也可以指定挂载一个本地的已有目录到容器中去作为数据卷:
docker run -it –-name robot1 -v /var/data:/opt/mydata ros/kinetic /bin/bash
上面的命令挂载主机的 /var/data 目录到容器的 /opt/mydata 目录。

这个功能在测试的时候特别方便,比如用户可以放置一些程序或数据到本地目录中,然后在容器中使用。另外,本地目录的路径必须是绝对路径,如果目录不存在,Docker 会自动创建。
Docker 挂载数据卷的默认权限是可读写 rw ,用户也可以通过 ro 标记指定为只读:
docker run -it –-name robot1 -v /var/data:/opt/mydata:ro ros/kinetic /bin/bash
加了 :ro 之后,容器内挂载的数据卷内的数据就变成只读的了。

除了把数据卷中的数据存储在宿主机,docker 还允许我们通过指定 volume driver 的方式把数据卷中的数据存储在其它的地方,比如 Azrue Storge 或 AWS 。

通过 vieux/sshfs 驱动把数据卷的存储在云主机上,docker 默认是不安装 vieux/sshfs 插件的,我们可以通过下面的命令进行安装:
docker plugin install --grant-all-permissions vieux/sshfs

然后通过 vieux/sshfs 驱动创建数据卷,并指定远程主机的登录用户名、密码和数据存放目录:

注意:确保指定的远程主机上的挂载点 /home/nick/sshvolume 目录是存在的,否则在启动容器时会报错。

最后在启动容器时指定挂载这个数据卷:

在容器中 /world 目录下操作的文件都存储在远程主机的 /home/nick/sshvolume 目录中。进入容器 testcon 然后在 /world 目录中创建一个文件,然后打开远程主机的 /home/nick/sshvolume 目录进行查看,新建的文件会出现在那里。

当使用 bind mounts 将主机上的目录挂载到容器中时,目录由其在主机上的完整或相对路径引用。

bind mount 和 volume 其实都是利用宿主机的文件系统,不同之处在于volume是docker自身管理的目录中的子目录,所以不存在权限引发的挂载的问题,并且目录路径是docker自身管理的,所以也不需要在不同的服务器上指定不同的路径,不需要关心路径

bind mounts 可以挂载在宿主机系统的任意位置 ,但 bind mount 在不同的宿主机系统是不可移植的,比如Windows和Linux的目录结构是不一样的, bind mount 所指向的 host 目录也不能一样。这也是为什么 bind mount 不能出现在Dockerfile中的原因,因为这样Dockerfile就不可移植了。

如果使用 Bind mounts 挂载 宿主机目录 容器内非空目录 ,那么 此容器中的非空目录中的文件会被隐藏 ,容器访问这个目录时能够访问到的文件均来自于宿主机目录。这也是Bind mounts模式和Volumes模式最大的行为上的不同。

挂载存储在宿主机系统的内存中,而不会写入宿主机的文件系统;

这张图说明 bind mount 和 volume 其实都是利用宿主机的文件系统, Bind mounts 模式是将宿主机上的任意文件或文件夹挂载到容器,而 Volumes 本质上是将Docker服务管理的一块区域(默认是 /var/lib/docker/volumes 下的文件夹)挂载到容器。所以 volume 不存在权限引发的挂载的问题,并且目录路径是docker自身管理的,所以也不需要在不同的服务器上指定不同的路径,不需要关心路径。

相对于 bind mount , volume 是Docker Engine在自己的“地盘”分配了一个路径作为挂载点,自己地盘的权限肯定是安排的明明白白。所以,以上挂载宿主机路径的问题都解决了。

在使用 volume 作为数据卷挂载到容器时,直接用 volume 名称代替宿主机路径名就行:
docker run -d -v test_vol:/var/data some_image

这样就将数据卷 test_vol 挂载到了容器内的 /var/data 目录下。

命名的容器挂载数据卷,其它容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器

可以利用数据卷容器对其中的数据卷进行备份、恢复,以实现数据的迁移。

备份
使用下面的命令来备份 mydata 数据卷容器内的数据卷:

sudo docker run --volumes-from mydata -v $(pwd):/backup –-name worker ubuntu tar cvf /backup/backup.tar /data
这个命令首先利用 Ubuntu 镜像创建了一个容器 worker。又使用 --volumes-from mydata 参数来让 worker 容器挂载 mydata 容器的数据卷。接下来使用 -v $(pwd):/backup 参数来挂载本地的当前目录到 worker 容器的 /backup 目录。
在 worker 容器启动后,使用了 tar cvf /backup/backup.tar /data 命令来将 /data 下内容备份为容器内的 /backup/backup.tar,即宿主主机的当前目录下的backup.tar。

恢复
如果要恢复数据到一个容器,可以按照下面的操作。首先创建一个带有数据卷的容器 mydata2:

sudo docker run -v /data –-name mydata2 ubuntu /bin/bash
然后创建另一个新的容器,挂载 mydata2 的数据卷,并使用 tar 解压缩备份文件到所挂载的容器卷中:

sudo docker run --volumes-from mydata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar

如果用户需要在容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器其实就是一个普通的容器,专门用它提供数据卷供其他容器挂载。下面简单介绍其使用方法。

首先要创建一个数据卷容器 mydata,并在其中创建一个数据卷挂载到 /data 目录。

sudo docker run -it -v /data –-name mydata ubuntu
然后在其他容器中使用 --volumes-from 来挂载 mydata 容器中的数据卷。例如创建两个容器 mycon1 和 mycon2,并从 mydata 容器挂载数据卷:

sudo docker run -it --volumes-from mydata –-name mycon1 ubuntu
sudo docker run -it --volumes-from mydata –-name mycon2 ubuntu
(注意,命令中没有指定数据卷的信息,也就是说新容器中挂载数据卷的目录和源容器中是一样的。)

此时容器 mycon1 和 mycon2 都挂载同一个数据卷到相同的目录 /data。三个容器任何一个在该目录下写入数据其他容器都能看到。
可以多次使用 --volumes-from 参数来从多个容器挂载多个数据卷。还可以从其他已经挂载了容器的容器来挂载数据卷。并且使用 --volumes-from 参数所挂载数据卷的容器自身并不需要保持在运行状态。
但删除挂载了数据卷的容器时,数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显式的使用 docker rm -v 命令来指定同时删除关联的容器。

如何对已经运行的容器挂载目录?
https://blog.51cto.com/hjun169/2440799
手动修改mount挂载的json文件,狂神的那个视频里面也有写。

深刻理解Docker镜像大小
https://blog.csdn.net/shlazww/article/details/47375009

理解docker的分层镜像实现 base 镜像共享(DockerFile)
https://blog.csdn.net/lu_1110/article/details/106533490

❻ Docker存储驱动之--overlay2

docker支持多种graphDriver,包括vfs、devicemapper、overlay、overlay2、aufs等等,其中最常用的就是aufs了,但随着linux内核3.18把overlay纳入其中,overlay的地位变得更重,最近也在自己的虚拟机上用overlay2作为docker存储驱动实验了一番,下面来做一个简单的笔记和总结。

docker默认的存储目录是 /var/lib/docker ,下面我们简单打印一下这个目录:

在这里,我们只关心 image 和 overlay2 就足够了。
做这个实验之前,我们应该先启动一个容器,在这里使用nginx作为实验:

可以看到新启动的nginx容器的id是 86b5733e54c7 ,我们继续往下看。

上面说了,我们只需要关心 /var/lib/docker/image 和 /var/lib/docker/overlay2 ,可以先到 /var/lib/docker/image 打印一下:

我们只能看到overlay2这个目录,想必聪明的你也猜到了,docker会在 /var/lib/docker/image 目录下按每个存储驱动的名字创建一个目录,如这里的 overlay2 。
接下来,使用 tree 命令浏览一下这个目录:

这里的关键地方是 imagedb 和 layerdb 目录,看这个目录名字,很明显就是专门用来存储元数据的地方,那为什么区分image和layer呢?因为在docker中,image是由多个layer组合而成的,换句话就是layer是一个共享的层,可能有多个image会指向某个layer。
那如何才能确认image包含了哪些layer呢?答案就在 imagedb 这个目录中去找。比如上面启动的nginx容器,我们可以先找到这个容器对应的镜像:

可以看到,imageID是 2bcb04bdb83f ,再次记住这个id,我们打印 /var/lib/docker/image/overlay2/imagedb/content/sha256 这个目录:

第一行的 正是记录我们 nginx 镜像元数据的文件,接下来cat一下这个文件,得到一个长长的json:

由于篇幅原因,我只展示最关键的一部分,也就是 rootfs 。可以看到rootfs的diff_ids是一个包含了3个元素的数组,其实这3个元素正是组成 nginx 镜像的3个layerID,从上往下看,就是底层到顶层,也就是说 5dacd731af1b0386ead06c8b... 是image的最底层。既然得到了组成这个image的所有layerID,那么我们就可以带着这些layerID去寻找对应的layer了。
接下来,我们返回到上一层的 layerdb 中,先打印一下这个目录:

在这里我们只管 mounts 和 sha256 两个目录,再打印一下 sha256 目录:

在这里,我们仅仅发现 5dacd731af1b038.. 这个最底层的layer,那么剩余两个layer为什么会没有呢?那是因为docker使用了chainID的方式去保存这些layer,简单来说就是chainID=sha256sum(H(chainID) diffid),也就是 5dacd731af1b038.. 的上一层的sha256 id是:

这个时候,你能看到 166d13b... 这个layer层的目录了吧?依次类推,我们就能找出所有的layerID的组合。
但是上面我们也说了, /var/lib/docker/image/overlay2/layerdb 存的只是元数据,那么真实的rootfs到底存在哪里呢?其中 cache-id 就是我们关键所在了。我们打印一下 /var/lib/docker/image/overlay2/layerdb/sha256//cache-id :

没错,这个id就是对应 /var/lib/docker/overlay2/ 。因此,以此类推,更高一层的layer对应的cache-id也能找到对应的rootfs,当这些rootfs的diff目录通过联合挂载的方式挂载到某个目录,就能完整整个容器需要的rootfs了。

❼ 谁可以简单介绍一下docker到底是干什么用的

参考sf上好雨科技的回答:
docker主要有2大核心贡献和对于软件交付的影响:
2大贡献:
1、封装,将运行环境与代码封装到一个盒子中
2、镜像仓库,将镜像以类似代码仓库的方式分发

软件交付的影响:作为一个IT界“集装箱” 它把整个软件交付的流程和方式都改变了,就相当于 集装箱 一样改变了整个航运、空运、陆运的方式,让生产者产出的产品到最终用户完全一致,无论中途经过多少过程。有了这个核心的“集装箱” 整个生态都围着它打转。

❽ 如何使用Docker开源仓库建立代理缓存仓库

开源Docker仓库v2 的其中一个最新特性:能够被用作代理缓存仓库,以缓存Docker Hub上的镜像。运行一个缓存仓库允许你在本地储存镜像,减少过多的通过互联网从Docker Hub拉取镜像,这个特性对于一些在他们环境中拥有数量庞大的Docker引擎的用户来说很有用。跟着本篇教程,你可以让Docker引擎从本地代理缓存仓库拉取镜像,而不是让每个引擎总是从Docker Hub拉取,从而节省时间和带宽。

你可以这样开始:
####要求:
- Docker引擎1.8.3
- Docker仓库v2
- 足够储存Docker镜像的磁盘空间
- TLS证书和密钥
持久化数据
在这个例子中,我们会假设你会储存所有持久化数据在本地文件系统的<code>/data</code>路径下,这个路径下包含TLS证书和密钥文件,配置文件和镜像缓存文件。我们之后会用卷挂载这个目录进运行仓库的容器。
保护你的代理缓存仓库安全
代理缓存仓库需要一个TLS证书来保证Docker引擎和缓存仓库之间的连接安全,在这个例子中,我们会放置我们证书文件(<code>domain.crt</code>)和密钥文件(<code>domain.key</code>)在主机的<code>/data</code>目录。
更多关于使用TLS加强仓库安全的信息,请参照 Docker仓库2.0文档 。
创建代理缓存仓库配置文件
下一步你需要创建一个配置文件,来把这个仓库用作代理缓存。你可以用cat命令把<code>registry:2</code>镜像中的缺省配置文件重定向输出到一个文件中:
sh
$ docker run -it --rm --entrypoint cat registry:2 \
/etc/docker/registry/config.yml > /data/config.yml

<code>我强烈建议从Docker镜像中获得这个默认配置,而不是使用例子中的配置,因为将来这个默认配置可能会有更新。</code>
默认的config.yml例子:
yaml
version: 0.1
log:
fields
service: registry
storage:
cache:
layerinfo: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000

修改'http'这节配置上TLS:
yaml
http:
addr: :5000
tls:
certificate: /var/lib/registry/domain.crt
key: /var/lib/registry/domain.key

在配置文件中新加一节'proxy'来开启缓存:
点击打开文档( https://github.com/docker/dist ... or.md )
yaml
proxy:
remoteurl: https://registry-1.docker.io
username: [username]
password: [password]

'username'和'password'这两个选项是可选的,这是Docker Hub账号的用户名和密码,设置上这两个选项,会使代理缓存仓库获取到这个账号的同等权限,也就是说,这个用户有权限获取的镜像,这个缓存仓库同样有权限获取。
<code>请确保完全理解设置这个Docker Hub账号背后意味着什么,并且确保你镜像的安全还有严格的访问权限!如果你不确定,请不要再配置包含用户名和密码,那么你的代理缓存仓库就只会缓存公共镜像。</code>
启动代理缓存仓库的容器:
sh
$ docker run -d --restart=always -p 5000:5000 --name v2-mirror \
-v /data:/var/lib/registry registry:2 /var/lib/registry/config.yml

以上命令使用一个卷把宿主机上的/data挂载进了容器中,使容器能使用持久储存镜像缓存,TLS证书和密钥,还有自定义的仓库配置文件。
验证你的代理缓存仓库已经启动并正常运行:
sh
$ curl -I https://mycache.example.com:5000/v2/
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
Date: Thu, 17 Sep 2015 21:42:02 GMT

配置你的Docker引擎使用代理缓存仓库
修改Docker守护进程的启动参数,加上<code>--registry-mirror</code>选项:
sh
--registry-mirror=https://<my-docker-mirror-host>:<port-number>

例如,如果你的缓存仓库的主机名为mycache.example.com并且仓库服务端口为5000,你需要加上以下选项到守护进程的参数:
sh
--registry-mirror=https://mycache.example.com:5000

参考 在各种的Linux分发版中配置运行Docker 了解更多信息关于如何添加Docker守护进程参数。
测试你的代理缓存仓库
从Docker Hub上拉取一个你本地没有的镜像。例如,busybox:latest镜像:
sh
$ docker pull busybox:latest

检查缓存仓库中的目录,验证busybox镜像是否被缓存:
sh
$ curl https://mycache.example.com:5000/v2/_catalog
{"repositories":["library/busybox"]}

你也可以验证latest标签是否被缓存:
sh
$ curl https://mycache.example.com:5000/v2/library/busybox/tags/list
{"name":"library/busybox","tags":["latest"]}

现在开始当你拉取镜像时,镜像将被缓存到你的代理缓存仓库,之后拉取相同的镜像时会更快,并且这些镜像缓存会维护自身,当他们不再被使用时将会自动清除。