Docker 容器(二)

Docker

  • 四、Docker容器数据卷
      • 1.数据卷的主要特点
      • 2.卷的共享与继承
        • (1)卷的共享(Sharing)
        • (2) 卷的继承(Inheritance)
      • 3.数据卷运行实例
  • 五、Dockerfile
    • 1.Dockerfile
    • 2. 创建一个名为 myubuntu的自定义镜像
        • 第 1 步:准备并编写 Dockerfile 文件
        • 第 2 步:构建镜像
        • 第 3 步:运行镜像
    • 3、什么是虚悬镜像?​

四、Docker容器数据卷

Docker 容器数据卷(Volume)​​ 是一种​​持久化数据​​和​​共享数据​​的机制,用于解决容器内数据生命周期的问题。它本质上是绕过容器联合文件系统(UnionFS)的​​一个特殊目录​​,可以存在于一个或多个容器中,但其数据直接存储在宿主机上或由外部服务管理。

1.数据卷的主要特点

  1. 数据持久化 (Persistence)
    • 卷中的数据是独立于容器生命周期的。即使容器被删除、重启或停止,卷中的数据依然安全地保留在宿主机上。一直到没有容器使用它为止。
    • 这是数据卷最核心的价值。
  2. 数据共享与复用 (Sharing & Reuse)
    • 一个数据卷可以同时被多个容器挂载和使用,是实现容器间数据共享的最佳方式。
    • 一个容器也可以挂载多个数据卷
  3. 高性能 (Performance)
    • 相对于容器内联合文件系统的写时复制(CoW)机制,直接对数据卷的读写性能更高,更接近原生文件系统I/O。
  4. 解耦应用与数据 (Decoupling)
    • 将动态变化的、需要持久化的数据(如数据库文件)与静态的应用环境(如已安装的程序)分离开,使容器更加轻量和专注于业务逻辑。

2.卷的共享与继承

(1)卷的共享(Sharing)

这是数据卷最直接和常用的功能。多个容器(无论是否同时运行)可以挂载同一个预先创建好的数据卷(通常是命名卷),从而实现数据的共同访问和交换。

工作机制
多个容器的挂载点(target)指向同一个卷源(source)。

操作示例:容器间共享数据

  1. 创建一个命名卷 (shared-data)

    docker volume create shared-data
    
  2. 启动第一个生产者容器 (producer),向共享卷写入数据

    docker run -it --name producer --mount source=shared-data,target=/data ubuntu bash
    

    在容器内执行:

    echo "Hello from Producer Container!" > /data/message.txt
    exit
    
  3. 启动第二个消费者容器 (consumer),从同一个共享卷读取数据

    docker run -it --name consumer --mount source=shared-data,target=/app ubuntu bash
    

    在容器内执行:

    cat /app/message.txt # 输出: Hello from Producer Container!
    
  4. 验证

  • 你可以在 consumer 容器中看到 producer 容器创建的文件。
  • consumer 中修改 /app/ 下的文件,producer 重新挂载后也能看到。
  • 即使这两个容器都停止了,shared-data 卷里的数据依然存在。
(2) 卷的继承(Inheritance)

卷的继承主要通过 --volumes-from 参数实现。它允许一个新容器自动继承另一个容器所挂载的所有数据卷,包括挂载点和权限。

重要提示--volumes-from 继承的是挂载规则,而不是复制数据。最终,继承的容器和被继承的容器会挂载到同一个物理卷上,因此它们操作的也是同一份数据,本质上也构成了一种共享。

操作示例:继承挂载规则

  1. 启动一个“数据卷容器” (data-container)
    这个容器本身可以不运行任何应用,它的唯一目的就是定义要挂载的卷。

    docker run -d --name data-container \-v /db-data \          # 定义一个匿名卷-v /config \           # 定义另一个匿名卷ubuntu sleep infinity  # 让它执行一个无害的长期命令
    
  2. 通过继承启动一个新容器 (app-container)

    docker run -d --name app-container \--volumes-from data-container \ # 关键参数:继承 data-container 的所有卷my-app-image
    

    此时,app-container 容器会自动拥有两个挂载点:/db-data/config,它们与 data-container 中的对应卷是同一个。

  3. 再启动一个容器也继承它 (backup-container)

    docker run -d --name backup-container \--volumes-from data-container \backup-image
    

    现在,data-containerapp-containerbackup-container 都共享着相同的 /db-data/config 卷。

3.数据卷运行实例

  1. ​​直接命令添加​​宿主机与容器的卷映射。
  2. 设置不同的​​读写规则​​(rw与 ro)。
  3. 实现容器间的​​卷的继承和共享​​。

