• Docker 匿名卷、命名卷与绑定挂载


    1 容器删除,容器内数据丢失

    如果仅仅将数据存储在容器中,那么就会遇到一个问题:一旦容器被删除,所存储的数据将全部丢失。

    2 卷

    容器具有独立的文件系统,一般情况下与本机没有任何关联。Docker 使用卷实现容器内数据的持久保存。

    Volumes are folders on your host machine hard drive, which are mounted(“made available”, mapped) into containers. 卷是主机文件夹,被映射到容器中。

    在这里插入图片描述
    这两个文件夹中的任意一个发生变化,都会反映到另一个文件夹。容器既可以写入数据到卷,也可以从卷中读出数据。

    卷分为匿名卷和命名卷。

    2.1 匿名卷 (Anonymous Volumes)

    在 Dockerfile 中,匿名卷的指令格式: VOLUME ["folder_name"]folder_name 为容器内的文件夹( / 路径)。
    以下是一个 node app 的 Dockerfile:

    FROM node
    
    WORKDIR /app
    
    COPY package.json .
    
    RUN npm install
    
    COPY . .  
    
    EXPOSE 80
    
    VOLUME ["/app/feedback"]
    
    CMD [ "node", "server.js" ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    docker 将匿名卷隐藏存放在本地的未知路径。

    如果容器启动时使用了 --rm 选项,容器停止时,容器被自动删除,匿名卷也会自动被删除。
    反之,如果没有--rm选项,即使使用命名 docker container rm my_container 删除了容器,匿名卷不会被自动删除。每次创建新的容器,都会重新创建新的匿名卷。
    重启容器则使用已有附加的匿名卷。

    可以在Dockerfile 中指定创建匿名卷,也可以在创建容器时指定匿名卷。

    要删除匿名卷,使用命令 docker volume rm 或者 prune.

    2.2 命名卷 (Named Volumes)

    与匿名卷相反,命名卷不会被附加到具体容器上,如果容器被删除,命名卷会保留。 同匿名卷,被 docker 隐藏存放在本地的未知路径,不易寻找,不应访问或者编辑命名卷。

    不能在 Dockerfile 内创建命名卷,只能在运行容器时指定,使用-v 选项,v 即 volume,语法格式:
    -v 任意名称:容器内路径
    例如:
    docker container run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback feedback-node:volumes

    2.3 与卷相关的命令

    docker volume --help 列举与卷相关的命令:

    Commands:
      create      Create a volume
      inspect     Display detailed information on one or more volumes
      ls          List volumes
      prune       Remove all unused local volumes
      rm          Remove one or more volumes
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    docker volume ls 列出所有卷

    3 绑定挂载 (由开发者管理,可用于代码调试)

    绑定挂载也是映射本地文件夹到运行的容器,与卷不同的是,可以直接修改本地文件夹,修改直接反映到容器。应用可以是,将app 的源代码文件夹进行绑定挂载,编辑源代码,容器中的 image 自动被修改。
    从而避免 1. 修改代码 -> 2. stop 容器 -> 3. 重新 build image ->4. 重新启动容器 这一重复的开发过程。

    在这里插入图片描述
    绑定挂载同样在运行容器时指定,同命名卷,不能在 Dockerfile 中指定。命令格式:

    -v 绝对路径:容器内文件夹

    对于如下的 Dockerfile,源代码被copy到 WORKDIR /app

    FROM node
    
    WORKDIR /app
    
    COPY package.json .
    
    RUN npm install
    
    COPY . .
    
    EXPOSE 80
    
    CMD [ "node", "server.js" ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    因此冒号右边是 /app,对于 windows 系统,命令如下:

    docker container run -p 3000:80 --name feedback-app --rm -v feedback:/app/feedback -v ${PWD}:/app feedback-node:volumes

    也可以不用 ${PWD}而是 copy 整个路径,例如 vs code explorer 里,右键"copy path",

    -v D:\temp\data-volumes-01-starting-setup:/app
    使用 -v "D:\temp\data-volumes-01-starting-setup:/app" 即加双引号更好,以防止特殊字符使命令不起作用。

    如果本地文件夹没有 node_modules, 此命令将无法启动容器,原因是,本地文件夹没有 node_modules,绑定挂载使得本地的文件完全覆盖了 /app 里的文件,app 缺少依赖包,无法运行。
    解决方法是,使用匿名卷。
    使用绑定挂载,本地文件夹将覆盖容器文件夹,而不是反过来,毕竟,容器删除或修改本地源代码是不能容忍的。
    为了防止容器内的 node_modules 因为本地没有而被删除,使用匿名卷,上述命令修改如下:

    docker container run -d -p 3000:80 --name feedback-app --rm -v feedback:/app/feedback -v ${PWD}:/app -v /app/node_modules feedback-node:volumes

    此命令中使用了:

    1. 命名卷:容器删除后保存数据, -v feedback:/app/feedback
    2. 绑定挂载:代码调试, -v ${PWD}:/app,还需要步骤3的匿名卷
    3. 因为步骤2,使用绑定挂载,本地文件夹覆盖了容器内的文件夹,容器内新生成的node_modules被删除,因此增加匿名卷 -v /app/node_modules

    当卷存在冲突时,docker指定路径越长越具体优先级越高,/app/node_modules路径比/app长,因此,匿名卷的由 npm install 生成的文件夹 node_modules 将覆盖绑定挂载的空的 app/node_modules

    将绑定挂载设定为容器只能读取,无法写入,在路径后加 :ro,同时为了保证源代码中的 temp 文件夹允许容器写入,增加匿名卷 -v /app/temp

    docker container run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback -v ${PWD}:/app:ro -v /app/temp -v /app/node_modules feedback-node:volumes

    容器正在运行,此时VS code 修改代码,例如 MySite 改成,MySite!!!!!,保存,然后浏览器页面刷新,就可以看到对应的界面已经被修改:
    在这里插入图片描述

    4 命名卷、匿名卷与绑定挂载三者比较

    在这里插入图片描述

    匿名卷,不管是在 Dockerfile 中指定,还是在命令行指定,都可以锁定容器中已经存在的某些数据。

  • 相关阅读:
    Deep Upsupervised Cardinality Estimation 解读(2019 VLDB)
    【计算机网络】计算机网络复习总结 ----- 计算机网络概述
    【D3.js】2.2-给 Circle 元素添加属性
    《Orange‘s 一个操作系统的实现》第六章
    java性能优化案例——面试可能用得到
    计算机毕业设计之java+javaweb的网上电子书店-图书商城网站
    Java---Stream进阶
    在C/C++中使用vcpkg
    测试员如何面对30岁后的下坡路,伤不起的年龄,职业道路何去何从?
    Anaconda Powershell Prompt和Anaconda Prompt的区别
  • 原文地址:https://blog.csdn.net/ftell/article/details/124412241