docker-容器持久化

数据持久化

  • 在做数据卷的时候有三种写入方式

    1.往容器内写入数据 bind mount (物理机挂载到容器的权限有ro,rw)
    2.从容器内获取数据 managed volume (容器持久化将数据存储到物理机)
    3.把容器放到内存中 tmpfs (内存挂载)

  • 共享 volume container (专门为其他容器提供存储的功能卷) 也叫容器卷

  • volume nfs (通过nfs服务,共享容器之间的数据,并把容器的数据保存到nfs服务中)

  • data-packed volume container (镜像持久化,将数据存储到一个docker镜像中)

资源存储

  • 容器的数据分为热数据和冷数据
  • 冷数据 > 就是镜像层的数据
  • 热数据 > 是容器层的数据 (热数据需要存储起来)

tmpfs内存挂载

  • 通过 –tmpfs 将容器内的目录挂载到内存中
    docker run -itd --name tmpfs-test --tmpfs /app busybox
    # 容器内的app目录就挂载到内存了,这时读写速度会非常快

bind mount (主机->容器)

  • 将物理机的内容挂载到容器内
  • 权限有 ro 和 rw
  • 挂载的必须是目录或者文件,不可以是块设备
  • 通过 –volume 或者 -v 进行挂载
    [root@localhost ~]# mkdir htdocs
    [root@localhost ~]# echo 'lmk' > htdocs/index.html 
    [root@localhost ~]# docker run -itd -p 80:80 --volume /root/htdocs/:/usr/local/apache2/htdocs httpd
    2d57a0bd883aa4b93764305eb8a5f5ac27c844c95d2096296dd418242f2719cf   
        #  --volume /root/htdocs/:/usr/local/apache2/htdocs 这里是将 本地的 htdocs 挂载到容器的 /usr/local/apache2/htdocs内
    [root@localhost ~]# curl 192.168.100.211                                                                               
    lmk
    [root@localhost ~]# echo 'kml' > htdocs/index.html
    [root@localhost ~]# curl 192.168.100.211
    kml
    
  • 可以看出已经将本地的目录挂载到容器内了,默认是容器和物理机都可以修改的,可以设置容器不能修改(把容器内的权限设置ro)
  • 设置权限
    [root@localhost ~]# docker run -itd --name httpd_1 -p 81:80 --volume /root/htdocs/:/usr/local/apache2/htdocs:ro httpd
    87c465ca5613bbc3934b6330261c7ede1ef2fb598cd1325fce68254c7000652f
    # 在最后面添加 ro权限,现在容器就修改不了数据了
    [root@localhost ~]# docker exec -it httpd_1 bash
    root@87c465ca5613:/usr/local/apache2# cd htdocs/
    root@87c465ca5613:/usr/local/apache2/htdocs# echo 'kkk' > index.html
    bash: index.html: Read-only file system
    # Read-only 只读的
  • 将文件挂载到容器内
    [root@localhost ~]# docker run -it --name bbox1 --volume /root/htdocs/index.html:/data/index.html busybox
    / # cd /data/
    /data # cat index.html
    kml
    /data # ls
    index.html
    # 将物理机的文件挂载到容器内
  • 查看一下挂载的信息
    [root@localhost ~]# docker inspect httpd_1
            "Mounts": [
                {
                    "Type": "bind",  # 挂载类型
                    "Source": "/root/htdocs",  # 源地址目录(物理机的目录)
                    "Destination": "/usr/local/apache2/htdocs", 被挂载目录(容器的目录)
                    "Mode": "ro", # 权限
                    "RW": false, # 是否读写(如果设置了ro权限这里就是false)
                    "Propagation": "rprivate"  # 传播方向 这里是私有挂载
                }
            ]

