docker入门之数据卷

docker进阶知识---docker数据卷和容器数据卷详解

Posted by yishuifengxiao on 2019-03-02

概念:有点类似我们 Redis 里面的 rdb 和 aof 文件

先来看看 Docker 的理念:

  • 将运用与运行的环境打包形成容器运行 ,运行可以伴随着容器,但是我们对数据的要求希望是持久化的
  • 容器之间希望有可能共享数据

一 容器数据卷的作用

  卷就是目录或文件,存在于一个或多个容器中,由 docker 挂载到容器,但不属于联合文件系统,因此能够绕过 Union File System 提供一些用于持续存储或共享数据的特性:

  卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此 Docker 不会在容器删除时删除其挂载的数据卷

特点:

  • 1:数据卷可在容器之间共享或重用数据

  • 2:卷中的更改可以直接生效

  • 3:数据卷中的更改不会包含在镜像的更新中

  • 4:数据卷的生命周期一直持续到没有容器使用它为止

总结

  • 容器持久 hua4
  • 容器间继承
  • 数据共享

二 添加数据卷

2.1 通过命令添加

添加命令如下

1
docker run -it -v /宿主机的绝对路径目录:/容器内目录 镜像名

主机上执行如下命令:

yishui@yishui:~$ docker images 
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
yishui/tomcat-demo   1.0                 1323b27a2652        2 hours ago         463MB
<none>               <none>              7cfe70fc34b0        2 hours ago         463MB
tomcat               latest              168588387c68        3 weeks ago         463MB
centos               latest              1e1148e4cc2c        2 months ago        202MB
yishui@yishui:~$ docker run -it -v /home/yishui/桌面/demo:/dataContainer centos
[root@34e873f8dc2b /]# ls
anaconda-post.log  bin  dataContainer  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@34e873f8dc2b /]# 

可以看到,本地路径已经被挂在进入了。

2.2 查看数据卷是否挂载成功

yishui@yishui:~$ docker ps 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
34e873f8dc2b        centos              "/bin/bash"         10 minutes ago      Up 10 minutes                           upbeat_leavitt
yishui@yishui:~$ 
yishui@yishui:~$ docker inspect 34e873f8dc2b
[
    {
        "Id": "34e873f8dc2b2dfb5eb6c759bea5e37282003d6ff45743d5c10a769acba170df",
        "Created": "2019-03-02T14:41:25.607089707Z",
        "Path": "/bin/bash",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 8845,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2019-03-02T14:41:27.06209462Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:1e1148e4cc2c148c6890a18e3b2d2dde41a6745ceb4e5fe94a923d811bf82ddb",
        "ResolvConfPath": "/var/lib/docker/containers/34e873f8dc2b2dfb5eb6c759bea5e37282003d6ff45743d5c10a769acba170df/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/34e873f8dc2b2dfb5eb6c759bea5e37282003d6ff45743d5c10a769acba170df/hostname",
        "HostsPath": "/var/lib/docker/containers/34e873f8dc2b2dfb5eb6c759bea5e37282003d6ff45743d5c10a769acba170df/hosts",
        "LogPath": "/var/lib/docker/containers/34e873f8dc2b2dfb5eb6c759bea5e37282003d6ff45743d5c10a769acba170df/34e873f8dc2b2dfb5eb6c759bea5e37282003d6ff45743d5c10a769acba170df-json.log",
        "Name": "/upbeat_leavitt",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "docker-default",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": [
                "/home/yishui/桌面/demo:/dataContainer"
            ],
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "shareable",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DiskQuota": 0,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": 0,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/asound",
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/6c2a4ebd1bbe8f6dedc2f074cdde310377e2d9d20be637b9c9a89f7b678d236c-init/diff:/var/lib/docker/overlay2/ff665c5429b28f49965818bdfb616377723719f87ae79ba0fb5c42bdffa87bcf/diff",
                "MergedDir": "/var/lib/docker/overlay2/6c2a4ebd1bbe8f6dedc2f074cdde310377e2d9d20be637b9c9a89f7b678d236c/merged",
                "UpperDir": "/var/lib/docker/overlay2/6c2a4ebd1bbe8f6dedc2f074cdde310377e2d9d20be637b9c9a89f7b678d236c/diff",
                "WorkDir": "/var/lib/docker/overlay2/6c2a4ebd1bbe8f6dedc2f074cdde310377e2d9d20be637b9c9a89f7b678d236c/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/home/yishui/桌面/demo",
                "Destination": "/dataContainer",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
        "Config": {
            "Hostname": "34e873f8dc2b",
            "Domainname": "",
            "User": "",
            "AttachStdin": true,
            "AttachStdout": true,
            "AttachStderr": true,
            "Tty": true,
            "OpenStdin": true,
            "StdinOnce": true,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "ArgsEscaped": true,
            "Image": "centos",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20181205",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "9f7f7afba32a3ebd87864c133a755efdbbd5d19edcd57188cd7c3f587931653f",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/9f7f7afba32a",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "e2242781e120de2e769a368c7a6182b3db7ed4b73d4da79e39066371809e0a26",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.3",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:03",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "2d6916d345929f6d9d83583bcab801903d0061620c1b4669699eb7a7bfd61462",
                    "EndpointID": "e2242781e120de2e769a368c7a6182b3db7ed4b73d4da79e39066371809e0a26",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:03",
                    "DriverOpts": null
                }
            }
        }
    }
]
yishui@yishui:~$ 