场景模拟​​
我们创建两个容器:

  • 容器1 (container1)​​:作为一个数据生产者,与宿主机建立映射,并创建数据。
  • ​​容器2 (container2)​​:继承容器1的卷规则,作为数据消费者来读取数据。

步骤 1: 直接命令添加容器卷(宿主机 vs 容器映射)

我们使用 docker run -v命令直接创建映射。

语法-v <宿主机目录>:<容器目录>:<读写规则>

执行命令:创建容器1并完成映射

# 在宿主机上创建一个目录用于映射
sudo mkdir -p /docker_volume_example/data# 运行容器1,并建立映射关系
# -v /docker_volume_example/data:/data:rw 表示将宿主机的目录映射到容器的/data目录,读写规则为读写(默认)
docker run -itd \--name container1 \-v /docker_volume_example/data:/data:rw \ubuntu:22.04 \bash
  • -v /docker_volume_example/data:/data:rw:这就是图中的“直接命令添加”。
    • 宿主机目录/docker_volume_example/data
    • 容器目录/data
    • 读写规则rw(读写,为默认模式,可省略)

步骤 2: 读写规则映射添加说明

现在我们在容器1内进行操作,验证读写权限,并模拟数据生产。

进入容器1并写入数据:

# 进入容器1
docker exec -it container1 bash# 此时,我们已在容器1的内部Shell中
# 查看映射的目录
ls /data # 此时应该是空的,因为宿主机目录是空的# 向数据卷中写入一个文件,模拟生产数据
echo "This is important data created by Container1." > /data/data_from_container1.txt# 退出容器1
exit

在宿主机上验证数据共享:

# 检查宿主机映射目录,应该能看到容器1创建的文件
cat /docker_volume_example/data/data_from_container1.txt

输出结果This is important data created by Container1.

这证明了宿主机和容器1之间的数据是实时共享的。


步骤 3: 卷的继承和共享

现在,我们启动容器2,让它继承容器1的卷规则,实现数据共享。

执行命令:创建容器2并继承容器1的卷

# 使用 --volumes-from 参数继承容器1的所有卷映射规则
docker run -itd \--name container2 \--volumes-from container1 \ # 这是实现继承的关键!ubuntu:22.04 \bash

验证继承与共享:

# 进入容器2
docker exec -it container2 bash# 检查容器2的 /data 目录,应该能看到容器1创建的文件
ls /data
cat /data/data_from_container1.txt

输出结果This is important data created by Container1.

成功!容器2没有直接映射宿主机目录,但通过 --volumes-from继承了容器1的映射,因此也能访问到同一份数据。

测试只读(ro)规则:

假设我们想让容器2只能读,不能写,我们可以在继承时重新定义挂载的读写规则。

1. 先删除旧的容器2

docker stop container2
docker rm container2

2. 以只读模式重新运行容器2

# 注意命令中的 :ro
docker run -itd \--name container2 \--volumes-from container1 \ # 先继承-v /docker_volume_example/data:/app_data:ro \ # 再重新挂载并覆盖为只读规则ubuntu:22.04 \bash
  • 这里我们做了一个调整,将容器2的挂载点从 /data改到了 /app_data,并设置了 :ro(只读)。

3. 验证容器2的只读权限

docker exec -it container2 bash# 可以成功读取
cat /app_data/data_from_container1.txt# 尝试写入会报错:Read-only file system
echo "Try to write from Container2" > /app_data/data_from_container2.txt

输出结果bash: /app_data/data_from_container2.txt: Read-only file system

这证明了只读(ro)规则已生效,完美实现了“只读”的说明。

五、Dockerfile

1.Dockerfile

Dockerfile 是一个文本文件​​,里面包含了一系列的​​指令(Instruction)​​ 和​​参数​​。每一条指令都会在镜像上构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
它将基础镜像一步步变成自定义镜像。

一个典型的 Dockerfile 分为四部分:

  1. ​​基础镜像信息​​:使用 FROM指令指定从哪个镜像开始构建。
  2. ​​元数据信息​​:使用 LABEL、MAINTAINER等指令添加镜像的描述信息。
  3. ​​构建指令​​:运行命令、复制文件、设置环境变量等,按顺序逐步构建镜像层。
  4. ​​容器启动指令​​:指定镜像构建完成后,启动容器时默认要运行的命令。

Dockerfile 的常用保留字

