数据是应用程序重要的产出,所以很好的管理和存储数据,是对应用程序劳动结果的尊重。特别是在大数据时代,所有的数据都是重要的资产。Docker里,容器运行的文件系统处于沙盒环境中,与外界是隔离的。

一、数据管理实现方式

Docker容器中的文件系统,有两个缺点:

  • 沙盒文件系统是跟随容器生命周期所创建和移除的,数据无法直接被持久化存储
  • 由于容器隔离,很难从容器外部获得或操作容器内部文件中的数据

Docker容器文件系统是基于UnionFS,由于UnionFS支持挂载不同类型的文件系统到统一的目录结构中,所以只需要将宿主操作系统中,文件系统里的文件或目录挂载到容器中,便能够让容器内外共享这个文件。UnionFS带来的读写性能损失是可以忽略不计的,所以这种实现可以说是相当优秀的。

挂载方式

基于底层存储实现,Docker提供了三种适用于不同场景的文件系统挂载方式:Bind MountVolumeTmpfs Mount




docker 数据存储 如何保证docker数据不丢失_Docker


Bind Mount,能够直接将宿主操作系统中的目录和文件挂载到容器内的文件系统中,通过指定容器外的路径和容器内的路径,就可以形成挂载映射关系,在容器内外对文件的读写,都是相互可见的。

Volume,从宿主操作系统中挂载目录到容器内,只是这个挂载的目录由Docker进行管理,只需要指定容器内的目录,不需要关心具体挂载到了宿主操作系统中的位置。

Tmpfs Mount,支持挂载系统内存中的一部分到容器的文件系统里,不过由于内存和容器的特征,它的存储并不是持久的,其中的内容会随着容器的停止而消失。

二、挂载文件到容器

将宿主操作系统中的目录挂载到容器,可以在容器创建的时候通过传递-v--volume选项来指定内外挂载的对应目录或文件。


docker run -d --name nginx -v /webapp/html:/usr/share/nginx/html nginx


挂载宿主操作系统目录的形式是-v <host-path>:<container-path>,其中host-path和container-path分别代表宿主操作系统中的目录和容器中的目录。为了避免混淆,Docker强制定义目录时必须使用绝对路径,不能使用相对路径。

当挂载了目录的容器启动后,可以看到我们在宿主操作系统中的文件已经出现在容器中了。


docker exec nginx ls /usr/share/nginx/html
index.html


docker inspect的结果里,可以看到有关容器数据挂载相关的信息。


docker inspect nginx

{
    "Mounts": [
        {
            "Type": "bind",
            "Source": "/webapp/html",
            "Destination": "/usr/share/nginx/html",
            "Mode": "",
            "RW": true,
            "Propagation": "rprivate"
        }
    ]
}


在挂载的信息中有一个RW字段,这表示挂载目录或文件的读写性。实际操作中,Docker还支持以只读的方式挂载,通过只读方式挂载的目录和文件,只能被容器中的程序读取,但不接受容器中程序修改它们的请求。在挂载选项-v后再接上:ro就可以只读挂载了。


docker run -d --name nginx -v /webapp/html:/usr/share/nginx/html:ro nginx


由于宿主操作系统文件挂载在权限允许的情况下能够挂载任何目录或文件,这给系统的安全性造成了一定的隐患,所以我们在使用 Bind Mount 的时候,一定要特别注意挂载的外部目录选择。当然,在保证安全性的前提下,有几种常见场景非常适合使用这种挂载方式。

  • 当需要从宿主操作系统共享配置的时候,对于一些配置项,可以直接从容器外部挂载到容器中,利于保证容器中的配置为确认的值,也方便对配置进行监控。
  • 需要借助Docker进行开发的时候,直接把代码挂载进入容器,每次对代码的修改都可以直接在容器外部进行。

挂载临时文件目录

Tmpfs Mount是一种特殊的挂载方式,利用内存来存储数据。由于内存不是持久性存储设备,所以其带给Tmpfs Mount的特征就是临时性挂载。

与挂载宿主操作系统目录或文件不同,挂载临时文件目录要通过--tmpfs选项来完成。由于内存的具体位置不需要指定,选项里只需要传递挂载到容器内的目录即可。容器已挂载的临时文件目录也可以通过docker inspect查看。