HostConfig 下面的 Binds 节点表明已经挂载成功。(也可以看 Mounts 节点)

容器停止退出后,修改主机数据,再次进入容器,数据依旧同步

2.3 带权限启动

1
docker run -it -v /宿主机的绝对路径目录:/容器内目录:ro 镜像名

2.4 通过 DockerFile 添加

tomcat 的官方 DockerFile 示例文件

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#

FROM openjdk:8-jre-buster

ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME

# let "Tomcat Native" live somewhere isolated
ENV TOMCAT_NATIVE_LIBDIR $CATALINA_HOME/native-jni-lib
ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR

# see https://www.apache.org/dist/tomcat/tomcat-9/KEYS
# see also "versions.sh" (https://github.com/docker-library/tomcat/blob/master/versions.sh)
ENV GPG_KEYS 48F8E69F6390C9F25CFEDCD268248959359E722B A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243

ENV TOMCAT_MAJOR 9
ENV TOMCAT_VERSION 9.0.58
ENV TOMCAT_SHA512 33c030a312a0a087deeb06fff921d13a23789e152d30620f33a368e7a2244c762fcf9acd55f3b90f08560704ba45bc2be820bccf2058b0cf5801a7b124f9056d

COPY --from=tomcat:9.0.58-jdk8-openjdk-buster $CATALINA_HOME $CATALINA_HOME
RUN set -eux; \
apt-get update; \
xargs -rt apt-get install -y --no-install-recommends < "$TOMCAT_NATIVE_LIBDIR/.dependencies.txt"; \
rm -rf /var/lib/apt/lists/*

# verify Tomcat Native is working properly
RUN set -eux; \
nativeLines="$(catalina.sh configtest 2>&1)"; \
nativeLines="$(echo "$nativeLines" | grep 'Apache Tomcat Native')"; \
nativeLines="$(echo "$nativeLines" | sort -u)"; \
if ! echo "$nativeLines" | grep -E 'INFO: Loaded( APR based)? Apache Tomcat Native library' >&2; then \
echo >&2 "$nativeLines"; \
exit 1; \
fi

EXPOSE 8080
CMD ["catalina.sh", "run"]

在宿主机上操作:

  • 根目录下新建 demo 文件夹并进入

  • 可在 Dockerfile 中使用 VOLUME 指令 来给镜像添加一个或多个数据卷

命令如下:

1
VOLUME["/dataVolumeContainer","/dataVolumeContainer2","/dataVolumeContainer3"]

说明:
出于可移植和分享的考虑,用-v 主机目录:容器目录这种方法不能够直接在 Dockerfile 中实现。

由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有的宿主机上都存在这样的特定目录。

文件内容如下:

1
2
3
4
5
# volume test
FROM centos
VOLUME ["/containerPath1","/containerPath2"]
CMD echo "完成===========》"
CMD /bin/bash
  • build 后生成镜像(获得一个新镜像)

命令如下

1
docker build -f /demo/dockerFile_demo yishui_dockerFile/centos
  • 启动新生成的容器

2.5 获取映射路径

此时,可以通过

1
docker inspect 容器 Id

获取到 containerPath1,containerPath2 在宿主机上对应的路径

三 访问权限报错

Docker 挂载主机目录 Docker 访问出现 cannot open directory .: Permission denied

解决办法:在挂载目录后多加一个—privileged=true 参数即可

四 容器数据卷

命名的容器挂载数据卷,其它容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器

  • 先启动第一个容器,并将其命名为 doc01
  • 分别启动 doc02 和 doc03 并继承 doc01
1
docker run -it --name doc02 --volumes-from doc01 yishui_demo/centos

结论:容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止