指令功能描述
FROM指定基础镜像,必须是第一条指令。
LABEL为镜像添加元数据(键值对),如版本、描述等。替代旧的 MAINTAINER
RUN在镜像构建过程中执行命令,用于安装软件、下载依赖等。
COPY宿主机上的文件或目录复制到镜像中。
ADD类似 COPY,但功能更多(如自动解压 tar 包、支持 URL)。推荐优先使用 COPY
WORKDIR设置后续指令的工作目录(如果不存在则创建)。类似 cd
EXPOSE声明容器运行时监听的网络端口(只是一个说明,实际映射需用 -p)。
ENV设置环境变量,后续指令和容器运行时都可以使用。
ARG设置构建时的环境变量,镜像运行时不存在。用于动态传入参数。
VOLUME创建匿名数据卷挂载点,用于持久化数据。
USER指定后续指令以哪个用户身份运行(默认为 root)。
CMD指定容器启动时默认执行的命令。一个 Dockerfile 只能有一条 CMD
ENTRYPOINT指定容器启动时的主要命令,CMD的内容会成为其参数。

2. 创建一个名为 myubuntu的自定义镜像

体验从编写 Dockerfile 到构建,最后运行的完整流程

第 1 步:准备并编写 Dockerfile 文件
  1. 创建一个空目录 作为工作空间,并进入该目录。

    mkdir myubuntu-dockerfile
    cd myubuntu-dockerfile
    
  2. 创建 Dockerfile文件(注意:没有文件扩展名)。

    touch Dockerfile
    
  3. 编辑 Dockerfile文件,输入以下内容:

    # 指定基础镜像
    FROM ubuntu:22.04# 维护者信息(可选)
    LABEL maintainer="student@example.com"# 设置环境变量,防止apt安装时交互式提示
    ENV DEBIAN_FRONTEND=noninteractive# 构建指令:更新软件包列表并安装常用工具
    RUN apt-get update && \apt-get install -y \vim \net-tools \iputils-ping \curl \&& rm -rf /var/lib/apt/lists/* # 清理缓存以减小镜像体积# 设置容器启动时默认执行的命令
    CMD ["/bin/bash"]
    

    代码解释:

    • FROM ubuntu:22.04: 基于官方 Ubuntu 22.04 镜像开始构建。
    • LABEL: 添加镜像的元数据信息。
    • RUN: 这是核心步骤。它执行命令来安装我们需要的软件包。
      • apt-get update && apt-get install -y: 更新软件源并安装指定工具(vim-编辑器, net-tools-网络工具如ifconfig, iputils-ping-ping命令, curl-传输工具)。
      • && rm -rf /var/lib/apt/lists/*: 这是一个很好的实践,清理 apt 缓存,可以显著减小镜像体积。
    • CMD ["/bin/bash"]: 指定当容器启动时,默认进入 bashshell。

第 2 步:构建镜像

使用 docker build命令,根据编写好的 Dockerfile 构建镜像。

命令格式: docker build -t 新镜像名字:TAG .

Dockerfile所在的目录下,执行以下命令:

docker build -t myubuntu:1.0 .

命令解释:

  • docker build: 构建镜像的命令。
  • -t myubuntu:1.0: -t参数用于给新镜像命名和打标签。这里我们将镜像命名为 myubuntu,标签为 1.0
  • .: 这个点 .非常重要!它指定了 构建上下文(Build Context) 的路径,即当前目录。Docker 引擎会在这个路径下寻找 Dockerfile文件。

等待构建完成,会看到类似下面的输出,表示构建成功:

Successfully built xxxxxxxxxxxx
Successfully tagged myubuntu:1.0

验证镜像是否创建成功:

docker images

你应该能在列表中看到 myubuntu镜像。


第 3 步:运行镜像

使用 docker run命令来启动并进入我们新创建的容器。

命令格式: docker run -it 新镜像名字:TAG

执行以下命令:

docker run -it myubuntu:1.0

命令解释:

  • docker run: 运行容器的命令。
  • -it: 这是两个参数的组合。
    • -i(--interactive): 保持标准输入流(STDIN)打开。
    • -t(--tty): 分配一个伪终端(pseudo-TTY)。
    • 组合使用 -it可以让我们以交互模式进入容器,就像登录一台虚拟机一样。
  • myubuntu:1.0: 指定要运行的镜像名称和标签。

验证自定义功能:

命令执行后,你的终端提示符会发生变化,表示你已经进入了容器内部,形如:

root@a1b2c3d4e5f6:/#

现在,可以测试我们在 Dockerfile 中安装的工具是否可用:

# 测试 ping 命令
ping -c 4 github.com# 测试 ifconfig 命令(来自net-tools)
ifconfig# 测试 vim 编辑器
vim --version

退出容器:输入 exit即可退出容器并回到宿主机的命令行。

3、什么是虚悬镜像?​

虚悬镜像​​是指没有标签(TAG)、并且没有被任何容器引用的镜像。它在 Docker 的镜像列表中通常显示为 <none>:<none>

产生场景:

  1. 镜像构建过程中
    当你使用 docker build重新构建一个同名的镜像时,Docker 会为新的构建过程创建新的镜像层。构建成功后,它会给​​新生成的镜像​​打上你指定的标签(如 my-app:latest)。

    而​​旧版本的镜像​​就会失去这个标签,变成 :,即虚悬镜像。

  2. 删除镜像后​​
    如果你删除了一个镜像的​​某个标签​​,而这个镜像还有其他标签,那么它不会变成虚悬镜像。但如果你删除了它的​​最后一个标签​​,这个镜像本身就会变成虚悬镜像。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/95401.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/95401.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PCB基础细节--工艺篇

pcb基础细节&#xff08;工艺篇&#xff09; 1. 孔与焊盘2. PCB各层之间的作用3. 阻抗匹配 3.1. 什么是传输线&#xff1f;我们只看特性阻抗&#xff0c;时延以后再说。 在画原理图时&#xff0c;我们把电阻&#xff0c;电容&#xff0c;电感是抽象成一个点了。两边加一个电压&…

信创服务器总死机原因及解决办法

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01;最近有个项目使用信创的服务器&#xff0c;总是出现死机的情况&#xff0c;联系厂家检查了一下&#xff0c;说是沐创网卡固件较低造成的&#xff0c;让移除网卡或升级固件尝试一下。记得5月份按厂家的说法处理过一台&am…

03_网关ip和端口映射(路由器转发)操作和原理

网关ip和端口映射&#xff08;路由器转发&#xff09;操作和原理IP 与端口映射配置全指南&#xff1a;2 种方案搞定外网访问内网一、先搞懂&#xff1a;为什么需要 IP 与端口映射&#xff1f;二、方案一&#xff1a;路由器端口映射&#xff08;适合有公网 IP&#xff0c;长期稳…

「数据获取」《安徽建设统计年鉴》(2002-2007)(2004、2006缺失)(获取方式看绑定的资源)

01、数据简介《安徽建设统计年鉴》是一部全方位反映安徽省建设事业发展变迁的重要统计资料著作。该书系统收集并精心整理了 2006 年度安徽省城乡建设领域的核心统计数据&#xff0c;涵盖城乡建设固定资产投资、建筑业发展态势、城镇建设推进情况等多个关键方面&#xff0c;为政…

Python/JS/Go/Java同步学习(第一篇)格式化/隐藏参数一锅端 四语言输出流参数宇宙(附源码/截图/参数表/避坑指南/老板沉默术)

&#x1f91d; 免骂声明&#xff1a; 本文四语言输出流参数经本蜀黎实战整理&#xff0c;旨在提供快速参考指南&#x1f4dd;因各语言版本迭代及不同系统环境差异&#xff0c;偶尔可能出现整理不全面之处&#xff0c;实属正常✅欢迎理性交流补充&#xff0c;喷子勿喷——毕竟你…

人工智能助力流感疫苗选择:MIT 团队推出 VaxSeer 系统

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

使用 qmake 生成 Makefile,Makefile 转换为 Qt 的 .pro 文件

使用 qmake 生成 Makefile 的完整指南 qmake 是 Qt 提供的构建工具&#xff0c;用于从 .pro 项目文件生成 Makefile。以下是详细的使用方法&#xff1a; 基本使用方法 1. 从 .pro 文件生成 Makefile bash qmake -o Makefile your_project.pro2. 直接运行 qmake&#xff08;自动…

利用DeepSeek编写验证xlsx格式文件中是否启用sharedStrings.xml对读写效率影响python程序

让他分别用100*10000个单元格有100、1000、10000个不同的1-200字符长的大写英文字母字符串测试. 一开始DeepSeek没有找到启用sharedStrings.xml的写xlsx模块&#xff0c;我自己找了pyxlsbwriter的例子告诉他才改好的。 import os import time import random import string impo…

【C++框架#2】gflags 和 gtest 安装使用

spdlog 安装和使用 1. 概述 介绍&#xff1a;spdlog 是一个高性能、超快速、零配置的 C 日志库&#xff0c;它旨在提供简洁的 API 和丰富的功能&#xff0c;同时保持高性能的日志记录。它支持多种输出目标、格式化选项、线程安全以及异步日志记录。 github 链接&#xff1a;htt…

平衡掌控者-游戏数值战斗设计

一、有效生命值1、计算公式有效生命生命值/&#xff08;1-伤害减免率&#xff09;/&#xff08;1-闪避率&#xff09;2、前摇和后摇对数值来说&#xff0c;战斗由两大模块组成&#xff0c;一个是战斗公式生效前的战斗攻击流程&#xff0c;一个是战斗公式与自身流程。比如说&…

使用DataLoader加载本地数据 食物分类案例

目录 一.食物分类案例 1..整合训练集测试集文档 2.导入相关的库 3.设置图片数据的格式转换 3.数据处理 4.数据打包 5.定义卷积神经网络 6.创建模型 7.训练和测试方法定义 8.损失函数和优化器 9.训练模型&#xff0c;测试准确率 10.测试模型 之前我们DataLoader加载…

从零开始的python学习——函数(2)

ʕ • ᴥ • ʔ づ♡ど &#x1f389; 欢迎点赞支持&#x1f389; 个人主页&#xff1a;励志不掉头发的内向程序员&#xff1b; 专栏主页&#xff1a;python学习专栏&#xff1b; 文章目录 前言 一、变量作用域 二、函数执行过程 三、链式调用 四、嵌套调用 五、函数递归 六、…

RAG 的完整流程是怎么样的?

RAG&#xff08;检索增强生成&#xff09;的完整流程可分为5个核心阶段&#xff1a;数据准备&#xff1a;清洗文档、分块处理&#xff08;如PDF转文本切片&#xff09;&#xff1b;向量化&#xff1a;使用嵌入模型&#xff08;如BERT、BGE&#xff09;将文本转为向量&#xff1…

研发文档版本混乱的根本原因是什么,怎么办

研发文档版本混乱的根本原因通常包括缺乏统一的版本控制制度、团队协作不畅、文档管理工具使用不当以及项目需求频繁变化等因素。这些问题使得研发团队在日常工作中容易出现文档版本混乱的情况&#xff0c;导致信息的不一致性、沟通不畅以及开发进度的延误。为了解决这一问题&a…

ChartView的基本使用

Qt ChartView&#xff08;准确类名 QChartView&#xff09;是 Qt Charts 模块里最常用的图表显示控件。一句话概括&#xff1a;“它把 QChart 画出来&#xff0c;并自带缩放、平移、抗锯齿等交互能力”。QML ChartView 简介&#xff08;一句话先记住&#xff1a;ChartView 是 Q…

系统扩展策略

1、核心指导思想&#xff1a;扩展立方体 在讨论具体策略前&#xff0c;先了解著名的扩展立方体&#xff08;Scale Cube&#xff09;&#xff0c;它定义了三种扩展维度&#xff1a; X轴&#xff1a;水平复制&#xff08;克隆&#xff09; 策略&#xff1a;通过负载均衡器&#…

HBuilder X 4.76 开发微信小程序集成 uview-plus

简介 本文记录了在HBuilder中创建并配置uni-app项目的完整流程。 首先创建项目并测试运行&#xff0c;确认无报错后添加uView-Plus组件库。 随后修改了main.js、uni.scss、App.vue等核心文件&#xff0c;配置manifest.json并安装dayjs、clipboard等依赖库。 通过调整vite.c…

第4章:内存分析与堆转储

本章概述内存分析是 Java 应用性能调优的核心环节之一。本章将深入探讨如何使用 VisualVM 进行内存分析&#xff0c;包括堆内存监控、堆转储生成与分析、内存泄漏检测以及内存优化策略。通过本章的学习&#xff0c;你将掌握识别和解决内存相关问题的专业技能。学习目标理解 Jav…

面经分享一:分布式环境下的事务难题:理论边界、实现路径与选型逻辑

一、什么是分布式事务? 分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。 一个典型的例子就是跨行转账: 用户从银行A的账户向银行B的账户转账100元。 这个操作包含两个步骤: 从A账户扣减100元。 向B账户…

C++的演化历史

C是一门这样的编程语言&#xff1a; 兼顾底层计算机硬件系统和高层应用抽象机制从实际问题出发&#xff0c;注重零成本抽象、性能、可移植性、与C兼容语言特性和细节很多&#xff0c;学习成本较高&#xff0c;是一门让程序员很难敢说精通的语言 C是自由的&#xff0c;支持5种…