- 默认情况下,在运行中的容器里创建的文件会被保存在一个可写的容器层
- 如果这个容器被删除,数据也会随之丢失(停止容器时不会丢失数据)
- 可写的容器层和特定的容器进行绑定,即这些数据无法方便的与其他容器共享
针对数据持久化的问题,Docker主要提供了两种方式:
- Data Volume:由Docker管理,是持久化数据最佳方式
- Bind Mount:由用户指定储存的数据挂载在系统什么位置
1. Data Volume
- 创建一个Dockerfile文件和my-cron文件,这个镜像的作用是执行计划任务(这里是每隔一分钟输出时间到一个文件里),具体过程可以参考Docker Blog:
Dockerfile_Volume:
FROM alpine:latest RUN apk update RUN apk --no-cache add curl ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.1.12/supercronic-linux-amd64 \ SUPERCRONIC=supercronic-linux-amd64 \ SUPERCRONIC_SHA1SUM=048b95b48b708983effb2e5c935a1ef8483d9e3e RUN curl -fsSLO "$SUPERCRONIC_URL" \ && echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \ && chmod +x "$SUPERCRONIC" \ && mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \ && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic COPY my-cron /app/my-cron WORKDIR /app # RUN cron job CMD ["/usr/local/bin/supercronic", "/app/my-cron"]
my-cron:
*/1 * * * * date >> /app/test.txt
- 创建镜像:
docker image build -f Dockerfile_Volume -t my-cron .
- 创建容器:
docker container run -d my-cron
- 进入交互式shell:
docker container exec -it 379 sh
完成上述操作后进入到容器内部后,会查看到my-cron文件和output.txt文件,每隔一分钟去查看output.txt会出现新的时间戳。
问题1:如果将容器删除后,output.txt文件也就被删除了,该如何持久化储存在磁盘上?
- 修改Dockerfile文件,在其中添加VOLUME命令:
Dockerfile_Volume_New:
FROM alpine:latest RUN apk update RUN apk --no-cache add curl ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.1.12/supercronic-linux-amd64 \ SUPERCRONIC=supercronic-linux-amd64 \ SUPERCRONIC_SHA1SUM=048b95b48b708983effb2e5c935a1ef8483d9e3e RUN curl -fsSLO "$SUPERCRONIC_URL" \ && echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \ && chmod +x "$SUPERCRONIC" \ && mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \ && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic COPY my-cron /app/my-cron WORKDIR /app VOLUME ["/app"] # RUN cron job CMD ["/usr/local/bin/supercronic", "/app/my-cron"]
VOLUME ["/app"]
:/app
表示VOLUME需要持久化的容器目录
- 重新构建镜像和容器
- 查看已经存在的VOLUME的NAME:执行
docker volume ls
会出现VOLUME NAME- 查看VOLUME详细的信息:执行
docker volume inspect (完整的VOLUME NAME)
,会出现该VOLUME详细的信息,其中Mountpoint
就是该VOLUME储存文件(即容器/app
目录下的文件)的位置,此时便可以查看该位置下被持久化储存的文件(在Windows系统下是无法直接根据这个路径进行查看文件,需要到docker engine中查看),这个文件同样每隔一分钟会出现新的时间戳
问题2:此时使用该镜像再次创建新的容器,就会出现一个新的VOLUME(VOLUME NAME每次是随机的),导致数据储存的位置不一样了,但是我们的目的是尽管创建了新容器,还是要使用相同VOLUME的数据(即可以继续使用原来output.txt中的数据),要实现这个要求该如何操作?
- 创建新容器的时候指定VOLUME的名字:执行
docker container run -d -v cron-data:/app my-cron
。其中,cron-data
为自定义的VOLUME名字,/app
与dockerfile文件中VOLUME ["/app"]
的含义一致(不在dockerfile文件中写命令,直接指定-v
也可)。这样再次创建新容器时执行相同的命令,就可以使用相同的VOLUMEtips:
docker volume prune -f
:删除所有的volume(删除volume前要删除所属容器)
2. Bind Mount
在使用Data Volume时,每次执行如
docker container run -d -v cron-data:/app my-cron
命令时,相当于使用cron-data这个Volume给你指定的储存路径,这样会导致之前提到的Windows系统下无法直接查看储存的文件的情况。如果能直接指定本地用于储存文件的路径就会方便很多,此时就要使用Bind Mount:
docker container run -d -v $(pwd):/app my-cron
:将原来的命令中指定的Volumecron-data
改为当前路径$(pwd)
(Linux下为圆括号,Windows下为大括号)即可,此时再使用docker volume ls
不会出现新的Volume,并且在本机当前目录下会出现output.txt文件。假如当前本机中没有gcc的编译环境,要使用container去完成某个C文件的编译和执行该如何操作?
- 在本地的当前目录创建需要执行的hello.c文件
- 创建一个
gcc:9.4
的镜像- 执行
docker container run --it -v $(pwd):/root gcc:9.4
进入到容器中- 此时在容器root目录下会出现hello.c文件,执行
gcc -o hello hello.c
和./hello
即可完成- 在本地的当前目录也会出现编译好的hello文件
3. 多个机器之间的容器共享数据
之前的内容我们是将本地的目录和容器中的目录进行挂载,所以在查看VOLUME详细信息时会看到
Driver:'local'
:
此时要实现两台主机容器间的数据共享该如何操作?
假设有两台主机,信息如下:
hostname ip ssh username ssh password docker-host1 192.168.200.10 vagrant vagrant docker-host2 192.168.200.11 vagrant vagrant
在两台主机上都安装一个plugin
vieux/sshfs
:执行docker plugin install --grant-all-permissions vieux/sshfs
在docker-host1中创建volume:
docker volume create --driver vieux/sshfs \ -o sshcmd=vagrant@192.168.200.12:/home/vagrant \ -o password=vagrant \ sshvolume
其中,
vagrant@192.168.200.12:/home/vagrant
表示指定目标主机储存的目录,sshvolume
为创建的VOLUME NAME。此时查看该VOLUME的详细信息时会发现Mountpoint发生了改变,下图中表示将docker-host2的/home/vagrant
挂载到了docker-host1的Mountpoint:
- 创建容器挂载Volume:执行
docker container run -it -v sshvolume:/app busybox sh
,即实现挂载sshvolume
到使用busybox镜像创建的容器的/app
目录,然后进入容器的shell,在/app目录创建一个test.txt文件。此时在docker-host1、docker-host2都会出现test.txt文件
4. 参考
https://dockertips.readthedocs.io/en/latest/docker-volume.html
https://dockertips.readthedocs.io/en/latest/docker-blog/docker-cron.html
https://docs.docker.com/storage/volumes/#share-data-among-machines