5.docker容器数据卷

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: docker基础1. docker前言知识(重要: 知道为什么学, 比学什么更重要): https://www.cnblogs.com/ITPower/p/12945685.html2. docker架构,原理,安装及简单应用: https://www.cnblogs.com/ITPower/p/12945711.html3. docker容器的命令: https://www.cnblogs.com/ITPower/p/12664292.html4. 镜像的原理: https://www.cnblogs.com/ITPower/p/12975385.html

docker基础


1. docker前言知识(重要: 知道为什么学, 比学什么更重要):


https://www.cnblogs.com/ITPower/p/12945685.html


2. docker架构,原理,安装及简单应用:


https://www.cnblogs.com/ITPower/p/12945711.html


3. docker容器的命令: https://www.cnblogs.com/ITPower/p/12664292.html


4. 镜像的原理: https://www.cnblogs.com/ITPower/p/12975385.html


 

目录:


1. docker数据卷的添加方式, 有两种: 命令添加, dockerfile添加


2. 数据加载卷共享: --volumes-from


 

一. 数据卷的添加方式


有两种:


1.1 . 直接命令添加


1. 命令


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

微信图片_20220513142042.png 

-v命令除了可以挂在目录, 还有mkdir的作用. 也就是说, 如果挂在的目录不存在, 那么他会自动创建目录

 

2. 查看数据卷是否挂在成功


docker inspect 容器id


docker inspect d804cc6b6e31, 看到挂在信息Mounts. 我们看到RW, 表示可以读写


微信图片_20220513142115.png


3. 容器和宿主机之间共享数据


在容器中创建数据, 宿主机可以共享. 在宿主机创建数据, 容器可以共享到.


4. 容器停止退出后, 主机修改的数据依然共享


5. 设置带有权限的容器


有时,我们只允许容器读数据, 不允许容器写数据. 这个怎么操作呢?


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


这里的ro表示的是read only, 只读


这是我们使用docker inspect 容器id查看挂在详情


微信图片_20220513142155.png


1.2  Dockerfile添加


简单了解一下,dockerfile是什么?


我们用类比的思想. 
java 中 hello.java, ----> hello.class 源码文件
docker中 image----->dockerfile  
也就是说, hello.class是hello.java的源码文件. 而dockerfile就是image的源码文件


下面我们来看看如何用dockerfile写容器目录的挂载


1. 学习别人是怎么写dockerfile的


我们可以看看别人的dockerfile是怎么写的


在hub.docker.com中搜索tomcat. 我们来看看tomcat的dockerfile