docker run -d --name webapp --tmpfs /webapp/tmp webapp


挂载临时文件几种常见的适应场景:

  • 应用中使用到,但不需要进行持久保存的敏感数据,可以借助内存的非持久性和程序隔离性进行一定的安全保障
  • 读写速度要求较高,数据变化量大,但不需要持久保存的数据,可以借助内存的高读写速度减少操作的时间

三、使用数据卷

除了与其他虚拟机工具近似的宿主操作系统目录挂载的功能外,Docker还创造了数据卷 Volume概念。数据卷的本质依然是宿主操作系统上的一个目录,只不过这个目录存放在 Docker内部,接受Docker的管理。

在使用数据卷进行挂载时,不需要知道数据具体存储在了宿主操作系统的何处,只需要给定容器中的哪个目录会被挂载即可。

依然可以使用-v--volume选项来定义数据卷的挂载。


docker run -d --name nginx -v /nginx/volume nginx


数据卷挂载到容器后,我们可以通过 docker inspect 看到容器中数据卷挂载的信息。


docker inspect nginx

{
    "Mounts": [
        {
            "Type": "volume",
            "Name": "8c2b91ad2e5fad6a99f269b12233014d9b995b655f195efbcc07cd6c3efd4913",
            "Source": "/var/lib/docker/volumes/8c2b91ad2e5fad6a99f269b12233014d9b995b655f195efbcc07cd6c3efd4913/_data",
            "Destination": "/nginx/volume",
            "Driver": "local",
            "Mode": "",
            "RW": true,
            "Propagation": ""
        }
    ]
}


绑定挂载有所区别,除了Type中的类型不一样之外,在数据卷挂载中Name和Source信息也不同。

其中Source是Docker为分配用于挂载的宿主机目录,其位于Docker的资源区域(默认的/var/lib/docker)内。当然,使用者并不关注这个目录,对它的管理都已经在Docker内实现了。

为了方便识别数据卷,可以像命名容器一样为数据卷命名,Name就是数据卷的命名。未给出数据卷命名的时候,Docker会采用数据卷的ID命名数据卷。也可以通过-v <name>:<container-path>来命名数据卷。


docker run -d --name nginx -v nginxdata:/nginx/volume nginx


A、数据卷作用

  • 当数据在多个容器间共享时,利用数据卷可以在保证数据持久性和完整性的前提下,完成更多自动化操作;
  • 当对容器中挂载的内容进行管理时,可以直接利用数据卷自身的管理方法实现;
  • 当使用远程服务器或云服务作为存储介质的时候,数据卷能够隐藏更多的细节,让整个过程变得更加简单。

B、共用数据卷

数据卷的另一大作用是实现容器间的目录共享,也即通过挂载相同的数据卷,让容器之间能够同时看到并操作数据卷中的内容。这个功能虽然也可以通过绑定挂载来实现,但通过数据卷来操作会更加的舒适、简单。

由于数据卷的命名在Docker中是唯一的,所以很容易通过数据卷的名称确定数据卷,可以很方便的让多个容器挂载同一个数据卷。


docker run -d --name webapp -v html:/webapp/html webapp
docker run -d --name nginx -v html:/usr/share/nginx/html:ro nginx


使用-v选项挂载数据卷时,如果数据卷不存在,Docker会为自动创建和分配宿主操作系统的目录,而如果同名数据卷已经存在,则会直接引用。

还可以通过docker volume下的命令专门操作数据卷。

通过docker volume create可以不依赖于容器独立创建数据卷。


docker volume create appdata


通过docker volume ls可以列出当前已创建的数据卷。


docker volume ls
DRIVER              VOLUME NAME
local               html
local               appdata


C、删除数据卷

虽然数据卷的目的是用来持久化存储数据的,但有时候也需要删除它们以释放空间。直接去Docker的目录下删除显然不是好的选择,应该通过Docker对数据卷的管理命令来删除它们。

可以通过docker volume rm来删除指定的数据卷。


docker volume rm appdata


在删除数据卷之前,必须保证数据卷没有被任何容器所使用(引用过这个数据卷的容器都已经删除),否则Docker不允许删除这个数据卷。

