Docker5 数据

Docker 在使用中往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享。容器中管理数据主要有两种方式:

  1. 数据卷:容器内数据直接映射到本地主机上
  2. 数据卷镜像:使用特定的容器维护数据卷

数据卷

数据卷是一个可供容器使用的特殊目录,类似Linux的mount操作。

数据卷有很多特性:

  1. 数据卷可以在容器之间共享和重用
  2. 对数据卷内数据的修改会立马生效
  3. 对数据的更新不会影响容器,解耦了应用和数据
  4. 卷会一直存在,直到没有容器使用,可以安全的卸载。

容器内创建数据卷

使用docker run的时候,可以使用-v在容器内创建一个数据卷,多次使用-v可以创建多个数据卷。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@ubuntu:~# docker pull training/webapp
Using default tag: latest
latest: Pulling from training/webapp
e190868d63f8: Pull complete
909cd34c6fd7: Pull complete
0b9bfabab7c1: Pull complete
a3ed95caeb02: Pull complete
10bbbc0fc0ff: Pull complete
fca59b508e9f: Pull complete
e7ae2541b15b: Pull complete
9dd97ef58ce9: Pull complete
a4c1b0cb7af7: Pull complete
Digest: sha256:06e9c1983bd6d5db5fba376ccd63bfa529e8d02f23d5079b8f74a616308fb11d
Status: Downloaded newer image for training/webapp:latest

1
2
3
4
5
6
root@kindle15:~# docker run -d -p 5000:5000 --name web -v /webapp training/webapp
5112b10e6b3c4bf0b96c5dbfb8a950089e0a33695bda193ff15dd80f55ee674d
root@kindle15:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5112b10e6b3c training/webapp "python app.py" 4 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp web
root@kindle15:~#

浏览器访问5000端口可以看见 Hello world!

使用exec重新连接看下是否有/webapp目录【如果不用-v指定创建一个,是不会有/webapp这个目录的】

1
2
3
4
5
6
root@kindle15:~# docker exec -it 5112b10 /bin/bash
root@5112b10e6b3c:/opt/webapp# cd /webapp/
root@5112b10e6b3c:/webapp# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 5 07:26 ./
drwxr-xr-x 1 root root 4096 Apr 5 07:26 ../

主机目录作为数据卷

先查看下镜像

1
2
3
4
root@rexyan:/src/webapp# docker images 
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 14.04 a35e70164dfb 4 weeks ago 222 MB
training/webapp latest 6fae60ef3446 2 years ago 349 MB

创建一个容器,并将本机目录文件夹/src/webapp作为数据卷和容器中的/tmp目录进行关联

1
root@rexyan:/src/webapp# docker run -it -v /src/webapp:/tmp ubuntu:14.04 /bin/bash

到容器中/tmp下新建一个目录

1
2
3
4
5
6
7
8
9
10
root@fe571def773f:/# cd /tmp/
root@fe571def773f:/tmp# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 5 13:11 ./
drwxr-xr-x 34 root root 4096 Apr 5 13:23 ../
root@fe571def773f:/tmp#
root@fe571def773f:/tmp#
root@fe571def773f:/tmp# touch hahahah.txt
root@fe571def773f:/tmp#
root@fe571def773f:/tmp# exit

退出容器,查看/src/webapp下文件的变化,可以看见新建的文件hahahah.txt

1
2
3
4
5
6
root@rexyan:/src/webapp# cd /src/webapp/
root@rexyan:/src/webapp# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 5 21:23 ./
drwxr-xr-x 3 root root 4096 Apr 5 21:11 ../
-rw-r--r-- 1 root root 0 Apr 5 21:23 hahahah.txt

这里要注意,本地路径必须是绝对路径,如果目录不存在Docker会自动创建。

Docker挂载数据卷的默认权限是读写(rw),用户也可以通过ro指定为只读,下面新建一个容器,将目录指定为只读,并去创建一个文件,会看见提示 Read-only file system

1
2
3
4
5
6
7
8
9
10
root@rexyan:/src/webapp# docker run -it -v /src/webapp:/tmp:ro ubuntu:14.04 /bin/bash
root@b3ae330ad08e:/# cd /tmp/
root@b3ae330ad08e:/tmp# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 5 13:23 ./
drwxr-xr-x 34 root root 4096 Apr 5 13:27 ../
-rw-r--r-- 1 root root 0 Apr 5 13:23 hahahah.txt
root@b3ae330ad08e:/tmp# touch 222.txt
touch: cannot touch '222.txt': Read-only file system
root@b3ae330ad08e:/tmp#