FROM openjdk:11-jdk
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-$TOMCAT_MAJOR/KEYS
# see also "update.sh" (https://github.com/docker-library/tomcat/blob/master/update.sh)
ENV GPG_KEYS 05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 713DA88BE50911535FE716F5208B0AB1D63011C7 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23
ENV TOMCAT_MAJOR 8
ENV TOMCAT_VERSION 8.5.55
ENV TOMCAT_SHA512 996b653b4f81b40ae3620d6424593d23687e5ceb5cbd7357fc8d0e4b92f76903fe7fb20bf7316505e4e86269153fbfe62394bf45e59b4fb1cbc1bc95fad9eb7a
RUN set -eux; \
    \
    savedAptMark="$(apt-mark showmanual)"; \
    apt-get update; \
    apt-get install -y --no-install-recommends \
        gnupg dirmngr \
        wget ca-certificates \
    ; \
    \
    ddist() { \
        local f="$1"; shift; \
        local distFile="$1"; shift; \
        local mvnFile="${1:-}"; \
        local success=; \
        local distUrl=; \
        for distUrl in \
# https://issues.apache.org/jira/browse/INFRA-8753?focusedCommentId=14735394#comment-14735394
            "https://www.apache.org/dyn/closer.cgi?action=download&filename=$distFile" \
# if the version is outdated (or we're grabbing the .asc file), we might have to pull from the dist/archive :/
            "https://www-us.apache.org/dist/$distFile" \
            "https://www.apache.org/dist/$distFile" \
            "https://archive.apache.org/dist/$distFile" \
# if all else fails, let's try Maven (https://www.mail-archive.com/users@tomcat.apache.org/msg134940.html; https://mvnrepository.com/artifact/org.apache.tomcat/tomcat; https://repo1.maven.org/maven2/org/apache/tomcat/tomcat/)
            ${mvnFile:+"https://repo1.maven.org/maven2/org/apache/tomcat/tomcat/$mvnFile"} \
        ; do \
            if wget -O "$f" "$distUrl" && [ -s "$f" ]; then \
                success=1; \
                break; \
            fi; \
        done; \
        [ -n "$success" ]; \
    }; \
    \
    ddist 'tomcat.tar.gz' "tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz" "$TOMCAT_VERSION/tomcat-$TOMCAT_VERSION.tar.gz"; \
    echo "$TOMCAT_SHA512 *tomcat.tar.gz" | sha512sum --strict --check -; \
    ddist 'tomcat.tar.gz.asc' "tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc" "$TOMCAT_VERSION/tomcat-$TOMCAT_VERSION.tar.gz.asc"; \
    export GNUPGHOME="$(mktemp -d)"; \
    for key in $GPG_KEYS; do \
        gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
    done; \
    gpg --batch --verify tomcat.tar.gz.asc tomcat.tar.gz; \
    tar -xf tomcat.tar.gz --strip-components=1; \
    rm bin/*.bat; \
    rm tomcat.tar.gz*; \
    command -v gpgconf && gpgconf --kill all || :; \
    rm -rf "$GNUPGHOME"; \
    \
# https://tomcat.apache.org/tomcat-9.0-doc/security-howto.html#Default_web_applications
    mv webapps webapps.dist; \
    mkdir webapps; \
# we don't delete them completely because they're frankly a pain to get back for users who do want them, and they're generally tiny (~7MB)
    \
    nativeBuildDir="$(mktemp -d)"; \
    tar -xf bin/tomcat-native.tar.gz -C "$nativeBuildDir" --strip-components=1; \
    apt-get install -y --no-install-recommends \
        dpkg-dev \
        gcc \
        libapr1-dev \
        libssl-dev \
        make \
    ; \
    ( \
        export CATALINA_HOME="$PWD"; \
        cd "$nativeBuildDir/native"; \
        gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
        aprConfig="$(command -v apr-1-config)"; \
        ./configure \
            --build="$gnuArch" \
            --libdir="$TOMCAT_NATIVE_LIBDIR" \
            --prefix="$CATALINA_HOME" \
            --with-apr="$aprConfig" \
            --with-java-home="$JAVA_HOME" \
            --with-ssl=yes; \
        make -j "$(nproc)"; \
        make install; \
    ); \
    rm -rf "$nativeBuildDir"; \
    rm bin/tomcat-native.tar.gz; \
    \
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
    apt-mark auto '.*' > /dev/null; \
    [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \
    find "$TOMCAT_NATIVE_LIBDIR" -type f -executable -exec ldd '{}' ';' \
        | awk '/=>/ { print $(NF-1) }' \
        | sort -u \
        | xargs -r dpkg-query --search \
        | cut -d: -f1 \
        | sort -u \
        | xargs -r apt-mark manual \
    ; \
    apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
    rm -rf /var/lib/apt/lists/*; \
    \
# sh removes env vars it doesn't support (ones with periods)
# https://github.com/docker-library/tomcat/issues/77
    find ./bin/ -name '*.sh' -exec sed -ri 's|^#!/bin/sh$|#!/usr/bin/env bash|' '{}' +; \
    \
# fix permissions (especially for running as non-root)
# https://github.com/docker-library/tomcat/issues/35
    chmod -R +rX .; \
    chmod 777 logs temp work
# verify Tomcat Native is working properly
RUN set -e \
    && 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"]


这是tomcat的dockerfile, 我们分解来看看


FROM openjdk:11-jdk
FROM相当于java中的extends. 继承自父类. 也就是说, tomcat运行, 依赖于openjdk.
这就是为什么tomcat很大的原因, 因为他依赖其他镜像而存在. 


ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
这里是设置环境变量


EXPOSE 8080
设置tomcat对外暴露的端口号是8080


CMD ["catalina.sh", "run"]
执行命令, 启动并运行tomcat


2. 编写带有挂载目录的dockerfile


那么下面我们来写一个挂载目录的dockerfile


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


VLOUME["容器目录1", "容器目录2", "容器目录3"]


备注:


处于可移植和分享的考虑, 用-v /宿主机目录:/容器目录 这种方法不能够直接在Dockerfile中使用


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


所以, 这里只设置容器挂载目录, 与宿主机的对应目录, 自动生成, 可以试用docker inspect查看详情

 

我们可以参考着上面的tomcat来写


FROM centos
VOLUME ["/dataVolumeContainer1", "/dataVolumeContainer2", "/dataVolumeContainer3"]
CMD echo "finish.......success!!"
CMD /bin/bash


这是一个很简单的dockerfile, 依赖的父类镜像是centos, 启动的容器, 只做了一个目录挂载.  


这个dockerfile写好了以后, 是什么意思呢? 大致可以理解为一下的含义


docker run -it -v /HOST:/dataVolumeContainer1 -v /HOST:/dataVolumeContainer2 -v /HOST:/dataVolumeContainer3 镜像ID /bin/bash


只是, 上面没有定义宿主机挂载的目录.


3. build生成镜像


docker build -f dockerfile目录  -t 新的镜像名字 .


docker build -f /docker/dockerfile/dockerfile -t lxl/centos .


微信图片_20220513142434.png


就像洋葱一样,一层套一层.


4. 运行容器


查看镜像


docker images

微信图片_20220513142502.png


我们看到了刚刚生成的镜像. 这个镜像就是带有挂载目录的镜像. 我们可以通过运行容器查看挂载目录


docker run -it 5a8ecf996d8d


进来直接就可以看到挂载目录. 那么在容器和宿主机创建的目录, 都可以被共享


 

比如: 我们在/dataVolumeContainer1中创建一个文件

微信图片_20220513142534.png


5. 查看目录挂载


使用docker inspect查看宿主机中挂载目录


docker inspect 0dcff7fc2508


微信图片_20220513142602.png


我们可以看到, 在宿主机上生成了一个默认的挂载目录.  


进入第一个目录, 看看能否看到刚刚创建的container.txt文件


微信图片_20220513142633.png


确实是可以共享

 

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

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

二. 容器数据卷


2.1. 什么是容器数据卷?


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


2.2. 构建容器数据卷


以上一步新建的镜像lxl/centos为模板并运行容器dc01/dc02/dc03


他们已经具有容器卷/dataVolumeContainer1, /dataVolumeContainer2,


/dataVolumeContainer3

 

容器间传递共享数据--volumes-from


下面演示一下. 具体操作


1. 先启动一个父容器dc01, 在/dataVolumeContainer2中新增内容


docker run -it --name dc01 lxl/centos
上面我创建了一个带有挂载卷的镜像lxl/centos. 这里启动的就是这个镜像
--name 指定容器的名字是dc01, 如果不指定会默认生成一个


接下来我们来查看是否有挂载卷目录


微信图片_20220513142710.png微信图片_20220513142713.png


果然, 生来自带三个目录

 

现在,我们向目录1中写入文件

微信图片_20220513142737.png

2. dc2/dc3继承自dc1,  --volumes-from


  • 退出dc01容器, 但不要关闭, 使用命令


ctrl + p + q


  • 先创建dc02, 继承自dc01容器


docker run -it --name dc02 --volume-from dc01 lxl/centos
--volume-from : 继承自父类容器dc01的加载卷
使用的镜像依然是lxl/centos
--name : 给容器命名为dc02


查看dc02中是否能够看到刚刚在dc01中创建的文件dc01.txt


 微信图片_20220513142828.png

 


没问题, 我们确实能够看到dc01创建的文件

 

接下来, 我们在dc02创建一个文件


微信图片_20220513142844.png


  • 退出dc02 容器


ctrl + p + q


  • 进入dc01容器, 看看是否能够看到刚刚dc02创建的dc02.txt

     微信图片_20220513142917.png


我们确实看到了, 这说明, dc01 和 dc02 的数据卷是共享

 

  • 在创建一个dc03容器, 继承自dc01 ,方法和dc02的创建类


[root@localhost ~]# docker run -it --name dc03 --volumes-from dc01 lxl/centos
[root@8545291ec601 /]# 
[root@8545291ec601 /]# ls  
bin  dataVolumeContainer1  dataVolumeContainer2  dataVolumeContainer3  dev  etc  home  lib  lib64  lost+found  media  mnt  opt    proc  root  run  sbin  srv  sys  tmp  usr  var
[root@8545291ec601 /]# cd dataVolumeContainer1 
[root@8545291ec601 dataVolumeContainer1]# ls
dc01.txt  dc02.txt
[root@8545291ec601 dataVolumeContainer1]# touch dc03.txt
[root@8545291ec601 dataVolumeContainer1]# ls
dc01.txt  dc02.txt  dc03.txt


如上面命令, 我们在dc03容器中创建了dc03.txt, 查看dc01和dc02也是都可以看到的.

 

3. 问题1: 删除掉dc01, dc02和dc03的加载卷是否会被删除呢?


查询当前启动的容器, dc01, dc02, dc03 都是启动中的状态[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
8545291ec601        lxl/centos          "/bin/sh -c /bin/bash"   4 minutes ago       Up 4 minutes                            dc03
d1cdf1ba3148        lxl/centos          "/bin/sh -c /bin/bash"   12 minutes ago      Up 12 minutes                           dc02
52a9525a9598        lxl/centos          "/bin/sh -c /bin/bash"   20 minutes ago      Up 20 minutes                           dc01
0dcff7fc2508        5a8ecf996d8d        "/bin/sh -c /bin/bash"   22 hours ago        Up 22 hours                             objective_mcclintock
停止dc01容器, 我们知道dc02和dc03都是继承自dc01,那么dc01停止以后, dc02和dc03的数据卷还会共享么?[root@localhost ~]# docker stop 52a9525a9598
52a9525a9598
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
8545291ec601        lxl/centos          "/bin/sh -c /bin/bash"   4 minutes ago       Up 4 minutes                            dc03
d1cdf1ba3148        lxl/centos          "/bin/sh -c /bin/bash"   12 minutes ago      Up 12 minutes                           dc02
0dcff7fc2508        5a8ecf996d8d        "/bin/sh -c /bin/bash"   22 hours ago        Up 22 hours                             objective_mcclintock
[root@localhost ~]# 
[root@localhost ~]# 进入dc02容器, 我们发现,dc02容器依然拥有数据卷, 下面的文件也都存在, dc03也是如此
[root@localhost ~]# docker attach dc02
[root@d1cdf1ba3148 dataVolumeContainer1]# ls
dc01.txt  dc02.txt  dc03.txt
 
 dc03也是如此
  [root@localhost ~]# docker attach dc03
  [root@8545291ec601 dataVolumeContainer1]# ls
  dc01.txt  dc02.txt  dc03.txt


4. 问题2: 删掉dc01以后, dc03创建的文件,是否可以和dc02共享呢?


现在是在dc03容器里面, 数据卷里有3个文件, 然后创建一个新的文件dc03-2.txt[root@8545291ec601 dataVolumeContainer1]# ls
 dc01.txt  dc02.txt  dc03.txt
[root@8545291ec601 dataVolumeContainer1]# touch dc03-2.txt
[root@8545291ec601 dataVolumeContainer1]# ls
 dc01.txt  dc02.txt  dc03-2.txt    dc03.txt
[root@8545291ec601 dataVolumeContainer1]# [root@localhost ~]# 
[root@localhost ~]# 进入dc02容器, 查看dc02中是否可以看到刚刚dc03创建的文件. 我们发现,确实看到了
[root@localhost ~]# docker attach dc02
[root@d1cdf1ba3148 dataVolumeContainer1]# ls
 dc01.txt  dc02.txt  dc03-2.txt    dc03.txt


总结: 以上两个问题说明:容器之间信息的传递, 数据卷的生命周期一直持续到所有的容器生命周期全部结束


仔细想想原因是什么?


因为dc01, dc02, dc03他们都是挂载在宿主机上. 他们每一次数据的改动都会被同步到宿主机. 他们最终的文件内容是和宿主机保持一致的.

 

最后来回顾一下, dockerfile容器挂载的几个步骤


1. 编写dockerfile文件


2. build生成镜像


3. 启动容器


4. 查看挂载卷.


5. 容器间共享数据卷 --volumes-from

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3 )前置知识要求   课程大纲 第一章 了解数据仓库概念 初步了解数据仓库是干什么的 第二章 按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章 数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章 采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章 用户行为数据仓库 严格按照企业的标准开发 第六章 搭建业务数仓理论基础和对表的分类同步 第七章 业务数仓的搭建  业务行为数仓效果图  
相关文章
|
5天前
|
Kubernetes Cloud Native Docker
云原生时代的容器化实践:Docker和Kubernetes入门
【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术成为企业提升敏捷性和效率的关键。本篇文章将引导读者了解如何利用Docker进行容器化打包及部署,以及Kubernetes集群管理的基础操作,帮助初学者快速入门云原生的世界。通过实际案例分析,我们将深入探讨这些技术在现代IT架构中的应用与影响。
23 2
|
3天前
|
运维 Cloud Native 虚拟化
一文吃透云原生 Docker 容器,建议收藏!
本文深入解析云原生Docker容器技术,涵盖容器与Docker的概念、优势、架构设计及应用场景等,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
一文吃透云原生 Docker 容器,建议收藏!
|
4天前
|
缓存 监控 开发者
掌握Docker容器化技术:提升开发效率的利器
在现代软件开发中,Docker容器化技术成为提升开发效率和应用部署灵活性的重要工具。本文介绍Docker的基本概念,并分享Dockerfile最佳实践、容器网络配置、环境变量和秘密管理、容器监控与日志管理、Docker Compose以及CI/CD集成等技巧,帮助开发者更高效地利用Docker。
|
5天前
|
监控 持续交付 Docker
Docker 容器化部署在微服务架构中的应用有哪些?
Docker 容器化部署在微服务架构中的应用有哪些?
|
5天前
|
监控 持续交付 Docker
Docker容器化部署在微服务架构中的应用
Docker容器化部署在微服务架构中的应用
|
5天前
|
安全 持续交付 Docker
微服务架构和 Docker 容器化部署的优点是什么?
微服务架构和 Docker 容器化部署的优点是什么?
|
7天前
|
关系型数据库 数据管理 应用服务中间件
【赵渝强老师】Docker的数据持久化
在生产环境中使用Docker时,为了实现数据的持久化和共享,可以通过数据卷(Data Volumes)和数据卷容器(Data Volume Containers)两种方式来管理数据。数据卷是一个独立于容器的挂载目录,可以跨多个容器共享和重用。数据卷容器则是一种特殊容器,用于维护数据卷,便于数据迁移和共享。本文通过示例详细介绍了这两种方法的使用步骤。
|
7天前
|
NoSQL Redis Docker
【赵渝强老师】使用Docker Compose管理容器
Docker Compose 通过 YAML 文件管理多个容器,简化复杂系统的部署和管理。本文介绍了 Docker Compose 的基本概念,并通过一个包含 Redis DB 和 Python Web 模块的示例,展示了如何使用 Docker Compose 部署和管理多容器应用。手动部署和 Docker Compose 部署的对比突显了 Docker Compose 在系统复杂度增加时的优势。
|
2月前
|
Linux Docker 容器
Docker操作 :容器命令
Docker操作 (四)
|
1月前
|
安全 Shell Linux
docker进入容器命令
docker进入容器命令