docker学习笔记volume的创建
Dockerfile指令VOLUME介绍
Dockerfile指令VOLUME介绍在介绍VOLUME指令之前,我们来看下如下场景需求:1)容器是基于镜像创建的,最后的容器⽂件系统包括镜像的只读层+可写层,容器中的进程操作的数据持久化都是保存在容器的可写层上。
⼀旦容器删除后,这些数据就没了,除⾮我们⼈⼯备份下来(或者基于容器创建新的镜像)。
能否可以让容器进程持久化的数据保存在主机上呢?这样即使容器删除了,数据还在。
2)当我们在开发⼀个web应⽤时,开发环境是在主机本地,但运⾏测试环境是放在docker容器上。
这样的话,我在主机上修改⽂件(如html,js等)后,需要再同步到容器中。
这显然⽐较⿇烦。
3)多个容器运⾏⼀组相关联的服务,如果他们要共享⼀些数据怎么办?对于这些问题,我们当然能想到各种解决⽅案。
⽽docker本⾝提供了⼀种机制,可以将主机上的某个⽬录与容器的某个⽬录(称为挂载点、或者叫卷)关联起来,容器上的挂载点下的内容就是主机的这个⽬录下的内容,这类似linux系统下mount的机制。
这样的话,我们修改主机上该⽬录的内容时,不需要同步容器,对容器来说是⽴即⽣效的。
挂载点可以让多个容器共享。
下⾯我们来介绍具体的机制。
⼀、通过docker run命令1、运⾏命令:docker run --name test -it -v /home/xqh/myimage:/data ubuntu /bin/bash其中的 -v 标记在容器中设置了⼀个挂载点 /data(就是容器中的⼀个⽬录),并将主机上的 /home/xqh/myimage ⽬录中的内容关联到 /data 下。
这样在容器中对/data⽬录下的操作,还是在主机上对/home/xqh/myimage的操作,都是完全实时同步的,因为这两个⽬录实际都是指向主机⽬录。
2、运⾏命令:docker run --name test1 -it -v /data ubuntu /bin/bash上⾯-v的标记只设置了容器的挂载点,并没有指定关联的主机⽬录。
docker学习笔记docker私有仓库搭建
Docker学习笔记——Docker私有仓库搭建和Mavan的管理一样,Dockers不仅提供了一个中央仓库,同时也允许我们使用registry搭建本地私有仓库。
使用私有仓库有许多优点:节省网络带宽,针对于每个镜像不用每个人都去中央仓库上面去下载,只需要从私有仓库中下载即可;提供镜像资源利用,针对于公司内部使用的镜像,推送到本地的私有仓库中,以供公司内部相关人员使用。
接下来我们就大致说一下如何在本地搭建私有仓库。
目前Docker Registry已经升级到了v2,最新版的Docker 已不再支持v1。
Registry v2使用Go语言编写,在性能和安全性上做了很多优化,重新设计了镜像的存储格式。
此文档是在v1的基础上写的,如果需要安装registry v2,只需下载registry:2.2即可,或者可以下载后面的安装脚本运行安装。
环境准备环境:两个装有Docker的Ubuntu虚拟机虚拟机一:192.168.112.132 用户开发机虚拟机二:192.168.112.136 用作私有仓库此处我们准备了两个虚拟机,分别都安装了Docker,其中132机器用作开发机,136机器用作registry私有仓库机器。
环境准备好之后接下来我们就开始搭建私有镜像仓库。
搭建私有仓库首先在136机器上下载registry镜像$ sudo docker pull registry下载完之后我们通过该镜像启动一个容器$ sudo docker run -d -p 5000:5000 registry默认情况下,会将仓库存放于容器内的/tmp/registry目录下,这样如果容器被删除,则存放于容器中的镜像也会丢失,所以我们一般情况下会指定本地一个目录挂载到容器内的/tmp/registry下,如下:$ sudo docker run -d -p 5000:5000 -v/opt/data/registry:/tmp/registry registry可以看到我们启动了一个容器,地址为:192.168.112.136:5000。
docker核心知识总结
docker核心知识总结容器与镜像容器:轻量级、独立的运行环境,包含应用程序及其依赖项,与底层操作系统隔离。
镜像:容器的静态模板,包含构建容器所需的指令和文件。
Docker架构Docker客户端:用户与Docker守护进程之间的接口。
Docker守护进程:在主机上管理容器创建、启动、停止和其他操作。
Docker注册表:存储和分发Docker镜像的中心仓库。
Docker命令docker build:根据Dockerfile构建镜像。
docker run:从镜像启动容器。
docker stop:停止容器。
docker start:启动容器。
docker ps:列出正在运行的容器。
docker images:列出本地镜像。
Docker网络容器网络:每个容器都有自己的网络命名空间,提供网络隔离。
Docker网络模式:指定容器如何与其他容器和主机网络交互,例如bridge模式或host模式。
Docker Compose:一个工具,用于定义和管理多容器应用程序。
Docker存储卷:用于在容器和主机之间共享数据。
Docker卷类型:bind挂载、volume挂载和tmpfs挂载。
Docker存储驱动程序:管理持久存储,例如overlay2和devicemapper。
Docker安全Docker镜像安全:扫描镜像是否存在漏洞和恶意软件。
Docker容器安全:配置容器设置(端口映射、卷权限)以增强安全性。
Docker注册表安全:使用安全凭据和加密机制保护注册表中的镜像。
Docker编排Docker Swarm:一个用于管理和编排Docker容器的工具。
Kubernetes:一个更高级的容器编排系统,提供服务发现、滚动更新和自动扩缩容。
Docker最佳实践使用多阶段构建:优化镜像大小和安全性。
创建可重复的Dockerfile:确保容器构建的可预测性。
使用卷:在容器和主机之间持久存储数据。
管理容器日志:启用日志记录并收集容器输出。
docker volume原理
docker volume原理
Volume是Docker容器技术的重要组成部分,它被用于存储应用程序的实体数据(比如文件、日志等),这些数据称为容器的持久数据,它们可在容器间共享、复制,甚至是在容器重启后也不丢失,这些特性使得volume 成为 Docker 容器部署应用程序时不可或缺的.
Volume 是 Docker 中一种高效的存储单元,用于存储和维护应用程序及其相关数据或配置文件。
它可以将存储从容器进程中独立出来,以方便在多个容器中统一管理。
在某种程度上,它看起来类似于宿主机上的文件,但有一个重要的区别是它是对宿主机文件系统的补充,而不是取代宿主机文件系统,因此即使宿主机的文件系统重新格式化,也可以保留 Volume 中的数据。
它的存储还可以分布在多台不同的机器上,实现跨机器的数据共享,从而让容器可以在不同机器上共享数据。
Volume 是 Docker 最重要的组成部分之一,它有以下几个主要特点:
1、Volume是一种持久化存储,当容器删除时,数据也不会丢失。
2、Volume通常被用于存储重要的数据和配置文件,可以在多个容器之下共享。
3、Volume可以跨多台机器共享,从而实现容器多机器之间的数据共享。
5、Volume可以跟踪容器里的写操作,从而保证数据永远不会被遗失。
6、Volume支持通过SELinux等安全机制确保安全性和隔离性。
7、Volume可以通过Rancher等第三方插件让容器更容易地与外界交互。
自己动手写Docker
目录分析
1.2 Go
1.1 Docker
1.3小结
2.1 Linux Namespace介绍
2.2 Linux Cgroups介绍
2.3 Union File System
2.4小结
3.1构造实现run命 令版本的容器
3.2增加容器资源限 制
3.3增加管道及环境 变量识别
3.4小结
4.1使用
自己动手写Docker
读书笔记模板
01 思维导图
03 读书笔记 05 作者介绍
目录
02 内容摘要 04 目录分析 06 精彩摘录
思维导图
本书关键字分析思维导图
了解
容器
环境变量
小结
实现
第章
语言
技术
结构
原理 网络
资源
理解
创建
限制
镜像
使用
技术
管道
内容摘要
内容摘要
通过讲解Docker使用到的各种底层技术,例如Namespace、Cgroups等来自己一步步动手完成一个简单版本 的Docker。在自己动手的过程中,从而对Docker这个技术有一个整体、细致的了解。能够明白Docker的原理以 及结构,从而加深对目前炽手可热的Docker技术的理解,方便解决工作中使用Docker遇到的各种问题。
读书笔记
读书笔记
了解容器原理的很好入门资料,也是对linux lernel关键概念namespace cgroup的很好实例模板。 非常推荐在没读本书以前,以为实现一个Docker Demo是一件很困难的事,到读下来以后,想去自己照着作 者代码写一遍,相信自己会有更深体会第二遍就开始写代码了,冲!。 学习原理的最好方式是自己动手实现。 本人实现:github/ForeverSRC/MyDocker。尤其是第6章的网络部分,实现过程中发现了众多bug,且未考 虑到容器删除后ip需要释放的逻辑。
k8s的volume类型
Kubernetes支持多种类型的V olume,用于存储和管理数据。
一些主要的V olume类型包括:
1. emptyDir:这是一个临时V olume,Pod被分配到Node时创建,且只在Pod生命周期内存在。
它无需指定宿主机上对应的目录文件,Kubernetes会自动分配一个目录。
emptyDir主要用于实现同pod上多个容器之间的数据传输。
2. hostPath:这是一个本地卷,可以将宿主机上的文件目录挂载到Pod中。
当你需要访问宿主机上Docker引擎内部数据时,可以定义hostPath的宿主机目录为docker数据存储目录,使容器内部应用可以直接访问docker的数据。
3. NFS、GlusterFS、Ceph等分布式文件系统:这些是Kubernetes 支持的持久化V olume类型,它们可以提供跨节点的数据存储和访问。
此外,还有其他的V olume类型,比如Flocker和Persistent V olume (PV)。
其中,PV分为不同的访问模式,包括ReadWriteOnce(RWO),ReadOnlyMany(ROX)和ReadWriteMany(RWX),它们分别对应不同的数据存储和访问需求。
以上信息仅供参考,如有需要,建议咨询相关领域的专家或查阅Kubernetes官方文档。
Docker容器创建与管理教程
Docker容器创建与管理教程Docker是一种开源的容器化平台,它提供了一种强大且轻量级的解决方案,用于创建、部署和管理应用程序的容器。
通过使用Docker,开发人员可以将应用程序及其所有相关组件打包到一个独立的、可移植的容器中,使其在任何环境下都能运行。
本教程将向您展示如何创建和管理Docker容器。
1. 安装Docker首先,您需要安装Docker。
请根据您的操作系统类型,下载适用于您的平台的Docker安装程序,并按照指示进行安装。
安装完成后,您可以在终端或命令提示符下运行`docker version`命令来验证是否成功安装了Docker。
2. 快速创建和运行Docker容器现在,让我们来快速创建和运行一个简单的Docker容器。
首先,我们需要创建一个Docker镜像。
Docker镜像是一个只读的模板,它包含了运行容器所需的所有文件和设置。
您可以使用`docker build`命令来从一个Dockerfile创建一个镜像。
例如,创建一个简单的Web应用程序镜像,您可以执行以下步骤:- 在项目根目录下创建一个名为`Dockerfile`的文件。
- 在Dockerfile中写入以下内容:```FROM nginx:latestCOPY . /usr/share/nginx/html```- 执行`docker build -t myapp .`命令来构建镜像。
`-t`参数用于给镜像命名,并使用`.`指定Dockerfile所在的路径。
一旦镜像创建完成,我们可以使用`docker run`命令来运行一个Docker容器。
例如,运行上面创建的myapp镜像,可以执行以下步骤:- 执行`docker run -d -p 80:80 myapp`命令来在后台运行一个容器,并将容器的80端口映射到主机的80端口。
`-d`参数用于以后台模式运行容器。
现在,您可以使用浏览器访问`http://localhost`来查看运行在Docker容器中的Web应用程序。
Docker容器的创建与管理教程
Docker容器的创建与管理教程随着云计算和虚拟化技术的快速发展,容器化技术如今已经成为了云原生应用开发和部署的重要组成部分。
Docker作为目前最流行的容器化平台,具有便捷、高效和灵活的特点,受到了越来越多开发者和企业的青睐。
本文将为大家介绍Docker容器的创建与管理教程,帮助读者全面了解和掌握Docker的基本操作。
一、Docker的安装与配置首先,我们需要在操作系统中安装Docker。
Docker官方提供了详细的安装教程,根据操作系统的不同,可选择合适的安装方式。
安装完成后,我们需要配置一些基本的Docker参数,如修改Docker镜像加速器、设置容器网络等。
这些配置可以通过修改Docker的配置文件或使用命令行参数来实现,具体方法可以参考Docker官方文档。
二、Docker镜像的获取与创建Docker镜像是Docker容器的基础,我们可以通过拉取已有的镜像或自行创建镜像来构建我们需要的容器。
首先,我们可以使用Docker Hub等镜像仓库来查找和拉取已有的镜像。
例如,我们可以通过运行`docker pull ubuntu:latest`命令来下载最新版的Ubuntu镜像。
如果我们需要创建自定义的镜像,我们可以通过编写Dockerfile来定义镜像的构建过程。
Dockerfile是一个文本文件,其中包含了一系列的指令,用于描述如何构建镜像。
例如,下面是一个简单的Dockerfile示例:```FROM ubuntu:latestRUN apt-get update && apt-get install -y python3COPY app.py /app.pyCMD ["python3", "/app.py"]```在这个Dockerfile中,我们首先指定了基础镜像为最新版的Ubuntu,然后使用apt-get命令安装了Python3,接着将当前目录下的app.py文件复制到镜像中,并最后指定了容器启动时要执行的命令。
Docker卷的使用方法和数据持久化实现
Docker卷的使用方法和数据持久化实现随着容器化技术的快速发展,Docker作为最受欢迎的容器平台之一,提供了许多用于数据管理的功能。
其中,Docker卷是一种重要工具,它可以帮助我们实现数据持久化,灵活管理和共享数据。
一、Docker卷的概念与作用Docker卷是一种特殊的文件类型,它在容器和主机之间建立了一个桥梁,用于持久化存储数据。
不同于容器内的文件系统,Docker卷的数据可以在不同的容器之间共享和重用,甚至可以在容器删除后仍然保留。
Docker卷的一个重要作用是帮助我们实现数据持久化。
在传统的容器使用中,当容器终止后,容器内生成的数据也会一同消失。
而使用Docker卷后,我们可以将数据存储到卷中,使数据得以长期保存,方便后续使用和管理。
二、Docker卷的创建和使用要创建一个Docker卷,我们可以使用docker volume create命令。
例如,我们可以执行以下命令来创建一个名为myvolume的卷:```bashdocker volume create myvolume```创建成功后,我们可以通过docker volume ls命令查看已创建的卷列表:```bashdocker volume ls```接下来,我们可以将卷挂载到容器中并开始使用。
假设我们有一个名为webapp的容器,我们可以通过以下命令将myvolume卷挂载到容器的特定路径(例如/var/www):```bashdocker run -d -v myvolume:/var/www webapp```这样,容器中的/var/www目录就和myvolume卷关联起来了。
我们可以在容器内部读写这个目录,数据将会被自动保存到myvolume卷中。
三、Docker卷的数据备份和恢复对于经常需要进行数据备份和恢复的场景,Docker卷同样提供了便利的方法。
我们可以使用docker cp命令将卷中的数据复制到主机上,以实现备份功能。
docker创建流程
docker创建流程Docker创建流程概述在本文中,我们将详细介绍使用Docker创建容器的流程。
Docker 是一个开源的容器化平台,能够帮助开发者轻松部署、打包和运行应用程序。
通过使用Docker,我们可以更加高效地管理和运行软件。
安装Docker1.在操作系统上安装Docker引擎。
Docker支持多个操作系统平台,如Linux、Windows和Mac等。
根据自己的操作系统类型下载并安装Docker。
创建Docker镜像1.编写Dockerfile。
Dockerfile是一个文本文件,其中包含了一系列用于构建Docker镜像的指令。
2.使用Dockerfile构建镜像。
在命令行中执行docker build命令,指定Dockerfile的路径和一个可选的镜像名称。
Docker将执行Dockerfile中的指令,逐步构建镜像。
3.验证镜像是否构建成功。
执行docker images命令,查看本地的Docker镜像列表。
确认目标镜像是否在列表中。
运行Docker容器1.通过镜像创建容器。
使用docker run命令,指定要使用的镜像名称和容器的名称等可选参数。
Docker将创建一个新的容器,并在其中运行指定的镜像。
2.验证容器是否成功创建。
执行docker ps命令,查看正在运行的容器列表。
确保目标容器在列表中显示为正在运行状态。
进入容器1.使用docker exec命令进入容器。
在命令行中执行dockerexec -it <容器名称或ID> /bin/bash命令,将会进入指定容器的交互式终端。
2.在容器中执行命令。
一旦进入容器,您可以在其中执行各种命令,比如安装软件、配置环境等等。
停止和删除容器1.停止容器。
执行docker stop <容器名称或ID>命令,Docker将停止运行指定的容器。
2.删除容器。
执行docker rm <容器名称或ID>命令,Docker将删除指定的容器。
Docker 存储之卷(Volume)
(1)Docker 安装及基本用法(2)Docker 镜像(3)Docker 容器的隔离性- 使用Linux namespace 隔离容器的运行环境(4)Docker 容器的隔离性- 使用cgroups 限制容器使用的资源(5)Docker 网络(6)若干企业生产环境中的容器网络方案(7)Docker 存储 - AUFS(8)Docker 存储- Volume1. Docker volume 的几种形态有状态容器都有数据持久化需求。
前一篇文章中提到过,Docker 采用AFUS 分层文件系统时,文件系统的改动都是发生在最上面的容器层。
在容器的生命周期内,它是持续的,包括容器在被停止后。
但是,当容器被删除后,该数据层也随之被删除了。
因此,Docker 采用volume (卷)的形式来向容器提供持久化存储。
Docker volume 有如下几种形态。
1.1 无- 不使用Docker volume默认情况下,容器不使用任何volume,此时,容器的数据被保存在容器之内,它只在容器的生命周期内存在,会随着容器的被删除而被删除。
当然,也可以使用docker commit 命令将它持久化为一个新的镜像。
1.2 Data volume (数据卷)一个data volume 是容器中绕过Union 文件系统的一个特定的目录。
它被设计用来保存数据,而不管容器的生命周期。
因此,当你删除一个容器时,Docker 肯定不会自动地删除一个volume。
有如下几种方式来使用data volume:(1)使用“-v 容器内目录”形式docker run -d -P --name web -v /webapp training/webapp python app.py使用docker inspect 命令可以看出,Docker 将本地一个_data 目录mount 为容器内的webapp 目录了:"Mounts": [{"Name":"f143b7f379fb6d012a08656fc950bf6df4bf5a5b90c72f310644aa997620122b", "Source":"/var/lib/docker/volumes/f143b7f379fb6d012a08656fc950bf6df4bf5a5b90c7 2f310644aa997620122b/_data","Destination": "/webapp","Driver": "local","Mode": "","RW": true,"Propagation": ""}],其实,在web 容器被删除后,/var/lib/docker/volumes/f143b7f379fb6d012a08656fc950bf6df4bf5a5b90c72f310644a a997620122b/_data 目录及其中的内容都还会保留下来,但是,新启动的容器无法再使用这个目录,也就是说,已有的数据不能自动地被重复使用了。
docker从零开始存储(二)volumes挂载
docker从零开始存储(⼆)volumes挂载使⽤volumes卷是保存Docker容器⽣成和使⽤的数据的⾸选机制。
mount binds依赖于主机的⽬录结构,⽽卷完全由Docker管理。
卷绑定安装有⼏个优点:与绑定装⼊相⽐,卷更易于备份或迁移。
您可以使⽤Docker CLI命令或Docker API管理卷。
卷适⽤于Linux和Windows容器。
可以在多个容器之间更安全地共享卷。
卷驱动程序允许您在远程主机或云提供程序上存储卷,加密卷的内容或添加其他功能。
新卷可以通过容器预先填充其内容。
此外,卷通常是⽤在容器的可写层中持久数据更好的选择,因为卷不会增加使⽤它的容器的⼤⼩,并且卷的内容存在于给定容器的⽣命周期之外。
如果容器⽣成⾮持久状态数据,请考虑使⽤ mpfs挂载以避免将数据永久存储在任何位置,并通过避免写⼊容器的可写层来提⾼容器的性能。
卷使⽤rprivate绑定传播,并且卷不可配置绑定传播。
选择-v或--mount标志最初,-v或者--volume标志⽤于独⽴容器,--mount标志⽤于群集服务。
但是,从Docker 17.06开始,您还可以使⽤--mount挂载独⽴容器。
⼀般来说,--mount更明确和冗长。
最⼤的区别在于-v语法将所有选项组合在⼀个字段中,⽽--mount语法将它们分开。
以下是每个标志的语法⽐较。
新⽤户应该尝试--mount⽐--volume语法更简单的语法。
如果需要指定卷驱动程序选项,则必须使⽤--mount。
-v或--volume:由三个字段组成,⽤冒号字符(:)分隔。
字段必须按正确的顺序排列,并且每个字段的含义不是很明显。
对于命名卷,第⼀个字段是卷的名称,并且在给定主机上是唯⼀的。
对于匿名卷,省略第⼀个字段。
第⼆个字段是⽂件或⽬录在容器中安装的路径。
第三个字段是可选的,是逗号分隔的选项列表,例如ro。
这些选项将在下⾯讨论。
--mount:由多个键值对组成,以逗号分隔,每个键<key>=<value>组由⼀个元组组成。
Dockervolume使用详解及实例
Dockervolume使⽤详解及实例Docker volume使⽤⼀个数据卷是⼀个特别指定的⽬录,该⽬录利⽤容器的UFS⽂件系统可以为容器提供⼀些稳定的特性或者数据共享。
数据卷可以在多个容器之间共享。
创建数据卷,只要在docker run命令后⾯跟上-v参数即可创建⼀个数据卷,当然你也可以跟多个-v参数来创建多个数据卷,当创建好带有数据卷的容器后,你就可以在其他容器中通过--volumes-froms参数来挂载该数据卷了,⽽不管该容器是否运⾏。
你也可以在Dockerfile中通过VOLUME指令来增加⼀个或者多个数据卷。
如果你有⼀些数据想在多个容器间共享,或者想在⼀些临时性的容器中使⽤该数据,那么最好的⽅案就是你创建⼀个数据卷容器,然后从该临时性的容器中挂载该数据卷容器的数据。
例如如下操作:#启动⼀个Volume_Container容器,包含两个数据卷docker run -v /var/volume1 -v /var/volume2 -name Volume_Container ubuntu14.04 linux_command#创建App_Container容器,挂载Volume_Container容器中的数据卷docker run -t -i -rm -volumes-from Volume_Container -name App_Container ubuntu14.04 linux_command#或者再创建⼀个容器,挂载App_Container中从Volume_Container挂载的数据卷docker run -t -i -rm -volumes-from App_Container -name LastApp_Container ubuntu14.04 linux_command1 在⼀个终端内创建数据卷容器,并在数据卷⽬录内写⼊测试⽂件2 另打开⼀个容器,挂载上⼀个数据卷容器的数据卷,查看测试⽂件即使你删除了刚开始的第⼀个数据卷容器或者中间层的数据卷容器,只要有其他容器使⽤数据卷,数据卷都不会被删除的。
docker-compose-volumes的说明
查看具体的volume对应的真实地址
$ docker volume inspect vagrant_mysql
[
{
"Name": "vagrant_mysql", "Driver": "local", "Mountpoint": "/var/lib/docker/volumes/vagrant_mysql/_data"
- ./ghost/config.js:/var/lib/ghost/config.js
卷标的 services: mysql:
image: mysql container_name: mysql volumes:
- mysql:/var/lib/mysql ... volumes: mysql:
第一种情况路径直接挂载到本地,比较直观,但需要管理本地的路径,而第二种使用卷标的方式,比较简洁,但你不知道数据存在本地什么位置,下面说明如何 查看docker的卷标
}
]
博客园 用户登录 代码改变世界 密码登录 短信登录 忘记登录用户名 忘记密码 记住我 登录 第三方登录/注册 没有账户, 立即注册
docker-compose-volumes的 说 明
◆ docker-compose里两种设置方式都是可以持久化的
绝对路径的
ghost:
image: ghost
volumes:
容器编排系统K8s之Volume的基础使用
容器编排系统K8s之Volume的基础使⽤ 在说k8s上的volume的使⽤前,我们先来回顾下docker⾥的volume;对于docker容器来说,镜像是分成构建的且每⼀层都是只读的,只读就意味着不能修改数据;只有当⼀个镜像运⾏为容器以后,在镜像的最顶端才会加上⼀个可写层,⼀旦这个容器被删除,对应可写层上的数据也随之被删除;为了解决docker容器上的数据持久化的问题;docker 使⽤了volume;在docker上volume有两种管理⽅式,第⼀种是⽤户⼿动指定把宿主机(对于宿主机上的⽬录可能是挂载存储系统上的某⽬录)上的某个⽬录挂载到容器某个⽬录,这种管理⽅式叫做绑定挂载卷;还有⼀种就是docker⾃⾝维护把某个⽬录挂载到容器某个⽬录,这种叫docker⾃⼰管理的卷;不管使⽤那种⽅式管理的volume,它都是容器直接关联宿主机上的某个⽬录或⽂件;docker中的volume解决了容器⽣命周期内产⽣的数据在容器终⽌后能够持久化保存的问题;同样k8s也有同样的烦恼,不同的是k8s⾯对的是pod;我们知道pod是k8s上最⼩调度单元,⼀个pod被删除以后,pod⾥运⾏的容器也随之被删除,那么pod⾥容器产⽣的数据该如何被持久化呢?要想解决这个问题,我们先来看看pod的组成; 提⽰:在k8s上pod⾥可以运⾏⼀个或多个容器,运⾏多个容器,其中⼀个容器我们叫主容器,其他的容器是⽤来辅助主容器,我们叫做sidecar;对于pod来说,不管⾥⾯运⾏多少个容器,在最底层都会运⾏⼀个pause容器,该容器最主要⽤来为pod提供基础架构⽀撑;并且位于同⼀个pod中的容器都共享pause容器的⽹络名称空间以及IPC和UTS;这样⼀来我们要想给pod⾥的容器提供存储卷,⾸先要把存储卷关联到pause容器,然后在容器⾥挂载pause⾥的存储卷即可;如下图所⽰ 提⽰:如上图所⽰,对于pause容器来说它可以关联存储A,也可以关联存储B;对于pause关联某个存储,其位于同⼀pod中的其他容器就也可以挂载pause⾥关联的存储⽬录或⽂件;对于k8s来说存储本来就不属于k8s内部组件,它是⼀个外来系统,这也意味着我们要想k8s使⽤外部存储系统,⾸先pause容器要有适配其对应存储系统的驱动;我们知道同⼀宿主机上运⾏的多个容器都是共享同⼀内核,即宿主机内核上有某个存储系统的驱动,那么pause就可以使⽤对应的驱动去适配对应的存储; volumes类型 我们知道要想在k8s上使⽤存储卷,我们需要在对应的节点上提供对应存储系统的驱动,对应运⾏在该节点上的所有pod就可以使⽤对应的存储系统,那么问题来了,pod怎么使⽤对应的存储系统呢?该怎么向其驱动程序传递参数呢?我们知道在k8s上⼀切皆对象,要在k8s上使⽤存储卷,我们还需要把对应的驱动抽象成k8s上的资源;在使⽤时,我们直接初始化对应的资源为对象即可;为了在k8s上简化使⽤存储卷的复杂度,k8s内置了⼀些存储接⼝,对于不同类型的存储,其使⽤的接⼝、传递的参数也有所不同;除此之外在k8s上也⽀持⽤户使⽤⾃定义存储,通过csi接⼝来定义; 查看k8s上⽀持的volumes接⼝[root@master01 ~]# kubectl explain pod.spec.volumesKIND: PodVERSION: v1RESOURCE: volumes <[]Object>DESCRIPTION:List of volumes that can be mounted by containers belonging to the pod.More info: https://kubernetes.io/docs/concepts/storage/volumesVolume represents a named volume in a pod that may be accessed by anycontainer in the pod.FIELDS:awsElasticBlockStore <Object>AWSElasticBlockStore represents an AWS Disk resource that is attached to akubelet's host machine and then exposed to the pod. More info:https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstoreazureDisk <Object>AzureDisk represents an Azure Data Disk mount on the host and bind mount tothe pod.azureFile <Object>AzureFile represents an Azure File Service mount on the host and bind mountto the pod.cephfs <Object>CephFS represents a Ceph FS mount on the host that shares a pod's lifetimecinder <Object>Cinder represents a cinder volume attached and mounted on kubelets hostmachine. More info: https://examples.k8s.io/mysql-cinder-pd/README.mdconfigMap <Object>ConfigMap represents a configMap that should populate this volumecsi <Object>CSI (Container Storage Interface) represents ephemeral storage that ishandled by certain external CSI drivers (Beta feature).downwardAPI <Object>DownwardAPI represents downward API about the pod that should populate thisvolumeemptyDir <Object>EmptyDir represents a temporary directory that shares a pod's lifetime.More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydirephemeral <Object>Ephemeral represents a volume that is handled by a cluster storage driver(Alpha feature). The volume's lifecycle is tied to the pod that defines it- it will be created before the pod starts, and deleted when the pod isremoved.Use this if: a) the volume is only needed while the pod runs, b) featuresof normal volumes like restoring from snapshot or capacity tracking areneeded, c) the storage driver is specified through a storage class, and d)the storage driver supports dynamic volume provisioning through aPersistentVolumeClaim (see EphemeralVolumeSource for more information onthe connection between this volume type and PersistentVolumeClaim).Use PersistentVolumeClaim or one of the vendor-specific APIs for volumesthat persist for longer than the lifecycle of an individual pod.Use CSI for light-weight local ephemeral volumes if the CSI driver is meantto be used that way - see the documentation of the driver for moreinformation.A pod can use both types of ephemeral volumes and persistent volumes at thesame time.fc <Object>FC represents a Fibre Channel resource that is attached to a kubelet's hostmachine and then exposed to the pod.flexVolume <Object>FlexVolume represents a generic volume resource that isprovisioned/attached using an exec based plugin.flocker <Object>Flocker represents a Flocker volume attached to a kubelet's host machine.This depends on the Flocker control service being runninggcePersistentDisk <Object>GCEPersistentDisk represents a GCE Disk resource that is attached to akubelet's host machine and then exposed to the pod. More info:https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdiskgitRepo <Object>GitRepo represents a git repository at a particular revision. DEPRECATED:GitRepo is deprecated. To provision a container with a git repo, mount anEmptyDir into an InitContainer that clones the repo using git, then mountthe EmptyDir into the Pod's container.glusterfs <Object>Glusterfs represents a Glusterfs mount on the host that shares a pod'slifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.mdhostPath <Object>HostPath represents a pre-existing file or directory on the host machinethat is directly exposed to the container. This is generally used forsystem agents or other privileged things that are allowed to see the hostmachine. Most containers will NOT need this. More info:https://kubernetes.io/docs/concepts/storage/volumes#hostpathiscsi <Object>ISCSI represents an ISCSI Disk resource that is attached to a kubelet'shost machine and then exposed to the pod. More info:https://examples.k8s.io/volumes/iscsi/README.mdname <string> -required-Volume's name. Must be a DNS_LABEL and unique within the pod. More info:https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#namesnfs <Object>NFS represents an NFS mount on the host that shares a pod's lifetime Moreinfo: https://kubernetes.io/docs/concepts/storage/volumes#nfspersistentVolumeClaim <Object>PersistentVolumeClaimVolumeSource represents a reference to aPersistentVolumeClaim in the same namespace. More info:https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaimsphotonPersistentDisk <Object>PhotonPersistentDisk represents a PhotonController persistent disk attachedand mounted on kubelets host machineportworxVolume <Object>PortworxVolume represents a portworx volume attached and mounted onkubelets host machineprojected <Object>Items for all in one resources secrets, configmaps, and downward APIquobyte <Object>Quobyte represents a Quobyte mount on the host that shares a pod's lifetimerbd <Object>RBD represents a Rados Block Device mount on the host that shares a pod'slifetime. More info: https://examples.k8s.io/volumes/rbd/README.mdscaleIO <Object>ScaleIO represents a ScaleIO persistent volume attached and mounted onKubernetes nodes.secret <Object>Secret represents a secret that should populate this volume. More info:https://kubernetes.io/docs/concepts/storage/volumes#secretstorageos <Object>StorageOS represents a StorageOS volume attached and mounted on Kubernetesnodes.vsphereVolume <Object>VsphereVolume represents a vSphere volume attached and mounted on kubeletshost machine[root@master01 ~]# 提⽰:从上⾯的帮助信息可以看到k8s上⽀持的存储接⼝还是很多,每⼀个存储接⼝都是⼀种类型;对于这些存储类型我们⼤致可以分为云存储,分布式存储,⽹络存储、临时存储,节点本地存储,特殊类型存储、⽤户⾃定义存储等等;⽐如awsElasticBlockStore、azureDisk、azureFile、gcePersistentDisk、vshperVolume、cinder这些类型划分为云存储;cephfs、glusterfs、rbd这些划分为分布式存储;nfs、iscsi、fc这些划分为⽹络存储;enptyDIR划分为临时存储;hostPath、local划分为本地存储;⾃定义存储csi;特殊存储configMap、secret、downwardAPId;持久卷申请persistentVolumeClaim等等; volumes的使⽤ ⽰例:创建使⽤hostPath类型存储卷Pod[root@master01 ~]# cat hostPath-demo.yamlapiVersion: v1kind: Podmetadata:name: vol-hostpath-demonamespace: defaultspec:containers:- name: nginximage: nginx:1.14-alpinevolumeMounts:- name: webhtmlmountPath: /usr/share/nginx/htmlreadOnly: truevolumes:- name: webhtmlhostPath:path: /vol/html/type: DirectoryOrCreate[root@master01 ~]# 提⽰:以上配置清单表⽰创建⼀个名为nginx的pod,对应使⽤nginx:1.14-alpine的镜像;并且定义了⼀个存储卷,该存储卷的名称为webhtml,其类型为hostPath;在定义存储卷时,我们需要在spec字段下使⽤volumes字段来指定,该字段的值为⼀个对象列表;其中name是必须字段,⽤于指定存储卷的名称,⽅便容器挂载其存储卷时引⽤的标识符;其次我们需要对应的存储卷类型来表⽰使⽤对应的存储接⼝;hostPath表⽰使⽤hostPath类型存储接⼝;该类型存储接⼝需要我们⼿动传递两个参数,第⼀个是path指定宿主机的某个⽬录或⽂件路径;type⽤来指定当宿主机上的指定的路径不存在时该怎么办,这个值有7个值;其中DirectoryOrCteate表⽰对应path字段指定的⽂件必须是⼀个⽬录,当这个⽬录在宿主机上不存在时就创建;Directory表⽰对应path字段指定的⽂件必须是⼀个已存在的⽬录;FileOrCreate表⽰对应path字段指定的⽂件必须是⼀个⽂件,如果⽂件不存在就创建;File表⽰对应path字段必须为⼀个已存在的⽂件;Socket表⽰对应path必须为⼀个已存在的Socket⽂件;CharDevice表⽰对应path字段指定的⽂件必须是⼀个已存在的字符设备;BlockDevice表⽰对应path字段指定的是⼀个已存在的块设备;定义volumes相当于把外部存储关联到对应pod的pause容器,⾄于pod⾥的其他容器是否要使⽤,怎么使⽤,取决于volumeMounts字段是否定义;spec.containers.volumeMounts字段⽤于指定对应pod⾥的容器存储卷挂载配置,其中name和mountPath是必选字段,name字段⽤于指定引⽤的存储卷名称;mountPath字段⽤于指定在容器内部的挂载点,readOnly⽤于指定是否为只读,默认是读写,即readOnly的值为false; 应⽤配置清单[root@master01 ~]# kubectl apply -f hostPath-demo.yamlpod/vol-hostpath-demo created[root@master01 ~]# kubectl get podNAME READY STATUS RESTARTS AGEmyapp-6479b786f5-9d4mh 1/1 Running 1 47hmyapp-6479b786f5-k252c 1/1 Running 1 47hvol-hostpath-demo 1/1 Running 0 11s[root@master01 ~]# kubectl describe pod/vol-hostpath-demoName: vol-hostpath-demoNamespace: defaultPriority: 0Node: /192.168.0.46Start Time: Wed, 23 Dec 2020 23:14:35 +0800Labels: <none>Annotations: <none>Status: RunningIP: 10.244.3.92IPs:IP: 10.244.3.92Containers:nginx:Container ID: docker://eb8666714b8697457ce2a88271a4615f836873b4729b6a0938776e3d527c6536Image: nginx:1.14-alpineImage ID: docker-pullable://nginx@sha256:485b610fefec7ff6c463ced9623314a04ed67e3945b9c08d7e53a47f6d108dc7Port: <none>Host Port: <none>State: RunningStarted: Wed, 23 Dec 2020 23:14:37 +0800Ready: TrueRestart Count: 0Environment: <none>Mounts:/usr/share/nginx/html from webhtml (ro)/var/run/secrets/kubernetes.io/serviceaccount from default-token-xvd4c (ro)Conditions:Type StatusInitialized TrueReady TrueContainersReady TruePodScheduled TrueVolumes:webhtml:Type: HostPath (bare host directory volume)Path: /vol/html/HostPathType: DirectoryOrCreatedefault-token-xvd4c:Type: Secret (a volume populated by a Secret)SecretName: default-token-xvd4cOptional: falseQoS Class: BestEffortNode-Selectors: <none>Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300sEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 43s default-scheduler Successfully assigned default/vol-hostpath-demo to Normal Pulled 42s kubelet Container image "nginx:1.14-alpine" already present on machineNormal Created 41s kubelet Created container nginxNormal Started 41s kubelet Started container nginx[root@master01 ~]# 提⽰:可以看到对应pod⾥以只读⽅式挂载了webhtml存储卷,对应webhtm存储卷类型为HostPath,对应path是/vol/html/; 查看对应pod所在节点[root@master01 ~]# kubectl get pod vol-hostpath-demo -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESvol-hostpath-demo 1/1 Running 0 3m39s 10.244.3.92 <none> <none>[root@master01 ~]# 在node03上查看对应⽬录是否创建?[root@node03 ~]# ll /total 16lrwxrwxrwx. 1 root root 7 Sep 15 20:33 bin -> usr/bindr-xr-xr-x. 5 root root 4096 Sep 15 20:39 bootdrwxr-xr-x 20 root root 3180 Dec 23 23:10 devdrwxr-xr-x. 80 root root 8192 Dec 23 23:10 etcdrwxr-xr-x. 2 root root 6 Nov 5 2016 homelrwxrwxrwx. 1 root root 7 Sep 15 20:33 lib -> usr/liblrwxrwxrwx. 1 root root 9 Sep 15 20:33 lib64 -> usr/lib64drwxr-xr-x. 2 root root 6 Nov 5 2016 mediadrwxr-xr-x. 2 root root 6 Nov 5 2016 mntdrwxr-xr-x. 4 root root 35 Dec 8 14:25 optdr-xr-xr-x 141 root root 0 Dec 23 23:09 procdr-xr-x---. 4 root root 213 Dec 21 22:46 rootdrwxr-xr-x 26 root root 780 Dec 23 23:13 runlrwxrwxrwx. 1 root root 8 Sep 15 20:33 sbin -> usr/sbindrwxr-xr-x. 2 root root 6 Nov 5 2016 srvdr-xr-xr-x 13 root root 0 Dec 23 23:09 sysdrwxrwxrwt. 9 root root 251 Dec 23 23:11 tmpdrwxr-xr-x. 13 root root 155 Sep 15 20:33 usrdrwxr-xr-x. 19 root root 267 Sep 15 20:38 vardrwxr-xr-x 3 root root 18 Dec 23 23:14 vol[root@node03 ~]# ll /voltotal 0drwxr-xr-x 2 root root 6 Dec 23 23:14 html[root@node03 ~]# ll /vol/html/total 0[root@node03 ~]# 提⽰:可以看到对应节点上已经创建/vol/html/⽬录,对应⽬录下没有任何⽂件; 在对应节点对应⽬录下创建⼀个⽹页⽂件,访问对应pod看看是否对应⽹页⽂件是否能够被访问到?[root@node03 ~]# echo "this is test page from node03 /vol/html/test.html" > /vol/html/test.html[root@node03 ~]# cat /vol/html/test.htmlthis is test page from node03 /vol/html/test.html[root@node03 ~]# exitlogoutConnection to node03 closed.[root@master01 ~]# kubectl get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESmyapp-6479b786f5-9d4mh 1/1 Running 1 47h 10.244.2.99 <none> <none>myapp-6479b786f5-k252c 1/1 Running 1 47h 10.244.4.21 <none> <none>vol-hostpath-demo 1/1 Running 0 7m45s 10.244.3.92 <none> <none>[root@master01 ~]# curl 10.244.3.92/test.htmlthis is test page from node03 /vol/html/test.html[root@master01 ~]# 提⽰:可以看到在对应节点上创建⽹页⽂件,访问pod能够正常被访问到; 测试:删除pod,看看对应节点上的⽬录是否会被删除?[root@master01 ~]# kubectl delete -f hostPath-demo.yamlpod "vol-hostpath-demo" deleted[root@master01 ~]# kubectl get podNAME READY STATUS RESTARTS AGEmyapp-6479b786f5-9d4mh 1/1 Running 1 47hmyapp-6479b786f5-k252c 1/1 Running 1 47h[root@master01 ~]# ssh node03Last login: Wed Dec 23 23:18:51 2020 from master01[root@node03 ~]# ll /vol/html/total 4-rw-r--r-- 1 root root 50 Dec 23 23:22 test.html[root@node03 ~]# exitlogoutConnection to node03 closed.[root@master01 ~]# 提⽰:可以看到删除了pod以后,在对应节点上的⽬录并不会被删除;对应的⽹页⽂件还是完好⽆损; 测试:重新引⽤配置清单,访问对应的pod,看看是否能够访问到对应的⽹页⽂件内容?[root@master01 ~]# kubectl apply -f hostPath-demo.yamlpod/vol-hostpath-demo created[root@master01 ~]# kubectl get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESmyapp-6479b786f5-9d4mh 1/1 Running 1 47h 10.244.2.99 <none> <none>myapp-6479b786f5-k252c 1/1 Running 1 47h 10.244.4.21 <none> <none>vol-hostpath-demo 1/1 Running 0 7s 10.244.3.93 <none> <none>[root@master01 ~]# curl 10.244.3.93/test.htmlthis is test page from node03 /vol/html/test.html[root@master01 ~]# 提⽰:可以看到对应pod被调度到node03上了,访问对应的pod能够访问到我们创建的⽹页⽂件;假如我们明确指定将此pod运⾏在node02上,对应pod是否还可以访问到对应的⽹页⽂件呢? 测试:绑定pod运⾏在上[root@master01 ~]# cat hostPath-demo.yamlapiVersion: v1kind: Podmetadata:name: vol-hostpath-demonamespace: defaultspec:nodeName: containers:- name: nginximage: nginx:1.14-alpinevolumeMounts:- name: webhtmlmountPath: /usr/share/nginx/htmlreadOnly: truevolumes:- name: webhtmlhostPath:path: /vol/html/type: DirectoryOrCreate[root@master01 ~]# 提⽰:绑定pod运⾏为某个节点上,我们可以在spec字段中⽤nodeName字段来指定对应节点的主机名即可; 删除原有pod,重新应⽤新资源清单[root@master01 ~]# kubectl delete pod/vol-hostpath-demopod "vol-hostpath-demo" deleted[root@master01 ~]# kubectl get podNAME READY STATUS RESTARTS AGEmyapp-6479b786f5-9d4mh 1/1 Running 1 47hmyapp-6479b786f5-k252c 1/1 Running 1 47h[root@master01 ~]# kubectl apply -f hostPath-demo.yamlpod/vol-hostpath-demo created[root@master01 ~]# kubectl get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESmyapp-6479b786f5-9d4mh 1/1 Running 1 47h 10.244.2.99 <none> <none>myapp-6479b786f5-k252c 1/1 Running 1 47h 10.244.4.21 <none> <none>vol-hostpath-demo 1/1 Running 0 8s 10.244.2.100 <none> <none>[root@master01 ~]# 提⽰:可以看到重新应⽤新资源清单,对应pod运⾏在node02上; 访问对应pod,看看test.html是否能够被访问到?[root@master01 ~]# curl 10.244.2.100/test.html<html><head><title>404 Not Found</title></head><body bgcolor="white"><center><h1>404 Not Found</h1></center><hr><center>nginx/1.14.2</center></body></html>[root@master01 ~]# 提⽰:可以看到现在访问pod,对应⽹页⽂件就不能被访问到;其实原因很简单;hostPath类型存储卷是将宿主机上的某个⽬录或⽂件当作存储卷映射进pause容器,然后供pod⾥的容器挂载使⽤;这种类型的存储卷不能跨节点;所以在node02上创建的pod,node03上的⽂件肯定是不能被访问到的;为此,如果要使⽤hostPath类型的存储卷,我们就必须绑定节点;除此之外我们就应该在k8s节点上创建相同的⽂件或⽬录; ⽰例:创建使⽤emptyDir类型存储卷pod[root@master01 ~]# cat emptyDir-demo.yamlapiVersion: v1kind: Podmetadata:name: vol-emptydir-demonamespace: defaultspec:containers:- name: nginximage: nginx:1.14-alpinevolumeMounts:- name: web-cache-dirmountPath: /usr/share/nginx/htmlreadOnly: truereadOnly: true- name: alpineimage: alpinevolumeMounts:- name: web-cache-dirmountPath: /nginx/htmlcommand: ["/bin/sh", "-c"]args:- while true; doecho $(hostname) $(date) >> /nginx/html/index.html;sleep 10;donevolumes:- name: web-cache-diremptyDir:medium: MemorysizeLimit: "10Mi"[root@master01 ~]# 提⽰:以上清单表⽰定义运⾏⼀个名为vol-emptydir-demo的pod;在其pod内部运⾏两个容器,⼀个名为nginx,⼀个名为alpine;同时这两个容器都同时挂载⼀个名为web-cache-dir的存储卷,其类型为emptyDir,如下图所⽰;定义empytDir类型的存储卷,我们需要在spec.volumes字段下使⽤name指定其存储卷的名称;⽤emptyDir指定其存储卷类型为emptyDir;对于empytDir类型存储卷,它有两个属性,medium字段⽤于指定媒介类型,Memory表⽰使⽤内存作为存储媒介;默认该字段的值为“”,表⽰使⽤默认的对应节点默认的存储媒介;sizeLimit字段是⽤来限制其对应存储⼤⼩,默认是空,表⽰不限制; 提⽰:如上图,其pod内部有两个容器,⼀个名为alpine的容器,它会每隔10往/nginx/html/inde.html⽂件中写⼊对应主机名+时间;⽽nginx容器挂载对应的empytDir类型存储卷到本地的⽹页存储⽬录;简单讲就是alpine容器往/nginx/html/index.html写数据,nginx容器挂载对应⽂件到⽹页⽬录; 应⽤资源清单[root@master01 ~]# kubectl apply -f emptyDir-demo.yamlpod/vol-emptydir-demo created[root@master01 ~]# kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESmyapp-6479b786f5-9d4mh 1/1 Running 1 2d 10.244.2.99 <none> <none>myapp-6479b786f5-k252c 1/1 Running 1 2d 10.244.4.21 <none> <none>vol-emptydir-demo 0/2 ContainerCreating 0 8s <none> <none> <none>vol-hostpath-demo 1/1 Running 0 72m 10.244.2.100 <none> <none>[root@master01 ~]# kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESmyapp-6479b786f5-9d4mh 1/1 Running 1 2d 10.244.2.99 <none> <none>myapp-6479b786f5-k252c 1/1 Running 1 2d 10.244.4.21 <none> <none>vol-emptydir-demo 2/2 Running 0 16s 10.244.3.94 <none> <none>vol-hostpath-demo 1/1 Running 0 72m 10.244.2.100 <none> <none>[root@master01 ~]# kubectl describe pod vol-emptydir-demoName: vol-emptydir-demoNamespace: defaultPriority: 0Node: /192.168.0.46Start Time: Thu, 24 Dec 2020 00:46:56 +0800Labels: <none>Annotations: <none>Status: RunningIP: 10.244.3.94IPs:IP: 10.244.3.94Containers:nginx:Container ID: docker://58af9ef80800fb22543d1c80be58849f45f3d62f3b44101dbca024e0761cead5Image: nginx:1.14-alpineImage ID: docker-pullable://nginx@sha256:485b610fefec7ff6c463ced9623314a04ed67e3945b9c08d7e53a47f6d108dc7Port: <none>Host Port: <none>State: RunningStarted: Thu, 24 Dec 2020 00:46:57 +0800Environment: <none>Mounts:/usr/share/nginx/html from web-cache-dir (ro)/var/run/secrets/kubernetes.io/serviceaccount from default-token-xvd4c (ro)alpine:Container ID: docker://327f110a10e8ef9edb5f86b5cb3dad53e824010b52b1c2a71d5dbecab6f49f05Image: alpineImage ID: docker-pullable://alpine@sha256:3c7497bf0c7af93428242d6176e8f7905f2201d8fc5861f45be7a346b5f23436Port: <none>Host Port: <none>Command:/bin/sh-cArgs:while true; do echo $(hostname) $(date) >> /nginx/html/index.html; sleep 10; doneState: RunningStarted: Thu, 24 Dec 2020 00:47:07 +0800Ready: TrueRestart Count: 0Environment: <none>Mounts:/nginx/html from web-cache-dir (rw)/var/run/secrets/kubernetes.io/serviceaccount from default-token-xvd4c (ro)Conditions:Type StatusInitialized TrueReady TrueContainersReady TruePodScheduled TrueVolumes:web-cache-dir:Type: EmptyDir (a temporary directory that shares a pod's lifetime)Medium: MemorySizeLimit: 10Midefault-token-xvd4c:Type: Secret (a volume populated by a Secret)SecretName: default-token-xvd4cOptional: falseQoS Class: BestEffortNode-Selectors: <none>Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300sEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 51s default-scheduler Successfully assigned default/vol-emptydir-demo to Normal Pulled 51s kubelet Container image "nginx:1.14-alpine" already present on machineNormal Created 51s kubelet Created container nginxNormal Started 50s kubelet Started container nginxNormal Pulling 50s kubelet Pulling image "alpine"Normal Pulled 40s kubelet Successfully pulled image "alpine" in 10.163157508sNormal Created 40s kubelet Created container alpineNormal Started 40s kubelet Started container alpine[root@master01 ~]# 提⽰:可以看到对应pod已经正常运⾏起来,其内部有2个容器;其中nginx容器⼀只读⽅式挂载名为web-cache-dir的存储卷,alpine以读写⽅式挂载web-cache-dir的存储卷;对应存储卷类型为emptyDir; 访问对应pod,看看是否能够访问到对应存储卷中index.html的内容?[root@master01 ~]# kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESmyapp-6479b786f5-9d4mh 1/1 Running 1 2d 10.244.2.99 <none> <none>myapp-6479b786f5-k252c 1/1 Running 1 2d 10.244.4.21 <none> <none>vol-emptydir-demo 2/2 Running 0 4m38s 10.244.3.94 <none> <none>vol-hostpath-demo 1/1 Running 0 77m 10.244.2.100 <none> <none>[root@master01 ~]# curl 10.244.3.94vol-emptydir-demo Wed Dec 23 16:47:07 UTC 2020vol-emptydir-demo Wed Dec 23 16:47:17 UTC 2020vol-emptydir-demo Wed Dec 23 16:47:27 UTC 2020vol-emptydir-demo Wed Dec 23 16:47:37 UTC 2020vol-emptydir-demo Wed Dec 23 16:47:47 UTC 2020vol-emptydir-demo Wed Dec 23 16:47:57 UTC 2020vol-emptydir-demo Wed Dec 23 16:48:07 UTC 2020vol-emptydir-demo Wed Dec 23 16:48:17 UTC 2020vol-emptydir-demo Wed Dec 23 16:48:27 UTC 2020vol-emptydir-demo Wed Dec 23 16:48:37 UTC 2020vol-emptydir-demo Wed Dec 23 16:48:47 UTC 2020vol-emptydir-demo Wed Dec 23 16:48:57 UTC 2020vol-emptydir-demo Wed Dec 23 16:49:07 UTC 2020vol-emptydir-demo Wed Dec 23 16:49:17 UTC 2020vol-emptydir-demo Wed Dec 23 16:49:27 UTC 2020vol-emptydir-demo Wed Dec 23 16:49:37 UTC 2020vol-emptydir-demo Wed Dec 23 16:49:47 UTC 2020vol-emptydir-demo Wed Dec 23 16:49:57 UTC 2020vol-emptydir-demo Wed Dec 23 16:50:07 UTC 2020vol-emptydir-demo Wed Dec 23 16:50:17 UTC 2020vol-emptydir-demo Wed Dec 23 16:50:27 UTC 2020vol-emptydir-demo Wed Dec 23 16:50:37 UTC 2020vol-emptydir-demo Wed Dec 23 16:50:47 UTC 2020vol-emptydir-demo Wed Dec 23 16:50:57 UTC 2020vol-emptydir-demo Wed Dec 23 16:51:07 UTC 2020vol-emptydir-demo Wed Dec 23 16:51:17 UTC 2020vol-emptydir-demo Wed Dec 23 16:51:27 UTC 2020vol-emptydir-demo Wed Dec 23 16:51:37 UTC 2020vol-emptydir-demo Wed Dec 23 16:51:47 UTC 2020[root@master01 ~]# 提⽰:可以看到能够访问到index.html⽂件内容,并且该⽂件内容是alpine容器动态⽣成的内容;从上⾯的⽰例,不难理解,在同⼀个pod内部可以共享同⼀存储卷; ⽰例:创建使⽤nfs类型的存储卷pod[root@master01 ~]# cat nfs-demo.yamlapiVersion: v1kind: Podmetadata:spec:containers:- name: nginximage: nginx:1.14-alpinevolumeMounts:- name: webhtmlmountPath: /usr/share/nginx/htmlreadOnly: truevolumes:- name: webhtmlnfs:path: /data/html/server: 192.168.0.99[root@master01 ~]# 提⽰:定义nfs类型存储卷,对应spec.volumes.nfs字段下必须定义path字段,该字段⽤于指定其nfs⽂件系统的导出⽂件路径;server字段是⽤于指定其nfs服务器地址;在使⽤nfs存储作为pod的后端存储,⾸先我们要准备好nfs服务器,并导出对应的⽬录; 准备nfs服务器,在192.168.0.99这台服务器上安装nfs-utils包[root@docker_registry ~]# ip a|grep 192.168.0.99inet 192.168.0.99/24 brd 192.168.0.255 scope global enp3s0[root@docker_registry ~]# yum install nfs-utils -yLoaded plugins: fastestmirror, langpacksRepository epel is listed more than once in the configurationRepository epel-debuginfo is listed more than once in the configurationRepository epel-source is listed more than once in the configurationbase | 3.6 kB 00:00:00docker-ce-stable | 3.5 kB 00:00:00epel | 4.7 kB 00:00:00extras | 2.9 kB 00:00:00kubernetes/signature | 844 B 00:00:00kubernetes/signature | 1.4 kB 00:00:00mariadb-main | 2.9 kB 00:00:00mariadb-maxscale | 2.4 kB 00:00:00mariadb-tools | 2.9 kB 00:00:00mongodb-org | 2.5 kB 00:00:00proxysql_repo | 2.9 kB 00:00:00updates | 2.9 kB 00:00:00(1/6): docker-ce-stable/x86_64/primary_db | 51 kB 00:00:00(2/6): kubernetes/primary | 83 kB 00:00:01(3/6): mongodb-org/primary_db | 26 kB 00:00:01(4/6): epel/x86_64/updateinfo | 1.0 MB 00:00:02(5/6): updates/7/x86_64/primary_db | 4.7 MB 00:00:01(6/6): epel/x86_64/primary_db | 6.9 MB 00:00:02Determining fastest mirrors* base: * extras: * updates: kubernetes 612/612Resolving Dependencies--> Running transaction check---> Package nfs-utils.x86_64 1:1.3.0-0.66.el7_8 will be updated---> Package nfs-utils.x86_64 1:1.3.0-0.68.el7 will be an update--> Finished Dependency ResolutionDependencies Resolved=============================================================================================================================================Package Arch Version Repository Size=============================================================================================================================================Updating:nfs-utils x86_64 1:1.3.0-0.68.el7 base 412 kTransaction Summary=============================================================================================================================================Upgrade 1 PackageTotal download size: 412 kDownloading packages:No Presto metadata available for basenfs-utils-1.3.0-0.68.el7.x86_64.rpm | 412 kB 00:00:00Running transaction checkRunning transaction testTransaction test succeededRunning transactionUpdating : 1:nfs-utils-1.3.0-0.68.el7.x86_64 1/2Cleanup : 1:nfs-utils-1.3.0-0.66.el7_8.x86_64 2/2Verifying : 1:nfs-utils-1.3.0-0.68.el7.x86_64 1/2Verifying : 1:nfs-utils-1.3.0-0.66.el7_8.x86_64 2/2Updated:nfs-utils.x86_64 1:1.3.0-0.68.el7Complete![root@docker_registry ~]# 创建/data/html⽬录[root@docker_registry ~]# mkdir /data/html -pvmkdir: created directory ‘/data/html’[root@docker_registry ~]# 配置该⽬录能够被k8s集群节点所访问[root@docker_registry ~]# cat /etc/exports/data/html 192.168.0.0/24(rw,no_root_squash)[root@docker_registry ~]# 提⽰:以上配置表⽰把/data/html这个⽬录以读写,不压榨root权限共享给192.168.0.0/24这个⽹络中的所有主机使⽤; 启动nfs[root@docker_registry ~]# systemctl start nfs[root@docker_registry ~]# ss -tnlState Recv-Q Send-Q Local Address:Port Peer Address:Port。
数据卷Volume
数据卷Volume数据卷概述Kubernetes Volume(数据卷)主要解决了如下两⽅⾯问题:数据持久性:通常情况下,容器运⾏起来之后,写⼊到其⽂件系统的⽂件暂时性的。
当容器崩溃后,kubelet 将会重启该容器,此时原容器运⾏后写⼊的⽂件将丢失,因为容器将重新从镜像创建。
数据共享:同⼀个 Pod(容器组)中运⾏的容器之间,经常会存在共享⽂件/⽂件夹的需求Docker ⾥同样也存在⼀个 volume(数据卷)的概念,但是 docker 对数据卷的管理相对 kubernetes ⽽⾔要更少⼀些。
在 Docker ⾥,⼀个Volume(数据卷)仅仅是宿主机(或另⼀个容器)⽂件系统上的⼀个⽂件夹。
Docker 并不管理 Volume(数据卷)的⽣命周期。
在 Kubernetes ⾥,Volume(数据卷)存在明确的⽣命周期(与包含该数据卷的容器组相同)。
因此,Volume(数据卷)的⽣命周期⽐同⼀容器组中任意容器的⽣命周期要更长,不管容器重启了多少次,数据都能被保留下来。
当然,如果容器组退出了,数据卷也就⾃然退出了。
此时,根据容器组所使⽤的 Volume(数据卷)类型不同,数据可能随数据卷的退出⽽删除,也可能被真正持久化,并在下次容器组重启时仍然可以使⽤。
从根本上来说,⼀个 Volume(数据卷)仅仅是⼀个可被容器组中的容器访问的⽂件⽬录(也许其中包含⼀些数据⽂件)。
这个⽬录是怎么来的,取决于该数据卷的类型(不同类型的数据卷使⽤不同的存储介质)。
使⽤ Volume(数据卷)时,我们需要先在容器组中定义⼀个数据卷,并将其挂载到容器的挂载点上。
容器中的⼀个进程所看到(可访问)的⽂件系统是由容器的 docker 镜像和容器所挂载的数据卷共同组成的。
Docker 镜像将被⾸先加载到该容器的⽂件系统,任何数据卷都被在此之后挂载到指定的路径上。
Volume(数据卷)不能被挂载到其他数据卷上,或者通过引⽤其他数据卷。
修改volumes
修改volumes"修改volumes"的具体操作可以取决于你所使用的平台、工具或系统。
下面是一些常见情况下修改volumes的方法:###Docker中修改容器的卷:1.Docker Compose文件:-如果你使用Docker Compose来管理容器,你可以打开`docker-compose.yml`文件,找到对应服务的`volumes`部分,并进行修改。
例如:```yamlservices:my_service:volumes:-/path/on/host:/path/in/container```2.Docker命令行:-如果你是使用Docker命令行启动容器,你可以在启动容器的时候通过`-v`选项来指定卷的映射。
例如:```bashdocker run-v/path/on/host:/path/in/container my_image```###Kubernetes中修改持久卷(Persistent Volume):1.YAML文件:-在Kubernetes中,你可以修改Pod或Deployment的YAML文件,找到`volumes`部分,并进行修改。
例如:```yamlvolumes:-name:my-volumepersistentVolumeClaim:claimName:my-claim```2.kubectl命令行:-你也可以使用kubectl命令行来修改Pod的卷。
例如:```bashkubectl edit pod my-pod```这会打开一个编辑器,你可以修改`volumes`部分。
###其他系统中修改卷:1.文件系统:-如果你在使用本地文件系统或其他存储系统,你可以通过直接修改文件系统中的路径或配置文件来更改卷的映射关系。
2.管理工具:-一些容器编排工具或存储管理工具可能提供了可视化界面或命令行工具,通过这些工具你可以更方便地修改卷的配置。
Docker容器的创建和部署方法
Docker容器的创建和部署方法随着云计算的快速发展,Docker作为一种轻量级的容器技术,越来越受到广大开发者的欢迎。
通过使用Docker,开发者可以更加高效地构建、打包和部署应用程序,实现应用程序的无缝移植和部署。
本文将介绍Docker容器的创建和部署方法,帮助读者更好地掌握这一技术。
一、Docker容器的创建Docker容器的创建是使用Docker镜像作为基础的。
Docker镜像是一个轻量级、可执行的、独立软件包,其中包含了运行特定应用程序所需的所有依赖项,包括代码、运行时环境、库和配置文件等。
创建Docker容器的过程可以通过以下几个步骤完成。
首先,选择一个适合的基础镜像。
Docker官方提供了一系列的官方镜像,例如Ubuntu、CentOS等,也可以选择其他社区贡献的镜像。
选择合适的基础镜像可以根据自己的需求和项目的特点进行选择。
其次,编写Dockerfile。
Dockerfile是一个文本文件,其中包含了一系列的指令,用于描述如何构建Docker镜像。
在Dockerfile中可以定义基础镜像、安装软件、添加文件等操作,以满足应用程序的运行需求。
然后,通过执行docker build命令来构建Docker镜像。
docker build命令会根据Dockerfile的指令来构建Docker镜像,生成一个新的镜像。
在构建过程中,Docker会依次执行Dockerfile中的指令,生成镜像的不同层级,并将这些层级打包成一个整体的镜像。
最后,通过执行docker run命令来创建并运行Docker容器。
docker run命令可以基于构建好的镜像来创建一个容器实例,并运行其中的应用程序。
在docker run命令中可以指定各种参数,例如端口映射、数据卷挂载等,以满足不同的需求。
二、Docker容器的部署Docker容器的部署是将创建好的容器实例部署到不同的环境中,确保应用程序可以被正常访问和使用。
Docker容器中数据两种持久化存储方式:卷和挂载宿主目录
镜像使用的是分层存储,容器也是如此。
每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。
容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。
因此,任何保存于容器存储层的信息都会随容器删除而丢失。
按照Docker最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。
所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
(1).卷(volumes):是宿主机器的文件系统的一部分,由Docker进行管理(在Linux,存储于/var/lib/docker/volumes/)。
非Docker程序不应该去修改这些文件。
Docker推荐使用卷进行持久化数据。
卷可支持卷驱动(volume drivers),该驱动允许用户将数据存储到远程主机或云服务商(cloud provider)或其它。
没有名字的卷叫匿名卷(anonymous volume),有名字的卷叫命名卷(named volume)。
匿名卷没有明确的名字,当被初始化时,会被赋予一个随机名字。
卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性:A.卷可以在容器之间共享和重用;B.对卷的修改会立马生效;C.对卷的更新,不会影响镜像;D.卷默认会一直存在,即使容器被删除。
卷的使用,类似于Linux下对目录或文件进行mount,镜像中的被指定为挂载点的目录中的文件会复制到卷中(仅卷为空时会复制)。
卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器被删除后自动删除卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的卷。
(2).挂载宿主目录(bind mounts, 绑定挂载):通过将宿主机器的路径挂载到容器里的这种方式,从而数据持久化,因此绑定挂载可将数据存储在宿主机器的文件系统的任何地方。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Docker学习笔记——Volume的创建
Volume可以将容器以及容器产生的数据分离开来,这样当你删除容器的时候,才不会影响相关的数据。
注意:容器并不是为了持久化。
Volume的创建
Volume可以使用两种方式创建:
- 在Dockerfile中制定VOLUME /some/dir
- 执行docker run -v /some/dir命令指定
Docker会在主机上创建一个目录,默认情况下是在
/var/lib/docker下,然后将其挂载到指定的路径(/some/dir),当删除使用该Volume的容器时,Volume本身不会受到影响,可以一直保存下去。
我们在主机上对/var/lib/docker目录的操作会同步到挂载该目录的容器中。
我们也可以使用-v参数来挂载指定的主机目录。
例如:
$ docker run -v /opt/data:/data ubuntu
该命令将挂载主机的/opt/data目录到容器内的/data目录上,任何在/opt/data目录的文件都将会出现在容器内。
这可以用
来实现主机和容器之间的文件共享。
当容器中的指定的目录不存在的时候会自动创建,当已存在的时候,该目录下的文件并不会同步到主机上的Volume,然后Volume中的数据则会被复制到容器中。
Volume的删除
我们可以在删除容器的时候同时删除Volume。
$ docker rm -v my_container
不过如果当前有其他容器仍挂载该Volume时,其是不会被删除的。
因此,由于我们在删除一些容器的时候未加-v参数,导致主机的/var/lib/docker/vfs/dir目录下出现了一些僵尸目录和文件。
数据共享
我们可以在docker run的时候使用–volumes-from参数从一个容器中访问另一个容器的Volume。
$ docker run -it --name newcontainer --volumes-from container-test ubuntu /bin/bash
此时并不管容器container-test是否在运行。
数据容器
通常使用数据容器来持久化数据库和数据文件。
$ docker run --name dbdata mysql echo "data only"
创建了一个名为dbdata的数据容器,运行完echo之后就停止了。
数据容器是不需要运行的,只要创建好了就可以了。
$ docker run -d --volumes-from dbdata --name db1 mysql
启动一个数据库服务容器,连接到dbdata数据容器上。
注意:
- 数据容器不需运行,纯粹是在浪费资源
- 不需为数据容器单独使用一个小的镜像,直接使用数据库镜像本身就可以了
数据备份
如果要备份mysql数据库,我们需要备份数据容器中的
/var/lib/mysql文件夹。
$ docker run --rm --volumes-from dbdata -v
$(pwd):/backup ubuntu tar zcvf /backup/mysql.tar.gz
/var/lib/mysql
此时就会在当前目录下生成一个msql.tar.gz文件。
参考资料:Docker入门实践——深入理解Docker Volume。