bind mount 长格式写法

  • --mount 挂载

  • type 挂载类型

  • source 源地址(物理机地址)

  • destination \target 挂载地址(容器地址) 在这里后面可以加权限 readonly(ro权限)

  • bind-propagation 传播方向

    开启容器挂载目录

    [root@localhost ~]# docker run -itd --name httpd_2 -p:82:80 --mount type=bind,source=/root/htdocs,target=/usr/share/nginx/html --mount type=bind,source=/root/htdocs,target=/usr/share/nginx/html2,readonly,bind-propagation=rslave nginx  
    afd3a75b8e904fa52820d4ec8d73e940bd91a42f3223bea5b39e1725c9edd6e6   
        # 变量写法
        # docker run -itd --name httpd --mount type=bind,source="$(pwd)"/htdocs,target=/usr/share/nginx/html --mount type=bind,source="$ (pwd)"/htdocs,target=/usr/share/nginx/html2,readonly,bind-propagation=rslave nginx
    
    # 将htdocs目录挂载到nginx的html目录 又将htdocs目录挂载到html2目录设置权限为只读,设置传播方向为rslave
    [root@localhost ~]# curl 192.168.100.211:82
    kml

    进入容器

    [root@localhost ~]# docker exec -it httpd_2 bash
    root@4554a29ba882:/# cd /usr/share/nginx/html2/
    root@4554a29ba882:/usr/share/nginx/html2# ls
    index.html
    root@4554a29ba882:/usr/share/nginx/html2# echo 'kkk' > index.html
    bash: index.html: Read-only file system
    # html2 目录不可读写
  • 查看挂载信息

    [root@localhost ~]# docker inspect httpd_2
                "Mounts": [
                    {
                        "Type": "bind", # 类型
                        "Source": "/root/htdocs", # 源目录
                        "Target": "/usr/share/nginx/html" # 挂载目录
                    },
                    {
                        "Type": "bind", # 类型
                        "Source": "/root/htdocs", #源目录
                        "Target": "/usr/share/nginx/html2", #挂载目录
                        "ReadOnly": true, # 是否只读
                        "BindOptions": {
                            "Propagation": "rslave" # 传播方向
                        }
                    }
                ],

maneged volume (容器->主机)

  • 和bind mount 最大的区别就是不需要指定源地址

    容器映射出目录

    [root@localhost ~]# docker run -itd --name httpd -p 80:80 --volume /usr/local/apache2/htdocs httpd 
    4805dd547134e0a6db1a431d11b7b3153a27feb040bfc134a56e163fd27801db
    [root@localhost ~]# curl 192.168.100.211                                                                          
    <html><body><h1>It works!</h1></body></html>

    查看容器详细挂载信息

    [root@localhost ~]# docker inspect httpd
            "Mounts": [
                {
                    "Type": "volume", # 挂载类型
                    "Name": "7b1a6dbcd4660cf545988020050d20f81476f1d6b883dfbabdeb7f0aaaa28524", # 卷的id
                    "Source": "/var/lib/docker/volumes/7b1a6dbcd4660cf545988020050d20f81476f1d6b883dfbabdeb7f0aaaa28524/_data", # 映射到物理机的地址
                    "Destination": "/usr/local/apache2/htdocs", # 容器内的地址
                    "Driver": "local", # 
                    "Mode": "",
                    "RW": true,
                    "Propagation": ""
                }
            ]

    查看映射目录

    [root@localhost ~]# cd /var/lib/docker/volumes/7b1a6dbcd4660cf545988020050d20f81476f1d6b883dfbabdeb7f0aaaa28524/_data
    [root@localhost _data]# ls
    index.html
    [root@localhost _data]# echo 'lmk_hello' > index.html
    [root@localhost _data]# curl 192.168.100.211
    lmk_hello

volume container 容器卷

  • 通过创建一个容器来映射数据,其他容器只需要挂载这个容器映射的数据
  • 通过 –volumes-from 来挂载容器卷

创建容器卷