主机文件作为数据卷

1
没有测试成功,挂载后为文件夹

数据卷容器

数据卷容器是一个容器,目的是专门用来提供数据卷供其他容器挂载。数据卷容器可以很方便的在多个容器之间共享文件数据

1
root@rexyan:/# docker run -it -v /datadb --name datadb ubuntu:14.04

此时已经进入了容器,我们可以看见我们刚刚创建的数据卷/datadb。注意这里是在容器中创建的/datadb文件夹,并不是你的主机上【注意区分挂载一个主机目录作为数据卷和挂载一个数据卷容器的区别,前者的功能是用于容器和主机之间进行数据的共享,而后者是用于容器与容器之间进行数据的共享】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
root@0043f3b8c86a:/# ll
total 76
drwxr-xr-x 35 root root 4096 Apr 5 13:44 ./
drwxr-xr-x 35 root root 4096 Apr 5 13:44 ../
-rwxr-xr-x 1 root root 0 Apr 5 13:44 .dockerenv*
drwxr-xr-x 2 root root 4096 Mar 2 04:49 bin/
drwxr-xr-x 2 root root 4096 Apr 10 2014 boot/
drwxr-xr-x 2 root root 4096 Apr 5 13:44 datadb/
drwxr-xr-x 5 root root 360 Apr 5 13:44 dev/
drwxr-xr-x 64 root root 4096 Apr 5 13:44 etc/
drwxr-xr-x 2 root root 4096 Apr 10 2014 home/
drwxr-xr-x 12 root root 4096 Mar 2 04:49 lib/
drwxr-xr-x 2 root root 4096 Mar 2 04:48 lib64/
drwxr-xr-x 2 root root 4096 Mar 2 04:47 media/
drwxr-xr-x 2 root root 4096 Apr 10 2014 mnt/
drwxr-xr-x 2 root root 4096 Mar 2 04:47 opt/
dr-xr-xr-x 188 root root 0 Apr 5 13:44 proc/
drwx------ 2 root root 4096 Mar 2 04:49 root/
drwxr-xr-x 8 root root 4096 Mar 6 22:16 run/
drwxr-xr-x 2 root root 4096 Mar 6 22:16 sbin/
drwxr-xr-x 2 root root 4096 Mar 2 04:47 srv/
dr-xr-xr-x 13 root root 0 Apr 5 13:40 sys/
drwxrwxrwt 2 root root 4096 Mar 2 04:49 tmp/
drwxr-xr-x 11 root root 4096 Mar 2 04:47 usr/
drwxr-xr-x 13 root root 4096 Mar 2 04:49 var/

新建两个容器,命名为test1和test2,并将刚刚创建的datadb数据卷容器挂载上

1
2
3
4
root@rexyan:/# docker run -itd --volumes-from datadb --name test1  ubuntu:14.04 
571888752cf6360cf8712a5d6c35354f334aaebd1b732c4fd01d11d16622ee76
root@rexyan:/# docker run -itd --volumes-from datadb --name test2 ubuntu:14.04
5264b61715cc464db23c1cfdf6eb7e7fa224ac84a65f8f5293499bdb72fbd17d

我们去datadb数据卷容器中的/datadb下新建一个文件

1
2
3
4
root@rexyan:/# docker exec -it 0043f3b8c86a /bin/bash 
root@0043f3b8c86a:/# cd /datadb/
root@0043f3b8c86a:/datadb# touch test_file.md
root@0043f3b8c86a:/datadb# exit

我们分别去test1容器和test2容器查看文件的情况

1
2
3
4
5
6
7
8
root@rexyan:/# docker exec -it test1 /bin/bash
root@571888752cf6:/# cd /datadb/
root@571888752cf6:/datadb# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 5 13:51 ./
drwxr-xr-x 35 root root 4096 Apr 5 13:47 ../
-rw-r--r-- 1 root root 0 Apr 5 13:51 test_file.md
root@571888752cf6:/datadb#

1
2
3
4
5
6
7
8
root@rexyan:/# docker exec -it test2 /bin/bash
root@5264b61715cc:/# cd /datadb/
root@5264b61715cc:/datadb# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 5 13:51 ./
drwxr-xr-x 35 root root 4096 Apr 5 13:47 ../
-rw-r--r-- 1 root root 0 Apr 5 13:51 test_file.md
root@5264b61715cc:/datadb#