对于没有直接命名的数据卷,因为要反复核对数据卷ID,使用时并不方便,对于没有命名的数据卷,通常可以看成它们与对应的容器产生了绑定,因为其他容器很难使用到它们。而这种绑定关系的产生,也可以在容器删除时将它们一并删除。

在docker rm删除容器的命令中,可以通过增加-v选项来删除容器关联的数据卷。


docker rm -v webapp


如果没有随容器删除数据卷,Docker在创建新的容器时也不会启用它们,此数据卷会一直占用硬盘空间而又不受管理,可以通过docker volume rm来删除它们。

为此,Docker专门提供了docker volume prune命令,它可以删除那些没有被容器引用的数据卷。


ocker volume prune -f
Deleted Volumes:
af6459286b5ce42bb5f205d0d323ac11ce8b8d9df4c65909ddc2feea7c3d1d53
0783665df434533f6b53afe3d9decfa791929570913c7aff10f302c17ed1a389
65b822e27d0be93d149304afb1515f8111344da9ea18adc3b3a34bddd2b243c7


四、数据卷容器

在数据卷的基础上,有一种相对新颖的用法,也就是数据卷容器。所谓数据卷容器,不指定具体应用,甚至不需要运行的容器,使用它的目的,是为了定义一个或多个数据卷并持有它们的引用。


docker 数据存储 如何保证docker数据不丢失_docker 数据存储_02


创建数据卷容器的方式很简单,由于不需要容器本身运行,因而找个简单的系统镜像都可以完成创建。


docker create --name appdata -v /webapp/storage ubuntu


使用数据卷容器时,不需要再定义数据卷的名称,因为可以通过对数据卷容器的引用来完成数据卷的引用。而不设置数据卷的名称,也避免了在同一Docker中数据卷重名的尴尬。

Docker的Network是容器间的网络桥梁,如果做类比,数据卷容器就可以算是容器间的文件系统桥梁。可以像加入网络一样引用数据卷容器,只需要在创建新容器时使用专门的--volumes-from选项即可。


docker run -d --name webapp --volumes-from appdata webapp


引用数据卷容器时,不需要再定义数据卷挂载到容器中的位置,Docker会以数据卷容器中的挂载定义将数据卷挂载到引用的容器中。

虽然看上去数据卷容器与数据卷的使用方法变化不大,但最关键的就在于其真正隐藏了数据卷的配置和定义,只需要通过数据卷容器的名称来使用它。这些细节的隐藏,意味着能够更轻松的实现容器的迁移。

五、Docker Object

Docker中常用的对象,包含images、containers、networks、volumes、plugins,Docker支持REST风格进行操作,以上对象都可以进行增删改查操作。

也是基于此,Docker的命令有新旧两种风格,在命令行直接输入docker,会出现提示。


Management Commands:
  builder     Manage builds
  config      Manage Docker configs
  container   Manage containers
  engine      Manage the docker engine
  image       Manage images
  network     Manage networks
  node        Manage Swarm nodes
  plugin      Manage plugins
  secret      Manage Docker secrets
  service     Manage services
  stack       Manage Docker stacks
  swarm       Manage Swarm
  system      Manage Docker
  trust       Manage trust on Docker images
  volume      Manage volumes

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  build       Build an image from a Dockerfile
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  events      Get real time events from the server
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  history     Show the history of an image
  images      List images
  import      Import the contents from a tarball to create a filesystem image
  info        Display system-wide information
  inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  login       Log in to a Docker registry
  logout      Log out from a Docker registry
  logs        Fetch the logs of a container
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  ps          List containers
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  run         Run a command in a new container
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  search      Search the Docker Hub for images
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  version     Show the Docker version information
  wait        Block until one or more containers stop, then print their exit codes


Docker的Management中,还可以通过--help查看支持的子命令。


docker container --help

Usage:	docker container COMMAND

Manage containers

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  inspect     Display detailed information on one or more containers
  kill        Kill one or more running containers
  logs        Fetch the logs of a container
  ls          List containers
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  prune       Remove all stopped containers
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  run         Run a command in a new container
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  wait        Block until one or more containers stop, then print their exit codes


Docker常用命令。


docker 数据存储 如何保证docker数据不丢失_docker_03



参考:

http://blog.poetries.top/2018/11/20/docker-base/