使用Docker创建数据容器

翻译自: Data-only container madness

1.什么是数据容器?

数据容器就是本身只创建一个volume供其他容器共享,创建完后即退出,不执行任何任务。比如通过以下方式创建一个postgres容器。

docker run --name dbdata postgres echo "Data-only container for postgres"

该容器运行echo "Data-only container for postgres"即退出,然而只要没有删除该容器,该容器/var/lib/postgresql/data的volume(在Dockerfile使用VOLUME指令定义)就会一直存在。

然后我们可以新建若干容器来共享数据,比如:

docker run -d --volumes-from dbdata --name db1 postgres

2.如何创建数据容器?

太简单了,创建任何容器,然后使用-v创建volume即可。但大家一定会想到用最小的镜像吧,比如hello-world,即

docker run -v /data hello-world

但这样是错误的! 为什么呢?

我们首先创建一个简单的镜像:

FROM debian:jessie
RUN useradd mickey
RUN mkdir /foo && touch /foo/bar && chown -R mickey:mickey /foo
USER mickey
CMD ls -lh /foo

构建:

docker build -t mickey_foo -< Dockerfile

运行下:

docker run --rm -v /foo mickey_foo

输出:

total 0
-rw-r--r-- 2 mickey mickey 0 Nov 18 05:58 bar

运行正常,没有任何问题。

下面我们尝试使用busybox来作为数据容器:

docker run -v /foo --name mickey_data busybox true
docker run --rm --volumes-from mickey_data mickey_foo

输出:

total 0
# Empty WTF??
docker run --rm --volumes-from mickey_data mickey_foo ls -lh /
total 68K
drwxr-xr-x 2 root root 4.0K Nov 18 06:02 bin
drwxr-xr-x 2 root root 4.0K Oct 9 18:27 boot
drwxr-xr-x 5 root root 360 Nov 18 06:05 dev
drwxr-xr-x 1 root root 4.0K Nov 18 06:05 etc
drwxr-xr-x 2 root root 4.0K Nov 18 06:02 foo
drwxr-xr-x 2 root root 4.0K Oct 9 18:27 home
drwxr-xr-x 9 root root 4.0K Nov 18 06:02 lib
drwxr-xr-x 2 root root 4.0K Nov 18 06:02 lib64
drwxr-xr-x 2 root root 4.0K Nov 5 21:40 media
drwxr-xr-x 2 root root 4.0K Oct 9 18:27 mnt
drwxr-xr-x 2 root root 4.0K Nov 5 21:40 opt
dr-xr-xr-x 120 root root 0 Nov 18 06:05 proc
drwx------ 2 root root 4.0K Nov 18 06:02 root
drwxr-xr-x 3 root root 4.0K Nov 18 06:02 run
drwxr-xr-x 2 root root 4.0K Nov 18 06:02 sbin
drwxr-xr-x 2 root root 4.0K Nov 5 21:40 srv
dr-xr-xr-x 13 root root 0 Nov 18 06:05 sys
drwxrwxrwt 2 root root 4.0K Nov 5 21:46 tmp
drwxr-xr-x 10 root root 4.0K Nov 18 06:02 usr
drwxr-xr-x 11 root root 4.0K Nov 18 06:02 var
Owened by root? WTF???
docker run --rm --volumes-from mickey_data mickey_foo touch /foo/ba
touch: cannot touch '/foo/bar': Permission denied

发生了什么呢?我们的/foo 仍然存在, 但是它是空的并且所有者是root

让我们再试试使用我们刚刚构建的mickey_foo作为数据容器:

~: docker rm -v mickey_data # remove the old one
mickey_data
~: docker run --name mickey_data -v /foo mickey_foo true
~: docker run --rm --volumes-from mickey_data mickey_foo
total 0
-rw-r--r-- 1 mickey mickey 0 Nov 18 05:58 bar
# Yes!
~: docker run --rm --volumes-from mickey_data mickey_foo ls -lh /
total 68K
drwxr-xr-x 2 root root 4.0K Nov 18 06:02 bin
drwxr-xr-x 2 root root 4.0K Oct 9 18:27 boot
drwxr-xr-x 5 root root 360 Nov 18 06:11 dev
drwxr-xr-x 1 root root 4.0K Nov 18 06:11 etc
drwxr-xr-x 2 mickey mickey 4.0K Nov 18 06:10 foo
drwxr-xr-x 2 root root 4.0K Oct 9 18:27 home
drwxr-xr-x 9 root root 4.0K Nov 18 06:02 lib
drwxr-xr-x 2 root root 4.0K Nov 18 06:02 lib64
drwxr-xr-x 2 root root 4.0K Nov 5 21:40 media
drwxr-xr-x 2 root root 4.0K Oct 9 18:27 mnt
drwxr-xr-x 2 root root 4.0K Nov 5 21:40 opt
dr-xr-xr-x 121 root root 0 Nov 18 06:11 proc
drwx------ 2 root root 4.0K Nov 18 06:02 root
drwxr-xr-x 3 root root 4.0K Nov 18 06:02 run
drwxr-xr-x 2 root root 4.0K Nov 18 06:02 sbin
drwxr-xr-x 2 root root 4.0K Nov 5 21:40 srv
dr-xr-xr-x 13 root root 0 Nov 18 06:05 sys
drwxrwxrwt 2 root root 4.0K Nov 5 21:46 tmp
drwxr-xr-x 10 root root 4.0K Nov 18 06:02 usr
drwxr-xr-x 11 root root 4.0K Nov 18 06:02 var
# YES!!
~: docker run --rm --volumes-from mickey_data mickey_foo touch /foo/baz
~: docker run --rm --volumes-from mickey_data mickey_foo ls -lh /foo
total 0
-rw-r--r-- 1 mickey mickey 0 Nov 18 06:11 bar
-rw-r--r-- 1 mickey mickey 0 Nov 18 06:12 baz
# YES!!!

由于我们刚刚使用了相同的镜像作为数据容器镜像,共享的容器能够找到共享数据。为什么使用busybox不可以呢?由于busybox没有/foo这个目录,当我们使用-v创建/foo这个数据卷时,docker会以默认用户自动创建对应的目录(这里是root),而--volumes-from仅仅是重用存在的卷,而不会对卷自动做任何事情。因此当我们尝试去写/foo时由于没有权限(root所有,mickey用户).

因此我们应该使用和共享的容器相同的镜像做数据容器镜像?是的!

那我们使用这么大的镜像不会浪费空间么?

3. 为什么不使用小镜像作为数据容器?

其中一个原因,在上一节已经解释。遗留的一个问题是使用这么大的镜像(因为一般的镜像都会比较大)会不会浪费空间呢?

首先我们需要知道Docker的文件系统是如何工作的。Docker镜像是由多个文件系统(只读层)叠加而成。当我们启动一个容器的时候,Docker会加载只读镜像层并在其上(译者注:镜像栈顶部)添加一个读写层。如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏。当删除Docker容器,并通过该镜像重新启动时,之前的更改将会丢失。在Docker中,只读层及在顶部的读写层的组合被称为Union File System(联合文件系统)。

因此当我们创建了一个debian容器实例时(大约150MB),根据以上的原理,我们再创建1000个debian镜像能够重用原来的只读层,需要的空间还是150MB.

容器本身并不会占任何空间,除非你修改了内容。

因此Docker无论创建一个镜像的多少实例,都不会占据更多的空间。

因此实际上,我们为了创建数据容器而使用busybox反而会占用更多的空间,这个空间就是busybox的镜像大小。

实际上我们经常这样使用:

~: docker run --name mydb-data --entrypoint /bin/echo mysql Data-only container for mydb
~: docker run -d --name mydb --volumes-from mydb-data mysql

上面的实例指行/bin/echo mysql Data-only container for mydb,能够更容易知道这是一个数据容器,利于使用grep查找.

