总结

Data Volume

docker container run -it -v myvolume:/data busybox

这种方式等效于下面这两条命令:

docker volume create myvolume
docker container run -it -v myvolume:/data busybox

Bind Mount

docker container run -it -v $(pwd):/data busybox


Data Volume的思想是先由Docker创建磁盘卷,然后在运行容器时将创建好的磁盘卷挂载到容器的某个路径上。这种方式的好处是所有的磁盘卷都是由Docker来管理的,不需要用户来维护,可以通过Docker命令来查看磁盘卷的信息,或是删除一个磁盘卷。Data Volume方式还支持挂载远程磁盘卷。

Bind Mount的思想是文件系统挂载,相当于nfs挂载,好处是简单,可以将任意路径挂载到容器里。

本章介绍

默认情况下,在运行中的容器里创建的文件,被保存在一个可写的容器层:

  • 如果容器被删除了,则数据也没有了。
  • 这个可写的容器层是和特定的容器绑定的,也就是这些数据无法方便的和其它容器共享。

Docker主要提供了两种方式做数据的持久化:

  • Data Volume, 由Docker管理,(/var/lib/docker/volumes/ Linux), 持久化数据的最好方式。
  • Bind Mount,由用户指定存储的数据具体mount在系统什么位置。

Data Volume

本节部分操作需要Linux系统的环境,但是大部分都可以在Windows环境下的Docker进行操作,只有一个操作不行,如何进行数据的持久化。

环境准备

准备一个Dockerfile 和一个 my-cron的文件:

Dockerfile
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"]
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

创建容器(不指定-v参数)

此时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参数)

在创建容器的时候通过 -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

Data Volume 练习 MySQL

本次练习,演示使用的是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

Bind Mount

docker container run -it -v $(pwd):/data busybox

可以将本机的任意路径挂载到容器里。

Bind Mount 练习之 Docker 开发环境

多个机器之间的容器共享数据

官方参考链接 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相互通信。

hostnameipssh usernamessh password
docker-host1192.168.200.10vagrantvagrant
docker-host2192.168.200.11vagrantvagrant
docker-host3192.168.200.12vagrantvagrant

安装plugin

在其中两台机器上安装一个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"
    }
]

创建容器挂载Volume

创建容器,挂载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






  • 无标签