# 查看容器卷
[root@localhost ~]# docker volume ls
DRIVER              VOLUME NAME
# 创建容器卷
[root@localhost ~]# docker create --name vc_data --volume /root/htdocs/:/usr/local/apache2/htdocs --volume /usr/local/apache2/logs busybox
84bd5d19bfad5dc447012ab4d4aa58523f0529bd32bb3745540eaf3c4b84a348
# 将本地的 htdocs目录挂载到容器内,又将容器内的logs目录映射出本机
[root@localhost ~]# docker volume ls
DRIVER              VOLUME NAME
local               954a38573384dfd5741744419d539f0079d5d4a5d1e64431518ba383ccc3b761

查看容器卷信息

[root@localhost ~]# docker inspect vc_data  
        "Mounts": [
            {
                "Type": "volume", # 类型
                "Name": "954a38573384dfd5741744419d539f0079d5d4a5d1e64431518ba383ccc3b761", # 卷id
                "Source": "/var/lib/docker/volumes/954a38573384dfd5741744419d539f0079d5d4a5d1e64431518ba383ccc3b761/_data", #映射出的目录
                "Destination": "/usr/local/apache2/logs", # 将容器内的logs目录映射出,到本地的目录
                "Driver": "local", 
                "Mode": "", 
                "RW": true, #读写
                "Propagation": ""
            },
            {
                "Type": "bind", # 类型
                "Source": "/root/htdocs", # 本地目录
                "Destination": "/usr/local/apache2/htdocs", #容器目录
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ]

创建容器挂载容器卷

[root@localhost ~]# docker run -itd --name httpd_1 -p 80:80 --volumes-from vc_data httpd
aa99f7a4b8e4367e69a333b67dc39e738ccfc47f655dbf39b7d832c8f12efb64
[root@localhost ~]# docker run -itd --name httpd_2 -p 81:80 --volumes-from vc_data httpd
52f01ce67bbfb4cf5f254132de25b36b6dfcf2f393e0b30bd07d4ce69698c7dc
[root@localhost ~]# curl 192.168.100.211
kml
[root@localhost ~]# curl 192.168.100.211:81
kml
# 查看映射出的数据
[root@localhost ~]# cd /var/lib/docker/volumes/954a38573384dfd5741744419d539f0079d5d4a5d1e64431518ba383ccc3b761/_data
[root@localhost _data]# ls
httpd.pid

data-packed volume container 镜像持久化

  • 将数据存储到镜像中
  • 可以做数据镜像迁移(如果数据较大就不推荐这样做)

    编写Dockerfile

    [root@localhost ~]# vim Dockerfile
    FROM centos
    ADD htdocs /usr/local/apache2/htdocs                                                                                   
    VOLUME /usr/local/apache2/htdocs

    制作镜像

    [root@localhost ~]# docker build -t data .
    Sending build context to Docker daemon  7.097MB
    Step 1/3 : FROM centos
     ---> 7e6257c9f8d8
    Step 2/3 : ADD htdocs /usr/local/apache2/htdocs
     ---> 13e0d3329dc6
    Step 3/3 : VOLUME /usr/local/apache2/htdocs
     ---> Running in f31b0a8a8842
    Removing intermediate container f31b0a8a8842
     ---> 31daf73594a4
    Successfully built 31daf73594a4
    Successfully tagged data:latest

    将镜像创建成一个容器

    [root@localhost ~]# docker create --name data data
    6f8bfef0a3d3026bfccfc8f959bdeaaa589d7e71491f6b7ca59ebb522f935b1a

    使用容器卷

    [root@localhost ~]# docker run -d -p 8080:80 --volumes-from data httpd
    1a4f18b2204850689553edf3a932d154e120be32649162b716645dc8a31f5b85
    [root@localhost ~]# curl 192.168.100.211:8080
    kkk

关于selinux标签在volume的使用

  • 不能使用 –mount设置selinux标签,设置selinux标签后ro权限会被忽略
  • z(小写) 表示挂载内容在多个容器之间共享
  • Z(大写) 表示挂载内容是私有和非共享的

    小写z

    [root@localhost ~]# docker run --name web3 -d -p 80 --volume /root/htdocs:/usr/local/apache2/htdocs:z httpd
    cfeb66d718a3c57fd7b12c218b260654d5ce33508360ddfa6fda6dd846549b03
    [root@localhost ~]# docker inspect web3 
    
            "Mounts": [
                {
                    "Type": "bind",
                    "Source": "/root/htdocs",
                    "Destination": "/usr/local/apache2/htdocs",
                    "Mode": "z",
                    "RW": true,
                    "Propagation": "rprivate"
                }
            ]
        # 表示这个/root/htdocs 可以在多个容器内共享

    大写z

    [root@localhost ~]# docker run --name web4 -d -p 80 --volume /root/htdocs:/usr/local/apache2/htdocs:Z httpd
    f07661653f09aea204beb8cd673aaa92480690dba59f84b807b98d2b387468f1
    [root@localhost ~]# docker inspect web4 
            "Mounts": [
                {
                    "Type": "bind",
                    "Source": "/root/htdocs",
                    "Destination": "/usr/local/apache2/htdocs",
                    "Mode": "Z",
                    "RW": true,
                    "Propagation": "rprivate"
                }
            ]
        # 表示/root/htdocs 挂载到这个容器的数据时不可以在其他容器内共享的
  • 这个一般不用

–mount 和 –volumes的区别

  • –mount可以有 rw 和ro权限
  • –volumes 只有一个rw权限

docker volume备份

创建一些目录

[root@localhost ~]# mkdir /values
[root@localhost ~]# mkdir /values/test1
[root@localhost ~]# mkdir /values/test2

创建容器卷将杠杆创建的目录挂载进去

# 将本地的values目录挂载到容器内的data目录下
[root@localhost ~]# docker create --name back --volume /values/:/data busybox
af2efdde81198c8e807a5156e82006a025db4065f57787d9eb551d17dec12097

创建容器挂载容器卷

# 创建容器挂载容器卷 
# 并将本地目录的bakcup挂载到容器内的backup中 在容器中运行一个命令 打包 data目录下的数据放到 backup中
[root@localhost ~]# docker run --rm --volumes-from back --volume /root/backup/:/backup busybox tar zcvf /backup/backup.t
ar /data
tar: removing leading '/' from member names
data/
data/test1/
data/test2/
# 本地查看压缩包
[root@localhost ~]# cd backup/
[root@localhost backup]# ls
backup.tar
# 备份完毕

volume nfs 容器间目录共享

  • 需要一台nfs服务器 和一台docker
    192.168.100.211 nfs
    192.168.100.212 docker

安装nfs

[root@localhost ~]# mkdir -p /data/nfs
[root@localhost ~]# yum -y install nfs-utils rpcbind
[root@localhost ~]# vim /etc/exports
/data/nfs *(rw,no_root_squash,sync)
[root@localhost ~]# exportfs -r
[root@localhost ~]# systemctl restart nfs-server
[root@localhost ~]# showmount -e 192.168.100.211
Export list for 192.168.100.211:
/data/nfs *

docker 创建nfs容器卷

[root@localhost ~]# docker volume create --driver local --opt type=nfs --opt o=addr=192.168.100.211,rw --opt device=:/data/nfs volume-nfs
volume-nfs

docker 将 nfs容器卷挂载到容器中

[root@localhost ~]# docker run -itd --name bbox1 --volume volume-nfs:/nfs busybox
2213cfd8aa7983cb2b05e6a5805112e31e22842dc6eeb964d96903123abf8111

修改nfs目录查看容器内是否有文件

# docker查看容器数据
[root@localhost ~]# docker exec -it bbox1 sh
/ # cd /nfs/
/nfs # ls
/nfs #  

# nfs目录创建文件
[root@localhost ~]# cd /data/nfs/
[root@localhost nfs]# echo 'lmk_hello' > file

# 容器查看
/nfs # ls
file
/nfs # cat file
lmk_hello
# 所有数据在nfs服务器内,容器关闭也不会消失

本博客所有文章是以学习为目的,如果有不对的地方可以一起交流沟通共同学习 邮箱:1248287831@qq.com!