Data Volume
这种方式等效于下面这两条命令:
Bind Mount
Data Volume的思想是先由Docker创建磁盘卷,然后在运行容器时将创建好的磁盘卷挂载到容器的某个路径上。这种方式的好处是所有的磁盘卷都是由Docker来管理的,不需要用户来维护,可以通过Docker命令来查看磁盘卷的信息,或是删除一个磁盘卷。Data Volume方式还支持挂载远程磁盘卷。 Bind Mount的思想是文件系统挂载,相当于nfs挂载,好处是简单,可以将任意路径挂载到容器里。 |
默认情况下,在运行中的容器里创建的文件,被保存在一个可写的容器层:
Docker主要提供了两种方式做数据的持久化:
本节部分操作需要Linux系统的环境,但是大部分都可以在Windows环境下的Docker进行操作,只有一个操作不行,如何进行数据的持久化。 |
准备一个Dockerfile 和一个 my-cron的文件:
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"] |
*/1 * * * * date >> /app/test.txt |
$ docker image build -t my-cron . $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE my-cron latest e9fbd9a562c9 4 seconds ago 24.7MB |
此时Docker会自动创建一个随机名字的volume,去存储我们在Dockerfile定义的volume VOLUME ["/app"]
$ docker run -d my-cron 9a8fa93f03c42427a498b21ac520660752122e20bcdbf939661646f71d277f8f $ docker volume ls DRIVER VOLUME NAME local 043a196c21202c484c69f2098b6b9ec22b9a9e4e4bb8d4f55a4c3dce13c15264 $ docker volume inspect 043a196c21202c484c69f2098b6b9ec22b9a9e4e4bb8d4f55a4c3dce13c15264 [ { "CreatedAt": "2021-06-22T23:06:13+02:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/043a196c21202c484c69f2098b6b9ec22b9a9e4e4bb8d4f55a4c3dce13c15264/_data", "Name": "043a196c21202c484c69f2098b6b9ec22b9a9e4e4bb8d4f55a4c3dce13c15264", "Options": null, "Scope": "local" } ] |
在这个Volume的mountpoint可以发现容器创建的文件。
在创建容器的时候通过 -v
参数我们可以手动的指定需要创建Volume的名字,以及对应于容器内的路径,这个路径是可以任意的,不必需要在Dockerfile里通过VOLUME定义。比如我们把上面的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"] |
重新build镜像,然后创建容器,加-v参数:
$ docker image build -t my-cron . $ docker container run -d -v cron-data:/app my-cron 43c6d0357b0893861092a752c61ab01bdfa62ea766d01d2fcb8b3ecb6c88b3de $ docker volume ls DRIVER VOLUME NAME local cron-data $ docker volume inspect cron-data [ { "CreatedAt": "2021-06-22T23:25:02+02:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/cron-data/_data", "Name": "cron-data", "Options": null, "Scope": "local" } ] $ ls /var/lib/docker/volumes/cron-data/_data my-cron $ ls /var/lib/docker/volumes/cron-data/_data my-cron test.txt |
Volume也创建了。
强制删除所有容器,系统清理和volume清理:
$ docker rm -f $(docker container ps -aq) $ docker system prune -f $ docker volume prune -f |
本次练习,演示使用的是Linux环境,Windows环境也可以做这里面的90%以上的内容。 使用MySQL官方镜像,tag版本5.7,Dockerfile可以在这里查看 https://github.com/docker-library/mysql/tree/master/5.7。 |
$ docker pull mysql:5.7 $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE mysql 5.7 2c9028880e58 5 weeks ago 447MB |
关于MySQL的镜像使用,可以参考https://hub.docker.com/_/mysql?tab=description&page=1&ordering=last_updated。
关于Dockerfile Volume的定义,可以参考 https://github.com/docker-library/mysql/tree/master/5.7。
$ docker container run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d -v mysql-data:/var/lib/mysql mysql:5.7 02206eb369be08f660bf86b9d5be480e24bb6684c8a938627ebfbcfc0fd9e48e $ docker volume ls DRIVER VOLUME NAME local mysql-data $ docker volume inspect mysql-data [ { "CreatedAt": "2021-06-21T23:55:23+02:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/mysql-data/_data", "Name": "mysql-data", "Options": null, "Scope": "local" } ] $ |
进入MySQL的shell,密码是 my-secret-pw
$ docker container exec -it 022 sh # mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.7.34 MySQL Community Server (GPL) Copyright (c) 2000, 2021, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.00 sec) mysql> create database demo; Query OK, 1 row affected (0.00 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | demo | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.00 sec) mysql> exit Bye # exit |
创建了一个叫 demo的数据库。
查看data volume:
$ docker volume inspect mysql-data [ { "CreatedAt": "2021-06-22T00:01:34+02:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/mysql-data/_data", "Name": "mysql-data", "Options": null, "Scope": "local" } ] $ ls /var/lib/docker/volumes/mysql-data/_data auto.cnf client-cert.pem ib_buffer_pool ibdata1 performance_schema server-cert.pem ca-key.pem client-key.pem ib_logfile0 ibtmp1 private_key.pem server-key.pem ca.pem demo ib_logfile1 mysql public_key.pem sys $ |
如果熟悉的话,也可以试试MongoDB https://hub.docker.com/_/mongo。
docker container run -it -v $(pwd):/data busybox |
可以将本机的任意路径挂载到容器里。
官方参考链接 https://docs.docker.com/storage/volumes/#share-data-among-machines
Docker的volume支持多种driver。默认创建的volume driver都是local。
$ docker volume inspect vscode [ { "CreatedAt": "2021-06-23T21:33:57Z", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/vscode/_data", "Name": "vscode", "Options": null, "Scope": "local" } ] |
这一节我们看看一个叫sshfs的driver,如何让docker使用不在同一台机器上的文件系统做volume。
准备三台Linux机器,之间可以通过SSH相互通信。
hostname | ip | ssh username | ssh password |
docker-host1 | 192.168.200.10 | vagrant | vagrant |
docker-host2 | 192.168.200.11 | vagrant | vagrant |
docker-host3 | 192.168.200.12 | vagrant | vagrant |
在其中两台机器上安装一个plugin vieux/sshfs
。
[vagrant@docker-host1 ~]$ docker plugin install --grant-all-permissions vieux/sshfs latest: Pulling from vieux/sshfs Digest: sha256:1d3c3e42c12138da5ef7873b97f7f32cf99fb6edde75fa4f0bcf9ed277855811 52d435ada6a4: Complete Installed plugin vieux/sshfs [vagrant@docker-host2 ~]$ docker plugin install --grant-all-permissions vieux/sshfs latest: Pulling from vieux/sshfs Digest: sha256:1d3c3e42c12138da5ef7873b97f7f32cf99fb6edde75fa4f0bcf9ed277855811 52d435ada6a4: Complete Installed plugin vieux/sshfs |
创建volume:
[vagrant@docker-host1 ~]$ docker volume create --driver vieux/sshfs \ -o sshcmd=vagrant@192.168.200.12:/home/vagrant \ -o password=vagrant \ sshvolume |
查看:
[vagrant@docker-host1 ~]$ docker volume ls DRIVER VOLUME NAME vieux/sshfs:latest sshvolume [vagrant@docker-host1 ~]$ docker volume inspect sshvolume [ { "CreatedAt": "0001-01-01T00:00:00Z", "Driver": "vieux/sshfs:latest", "Labels": {}, "Mountpoint": "/mnt/volumes/f59e848643f73d73a21b881486d55b33", "Name": "sshvolume", "Options": { "password": "vagrant", "sshcmd": "vagrant@192.168.200.12:/home/vagrant" }, "Scope": "local" } ] |
创建容器,挂载sshvolume到/app目录,然后进入容器的shell,在/app目录创建一个test.txt文件:
[vagrant@docker-host1 ~]$ docker run -it -v sshvolume:/app busybox sh Unable to find image 'busybox:latest' locally latest: Pulling from library/busybox b71f96345d44: Pull complete Digest: sha256:930490f97e5b921535c153e0e7110d251134cc4b72bbb8133c6a5065cc68580d Status: Downloaded newer image for busybox:latest / # / # ls app bin dev etc home proc root sys tmp usr var / # cd /app /app # ls /app # echo "this is ssh volume"> test.txt /app # ls test.txt /app # more test.txt this is ssh volume /app # /app # |
这个文件我们可以在docker-host3上看到:
[vagrant@docker-host3 ~]$ pwd /home/vagrant [vagrant@docker-host3 ~]$ ls test.txt [vagrant@docker-host3 ~]$ more test.txt this is ssh volume |