一,docker容器面临的困境:
  • 容器运行中产生的数据,是放到容器栈的最顶层,当容器停止并被删除后,这些数据就被删除了。
  • docker采用COW(写时复制)策略,导致性能低下。比如有个mysql容器,会有频繁的I/O处理。
二,解决策略:给容器外挂一个存储文件系统,它就叫docker存储卷(Volumes),它独立于容器的生命周期,删除容器时不会删除卷(让然也可以做到,删除容器的时候也删除卷,但没有这么干的)。

让容器里面的某个目录绑定到宿主机的某个目录。

docker 修改mysql 数据目录 更改docker 存储目录_数据

容器写数据时,写到/下的数据,最后被写到了容器的可读写层;写到/data下的数据,最后被写到了宿主机的/data目录下了。如下图:

docker 修改mysql 数据目录 更改docker 存储目录_docker 修改mysql 数据目录_02

下图的宿主机A,B,C是文件系统NFS的客户端。宿主机A的文件目录A,宿主机B的文件目录B,宿主机C的文件目录C,都是访问NFS上的同一个目录。

使用docker存储卷功能,让宿主机A上运行的mysql容器,产生的数据目录,绑定到宿主机A的文件目录A,所以当由mysql容器产生的数据,就存放到了宿主机A的文件目录A上了,进而就存到到了NFS上了。

当宿主机A上运行的mysql容器被删除了,数据还是在的,存在NFS上了。

当在宿主机B或者宿主机C上运行刚才那个mysql容器,也让产生的数据目录,绑定到宿主机B或者宿主机C,可以从NFS上可以拿到数据,所以数据和在宿主机A上运行是一样的。

这就给运维提供了极大的便利,容器可以随便部署到集群里的任何机器上了。

docker 修改mysql 数据目录 更改docker 存储目录_docker 修改mysql 数据目录_03

可以用【存储】,【状态】来划分4个象限。

nginx只作为反向代理服务器,所以它没有状态也不需要存储。

docker 修改mysql 数据目录 更改docker 存储目录_nginx_04

三,docker存储卷有2种策略,都是使用-v选项。
  • bind mount volume:手动指定宿主机目录。
    命令:docker run -v HOSTDIR:CONTAINERDIR
#  docker run --name b1 -it --rm -v /tmp/html:/data busybox:latest
  • docker-managed volume:由docker自己决定宿主机目录。
    命令:docker run -v CONTAINERDIR
# docker run --name b1 -it --rm -v /data busybox:latest

我们不知道被关联的宿主机的目录是啥,使用docker inspect b1,找到【Mount】里的【Source】,就可以看到了。但是你下次再启动容器是,关联的目录也会变化。

也可以看到Volumes。

# docker inspect b1
"Mounts": [
            {
                "Type": "volume",
                "Name": "2eeb1bdee5c83a304d101a98b06430af3aff27a578ad38c7e23423f317db9063",
                "Source": "/var/lib/docker/volumes/2eeb1bdee5c83a304d101a98b06430af3aff27a578ad38c7e23423f317db9063/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
"Volumes": {
                "/data": {}
            },

使用:docker inspect -f {{.Mounts}} b1,也可以看到。注意大括号里的key是区分大小写的。

docker 修改mysql 数据目录 更改docker 存储目录_docker_05

四,活用volume
  • 让2个容器绑定到宿主机的同一个目录,以达到2个容器的通信。
# docker run --name b1 -it --rm -v /tmp/html:/data busybox:latest
# docker run --name b2 -it --rm -v /tmp/html:/data2 busybox:latest

2个容器都绑定到了宿主机的/tmp/html上了。

  • 当另一个容器想和某个容器绑定到宿主机的同一个目录时,但是又不知道宿主机的目录,这时,可以让这个容器直接使用某个容器的volume,这样一来,就不用知道宿主机的目录了。
    命令:docker run --volumes-from b1
# docker run --name b2 -it --rm --volumes-from b1 busybox:latest
  • volume和joined containers(参考:二,host章节 )一起使用,创建nginx容器和tomcat容器,共享base容器的网络空间和volume。
  • 找一个容器,作为基础,它使命是:
  • 指定宿主机的目录
  • 提供统一的对外网络接口,外部客户端直接可以访问nginx服务,但是看不到tomcat
  • nginx和tomcat使用lo(127.0.0.1)通信。
# docker run --name base -it -v /tmp/html:/data busybox:latest
  • 启动nginx容器:--network container:base --volumes-from base
# docker run --name nginx -it --rm --network container:base --volumes-from base busybox:latest
  • 启动tomcat容器:--network container:base --volumes-from base
# docker run --name tomcat -it --rm --network container:base --volumes-from base busybox:latest