会看见test1和test2容器都有了刚刚在datadb数据卷容器创建的文件。

我们这次在test1容器中新建一个文件,然后去看test2容器和datadb容器中的变化

1
2
3
4
5
root@rexyan:/# docker exec -it test1 /bin/bash
root@571888752cf6:/# cd /datadb/
root@571888752cf6:/datadb#
root@571888752cf6:/datadb# touch test1_file.md
root@571888752cf6:/datadb# exit

1
2
3
4
5
6
7
8
9
10
11
root@rexyan:/# docker exec -it test2 /bin/bash
root@5264b61715cc:/# cd /datadb/
root@5264b61715cc:/datadb#
root@5264b61715cc:/datadb#
root@5264b61715cc:/datadb# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 5 13:56 ./
drwxr-xr-x 36 root root 4096 Apr 5 13:56 ../
-rw-r--r-- 1 root root 0 Apr 5 13:56 test1_file.md
-rw-r--r-- 1 root root 0 Apr 5 13:51 test_file.md
root@5264b61715cc:/datadb#
1
2
3
4
5
6
7
8
root@rexyan:/# docker exec -it datadb /bin/bash
root@0043f3b8c86a:/# cd /datadb/
root@0043f3b8c86a:/datadb# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 5 13:56 ./
drwxr-xr-x 36 root root 4096 Apr 5 13:45 ../
-rw-r--r-- 1 root root 0 Apr 5 13:56 test1_file.md
-rw-r--r-- 1 root root 0 Apr 5 13:51 test_file.md

由此得出结论,因为datadb容器中的/datadb是数据卷,而datadb容器做为数据卷容器,并挂载在了test1和test2容器上,所有,当一个的/datadb数据卷发生变化的时候,其他两者都是会变化的。这里还需注意,使用–volumes-from参数所挂载数据卷的容器自身并不需要处于运行状态。

1
2
3
4
5
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
5264b61715cc ubuntu:14.04 "/bin/bash" 14 minutes ago Up 14 minutes test2
571888752cf6 ubuntu:14.04 "/bin/bash" 14 minutes ago Up 14 minutes test1
0043f3b8c86a ubuntu:14.04 "/bin/bash" 17 minutes ago Up 11 minutes datadb
root@rexyan:/# docker stop datadb

新建一个容器,挂载在刚刚停止的数据卷容器,可以挂载上,所以使用–volumes-from参数所挂载数据卷的容器自身并不需要处于运行状态

1
2
3
4
5
6
7
root@rexyan:/# docker run -itd --volumes-from datadb --name test3  ubuntu:14.04 
ecf33118c725313422c06e49a9b6ca7a1d0ac37d1ff8475aa42b5ccf84353329
root@rexyan:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ecf33118c725 ubuntu:14.04 "/bin/bash" 3 seconds ago Up 1 second test3
5264b61715cc ubuntu:14.04 "/bin/bash" 14 minutes ago Up 14 minutes test2
571888752cf6 ubuntu:14.04 "/bin/bash" 15 minutes ago Up 15 minutes test1

如果删除了挂载的容器(test1/test2/test3)数据卷不会自动被删除,如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显视使用docker rm -v来指定同时删除关联的容器。

先删除两个容器,剩下一个还挂载着的

1
2
3
4
5
6
7
8
9
10
11
12
root@rexyan:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ecf33118c725 ubuntu:14.04 "/bin/bash" 11 minutes ago Up 11 minutes test3
5264b61715cc ubuntu:14.04 "/bin/bash" 25 minutes ago Up 25 minutes test2
571888752cf6 ubuntu:14.04 "/bin/bash" 26 minutes ago Up 26 minutes test1
root@rexyan:/#
root@rexyan:/#
root@rexyan:/# docker rm -f ecf33118c725
ecf33118c725
root@rexyan:/# docker rm -f 5264b61715cc
5264b61715cc
root@rexyan:/#

这时查看数据卷容器是否还在

1
2
3
4
root@rexyan:/# docker ps -a 
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
571888752cf6 ubuntu:14.04 "/bin/bash" 27 minutes ago Up 27 minutes test1
0043f3b8c86a ubuntu:14.04 "/bin/bash" 30 minutes ago Exited (0) 12 minutes ago datadb

可以看见数据卷容器datadb还在,我们可以使用docker rm -v datadb 来删除数据卷容器。

数据卷容器的备份和恢复

备份

恢复

错误

1
standard_init_linux.go:178: exec user process caused "exec format error"

这是因为操作系统是32位的,不支持。