使用Docker创建数据容器的更多相关文章

  1. Docker 创建 Redis 容器

    Docker 创建 Redis 容器 # 配置文件映射: # -v /root/redis/redis.conf:/etc/redis/redis.conf # 数据目录映射: # -v /root/ ...

  2. Docker创建数据卷容器

    docker create --name test_4 -v /data_4 nginx创建一个test_4数据卷容器,在该容器的/data_4目录挂载数据卷 使用数据卷容器时,无须保证数据卷容器处于 ...

  3. docker创建mysql容器,并挂载数据+配置

    新建:/my/mysql/my.cnf (准备挂载配置文件用) 将以下内容拷贝进去(或者启动一个docker的mysql,并且把/etc/mysql/my.cnf中的内容拷贝出来) # Copyrig ...

  4. Docker创建数据卷

    当程序在容器中运行时,需要与其他容器中的程序或者容器外部的程序进行文件读写操作时,就需要进行数据的交换:容器内部的文件系统,是一个临时层,当容器停止运行并被删除时,这个临时层就会被一同丢弃:为了达到从 ...

  5. Docker创建Mysql容器并通过命令行连接到容器

    拉取网易蜂巢的mysql-server:5.6 docker pull hub.c.163.com/nce2/mysql:5.6 创建mysql5.6容器 1master+3个slave docker ...

  6. 使用docker创建rabbitMQ容器

    1.拉去镜像 docker pull rabbitmq:3.7.7-management

  7. 使用docker创建mysql容器

    1.拉取mysql容器   docker pull mysql:5.7

  8. Docker(八)-Docker创建Nginx容器

    获取Nginx镜像 最简单的方法就是通过 docker pull nginx 命令来创建 Nginx容器. $ sudo docker pull nginx 或者: $ sudo docker pul ...

  9. 使用docker创建MySQL容器,并在springboot中使用

    最近在看网上找了个springboot的项目试试,在项目中需要的MySQL版本是5.7,但是本机的MySQL只有5.5.因此想着在我的服务器上跑一个MySQL:5.7的容器解决这一问题,但是在实际操作 ...

随机推荐

  1. xml配置离线约束的目的和ecplipse离线约束配置

    正常情况下如果电脑已经联网的情况下,Spring的核心配置文件编写内容的时候是可以自动提示的,假设电脑如果离线情况下想要自动提示的话,就得配置离线约束文件. https://blog.csdn.net ...

  2. php开发面试题---数据库SQL调优的几种方式

    php开发面试题---数据库SQL调优的几种方式 一.总结 一句话总结: 创建索引:尽量避免使用or或者like,或者sql中的正则 存储查询中间结果 可以加sphinx搜索技术 查询优化 主从数据库 ...

  3. Code::Blocks

    Code::Blocks 是一个开放源码的全功能的跨平台C/C++集成开发环境. Code::Blocks是开放源码软件.Code::Blocks由纯粹的C++语言开发完成,它使用了著名的图形界面库w ...

  4. Java-Class-@I:java.annotation.Resource

    ylbtech-Java-Class-@I:java.annotation.Resource 1.返回顶部   2.返回顶部 1.1. import javax.annotation.Resource ...

  5. (动态改变数据源遇到的问题)ORACLE11g:No Dialect mapping for JDBC type: -9解决方案

    在动态改变数据源时 hibernate配置不能使用Oracle官方的方言(org.hibernate.dialect.Oracle10gDialect) 做法写一个方言扩展类,缺什么类型,添加什么类型 ...

  6. Elasticsearch介绍和安装与使用

    转载:https://blog.csdn.net/weixin_42633131/article/details/82902812 1.Elasticsearch介绍和安装 1.1.简介1.1.1.E ...

  7. 谈谈-Android Studio 调试功能

    先编译好要调试的程序. 1.设置断点 选定要设置断点的代码行,在行号的区域后面单击鼠标左键即可. 2.开启调试会话 点击红色箭头指向的小虫子,开始进入调试. IDE下方出现Debug视图,红色的箭头指 ...

  8. 8.1 图像API

    8.1 图像API Routine Description Drawing related functions GUI_AddRect() 调整矩形框的大小 GUI_GetClientRect() R ...

  9. 1022 Digital Library (30 分)

    1022 Digital Library (30 分)   A Digital Library contains millions of books, stored according to thei ...

  10. HTML中列表中元素居中问题

    想让列表<table>中某一行元素居中的话,单纯使用<align  = 'center'>是达不到效果的,需要先将该行进行合并,使用colspan属性. <html> ...