首页
提效神器
常用运维脚本汇总
电子书阅读
推荐
电子书阅读
事物管理
Search
1
安装docker时报错container-selinux >= 2:2.74
185 阅读
2
rsync命令(可替代rm删除巨量文件)
147 阅读
3
docker 镜像加速器配置,daemon.json文件详解
138 阅读
4
kubernetes集群各组件安装过程汇总
107 阅读
5
使用国内镜像地址拉取k8s安装需要的images
97 阅读
运维
自动化运维
数据库
容器与k8s
环境
云计算
脚本
ai
登录
/
注册
Search
标签搜索
命令
nginx
zabbix
Mingrui
累计撰写
99
篇文章
累计收到
8
条评论
首页
栏目
运维
自动化运维
数据库
容器与k8s
环境
云计算
脚本
ai
页面
提效神器
常用运维脚本汇总
电子书阅读
推荐
电子书阅读
事物管理
搜索到
75
篇与
的结果
2025-04-23
集群存储之PV与PVC
PVPV:Persistent Volume 持久卷。资源提供者,根据集群的基础设施变化而变化,由集群管理员进行配置管理。PV将存储定义为一种容器应用可以使用的资源。PV由管理员创建和配置,它与存储资源提供者的具体实现直接相关。不同提供者提供的PV类型包括NFS、iSCSI、RBD或者由公有云提供的共享存储。PV与普通的临时卷一样,也是通过插件机制进行实现的,只是PV的生命周期独立于使用它的Pod。PV并不直接属于某个Pod。如果某个Pod想要使用PV,需要使用PVC来完成申请。随后Kubernetes会完成从PVC到PV的绑定。之后被绑定的PV就可以被申请的Pod使用了。一个PV只能被一个PVC绑定,被绑定的PV不能再被其他PVC绑定。 PART.01 PV详解 PV作为对存储资源的定义,主要涉及存储能力,访问模式,存储类型,回收策略,后端存储类型等关键信息的设置。不同类型的PV是以不同的插件进行设计和实现的,主要包括以下几类:CSI:CSI容器存储借口,由存储资源提供者提供驱动程序和存储管理程序FC(Fibre channel):光纤存储设备hostPath:宿主机目录,仅供单Node测试iSCSI:iSCSI存储设备Local:本地持久化存储NFS:基于NFS协议的网络文件系统# 示例 apiVersion:v1 kind: PersistentVolume metadata: name: pv1 spec: capacity: storage: 5Gi volumeMode: Filesystem accesModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageOptions: - hard - nfsvers=4.1 nfs: path: /tmp server: 10.15.55.55 存储容量(capacity)存储容量用于描述存储的容量,目前仅支持对存储空间的设置(storage=XX)。存储卷模式(volumeMode)可选性只有两个:Filesystem(文件系统,默认值)和Block(块设备)。文件系统模式的PV将以目录(Directory)形式被挂载到Pod内。访问模式ReadWriteOnce(RWO):读写权限,只能被单个Node挂载(单用户读写)ReadOnlyMany(ROX):只读权限,允许被多个Node挂载(多用户只读)ReadWriteMany(RWX):读写权限,允许被多个Node挂载(多用户读写)ReadWriteOncePod(RWOP):可以被单个Pod以读写方式挂载,仅支持CSI存储卷,用于集群中只有一个Pod时以读写方式使用这种模式的PVC。某些PV可能同时支持多种访问模式,但PV在挂载时只能使用一种访问模式,多种访问模式不能同时生效。节点亲和性(nodeAffinity)PV可以通过设置节点亲和性来实现只能通过某些Node访问Valume,这可以在PV定义的nodeAffinity字段中进行设置。使用这些Volume的Pod将被调度到满足亲和性要求的Node上。大部分存储驱动提供的volume都已自动完成亲和性的设置,通常无需用户手动设置。对于Local类型的PV,需要手动设置。apiVersion: v1 kind: PersistentVolume metadata: name: local-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete storageClassName: local-storage local: path: /mnt/disks/ssd1 nodeAffinity: required: nodeSelectorterms: - matchExpressions: - key: kubernetes.io/hostname operator: In volues: - my-nodePV生命周期Available:可用状态,还未与某个PVC绑定Bound:以与某个PVC绑定Released:与之绑定的PVC已被删除,但未完成资源回收,不能被其他PVC使用Failed:自动资源回收失败 PART.01 PVC详解 PVC:PersistentVolumeClaim 持久卷声明。资源的使用着,根据业务的需求变化来配置,用户无需知道PV的技术细节,只需要声明你需要什么样的资源资源即可。apiVersion: v1 kind: PersistentVolumeClaim metadata: name: myclaim spec: accessModes: - ReadWriteOnce volumeMode: Filesystem resources: requests: storage: 8Gi storageClassName: slow selector: matchLabels: release: "stable" matchExpressions: - { key: environment, operator: In, values: [dev] } 说明resources:资源请求,描述对存储资源的请求,通过resources.requests.storage字段设置需求的存储空间的大小accessModes:访问模式,PVC也可以设置访问模式,用于描述用户应用对存储资源的访问权限volumeMode:存储卷模式,用于描述希望使用的PV存储卷模式,包括文件系统和块设备。PVC设置的存储卷模式最好与PV存储卷模式相同,以实现绑定。如果不同可能会出现无法绑定的结果。selector:PV选择条件,通过设置Label Selector,可以使PVC对于系统中已经存在的各种PV进行筛选。系统将根据标签选出合适的PV与该PVC进行绑定。对于选择条件,可以通过matchLabels和matchExpressions进行设置。如果两个字段都已设置,则Selector要同时满足才能完成匹配。Clas:存储类别,在定义PVC时可以设定需要的后端存储类别(通过storageClassName字段进行指定),以减少对后端存储特性的详细信息的依赖。只有设置了Class的PV才能被系统筛选出来,与该PV进行绑定。PVC也可以不设置Class需求,如果storageClassName字段的值被设置为空(storageClassName=""),则表示该PVC不需求特定的Class,系统只选择未设定Class的PV与之绑定。PVC也可以完成不设置storageClassName字段,此时将根据系统是否启用了名为DefaultStorageClass的Admission Controller进行相应的操作。{mtitle title="PV和PVC的工作原"/}1.资源供应Kubernetes支持两种资源供应模式:静态(static)和动态(Dynamic)模式。资源供应的结果就是将适合的PV与PVC成功绑定。静态模式:集群管理员预先创建若干PV,在PV的定义中能够体现存储资源的特征。动态模式:集群管理员无需预先创建PV,而是通过StorageClass的设置对后端存储资源进行描述,标记存储的类型和特征。用户通过创建的PVC对存储类型进行申请。之后,StorageClass中的驱动提供者将自动完成PV的创建工作,并将创建出的PV与PVC进行绑定。如果PVC声明的Class为空,则说明PVC不适用动态模式。Kubernetes支持设置集群范围内默认的StorageClass,为用户创建的PVC设置一个默认的存储类StrongClass。2.资源绑定在用户定义好PVC后,系统将根据PVC对存储资源的请求(存储空间和访问模式),在已存在的PV中选择一个满足PVC要求的PV。一旦找到,就将该PV与用户定义的PVC进行绑定,用户的应用就可以使用这个PVC了。如果系统中没有满足PVC要求的PV,那么PVC会无限期处在pending状态,直到系统为其创建了一个满足要求的PV。PV一旦与某个PVC完成绑定,就会被这个PVC独占,不能再与其他的PVC绑定。PVC与PV的绑定关系是一对一的,不会存在一对多的情况。但是同一个PVC可以被多个Pod同时挂载(应用需要处理完成多个进程访问同一个存储的问题)。如果PVC申请的存储空间比PV拥有的存储空间少,则整个PV的空间都能为PVC所用。但是这可能造成一定的资源浪费。如果资源供应使用的是动态模式,那么系统在为PVC找到合适的StorageClass后,将自动创建一个PV并完成与PVC的绑定。3.资源使用当Pod需要使用存储资源时,需要在Volume的定义中引用PVC类型的Volume,将PVC挂载到容器内的某个路径下进行使用。Volume的类型字段为“persistentVolumeClaim”。Pod在被挂载了PVC后,就可以使用存储资源了。4.资源回收用户使用完存储资源后,可以删除PVC。与该PVC绑定的PV会被标记为“已释放”,但它还不能立刻与其他PVC绑定。Pod在该PVC中生成的数据可能还被保留在PV对应的存储设备上。只有在清楚了这些数据后,才能再次使用该PV。PV的回收策略Retain(保留)Delete(删除)Retain策略 表示在删除PVC后,与之绑定的PV不会被删除,仅被标记为已释放(released)。PV中的数据仍然存在,在清空数据之前不能被新的PVC使用,需要管理员手动清理之后才能继续使用。清理步骤:删除PV资源对象,此时与该PV关联的某些外部存储资源提供者的后端存储资产(Asset)中的数据仍然存在。手动清理PV后端存储资产中的数据。手动删除后端存储资产。如果希望重用该资产,可以创建一个新的PV与之关联。Delete策略 表示自动删除PV资源对象和相关后端存储资产,同时会删除与该PV关联的后端存储资产。但并不是所有类型的存储资源都支持Delete策略。通过动态供应机制创建的PV将继承StorageClass的回收策略,默认为delete策略。管理员应该基于用户的需求来设置StorageClass的回收策略,或者在创建出PV后手动更新其回收策略。存储对象保护机制存储资源(PV、PVC)相对于容器应用(Pod)是可以独立管理的资源,可以单独将其删除。在执行删除操作时,系统会检测存储资源当前是否正在被使用,如果仍被使用,则相关资源对象的删除操作会被推迟,直到没有被使用才会执行删除操作。这样可以确保资源在仍被使用的情况下,不会被直接删除而导致数据丢失,这个机制被称为使用中的存储对象的保护机制(Storage Object in Use Protection)。对于PVC的删除操作将等到使用它的Pod被删除后再执行。当用户删除一个正在使用中的PVC时,PVC资源对象不会被立即立即删除,查看PVC资源对象的状态,可以看到其为“Terminating”,以及系统为其设置的Finalizer为“kubernetes.io/pvc-protection”,说明PVC资源对象处于被保护状态。对PV的删除操作将等到绑定的PVC删除之后再执行。当用户删除一个仍被PVC绑定的PV时,PV对象不会立即被删除,查看PV资源对象的状态,可以看到其为“Terminating”,以及系统为其设置的Finalizer为“kubernetes.io/pv-protection”,说明PV资源对象处于被保护状态。总的来说,PV与PVC的删除顺序是这样的:先删除正在使用PVC的Pod,再删除PVC,最后删除PV。
2025年04月23日
52 阅读
0 评论
0 点赞
2025-04-23
集群存储之持久卷介绍
Kubernetes支持的内置(in-tree)持久卷类型包括hostPath(宿主机目录)、FC(fibre Channel)、iSCSI(iSCSI存储设备)、Local(本地持久化存储)、NFS(基于NFS协议的网络文件系统)等资源。它们不作为PV资源对象被创建,而是直接在Pod的Volume字段被设置和使用。下面就常用的hostPath和NFS做简要介绍。hostPathhostPath类型的Volume用于将Node文件系统的目录或文件挂载到容器内部,并且在Pod删除后数据仍然被保留。由于hostPath直接使用宿主机的文件系统,无法被Kubernetes直接管理,因此存在很多安全风险,建议尽量不要使用。在必须要用时尽量以只读的方式将其挂载到容器内,以尽量减少对容器应用可能造成的破坏。使用场景容器应用的关键数据需要持久化保存到宿主机上;需要使用docker中的某些内部机制,可以将主机的/var/lib/docker目录挂载到容器内;监控系统,例如cAdvisor需要采集宿主机/sys/目录下的内容;Pod的启动依赖于宿主机上的某个目录或文件就绪。hostPath的主要配置参数为path,表示宿主机目录或文件路径;还可以设置一个可选的参数type,表示路径的操作类型。type的配置参数如下:type参数检校规则空默认值,系统在挂载path时不做任何检校DirectoryOrCreatepath指定的路径必须是目录,如果不存在系统将自动创建该目录,并将目录的权限设置为0755,具有与Kubelet相同的owner和groupDirectorypath指定的路径必须是目录,否则挂载失败FileOrCreatepath指定的路径必须是文件,如果不存在,系统将自动创建该文件,并将文件的权限设置为0644,具有与Kubelet相同的owner和groupFilepath指定的路径必须是文件,否则挂载失败SocketPath指定的UNIX Socket必须存在,否则挂载失败CharDevicepath指定的字符设备必须存在,否则挂载失败BlockDevicepath指定的块设备必须存在,否则挂载失败对于type为FileOrCreate模式的情况,如果挂载文件有上层目录,则系统不会自动创建上层目录,当上层目录不存在时,Pod启动失败。在这种情况下,可以将上层目录也设置为一个hostPath类型的Volume,并且设置type为DirectoryOrCreate,确保当目录不存在时,系统会自动创建出来。注意事项通过hostPath可能会将宿主机的某些具有特殊权限的文件挂载到容器内,例如Kubelet和容器运行时的Socket,使得容器的进程也能够越权对宿主机进行某些操作;对具有相同hostPath设置的多个Pod来说,可能会被master调度到多个Node上运行,但如果这些Node上的hostPath中的文件夹的内容(如配置文件这些)不同,则各个Pod的运行结果可能会出现差异;如果管理员设置了某些基于存储资源情况的调度策略,则hostPath目录下的磁盘空间将无法计入Node的可用资源范围内,可能出现与预期不同的调度结果;如果是之前不存在的路径,由Kubelet自动创建的文件或目录的owner和group将是root。这意味着如果容器内运行的用户(user)不是root,则将无法对该目录进行写操作,除非将容器设置为特权容器,或者由管理员修改hostPath的权限;hostPath设置的宿主机目录或文件不会随着Pod的销毁而被删除,而是在Pod被销毁之后,由管理员手动删除。NFSNFS类型的Volume用于将基于NFS协议的网络网络文件系统中的目录或文件挂载到容器内使用,并且在Pod被删除后数据仍然被保留。在Pod使用NFS协议的Volume之前,需要确保NFS服务正常运行。另外,也不能像PV那样使用mountOptions字段来定义挂载项。NFS卷可以在不同节点的Pod间共享数据。本地NFS客户端可以透明的读写位于远端NFS服务器上的 文件,就像访问本地文件一样。
2025年04月23日
48 阅读
0 评论
0 点赞
2025-04-23
集群存储之临时卷介绍
Volume在集群中也是一种资源,Pod通过挂载(Mount)的方式来使用一个或多个Volume。某些类型的Volume具有与Pod相同的生命周期,被称为“临时卷”。emptyDIr该类型的Volume在Pod被调度到Node时由Kubelet进行创建,在初始状态下是个空目录,被命名为“空目录”(Empty DIrectory)。它与Pod具有相同的生命周期,当Pod被销毁时,emptyDir对应的目录也会被删除。同一个Pod中的多个容器都可以挂载这种类型的Volume。使用场景基于磁盘进行合并排序操作时需要的暂存空间;长时间计算任务的中间检查点文件;为某个Web服务提供的临时网站内容文件。同一个Pod中容器共享数据使用内存提供存储服务emptyDir可以通过medium字段设置存储介质为“Memory”,表示使用基于内存的文件系统。需要注意的是,在主机重启后,内存中存储的信息会被清空。写入内存的数据将被计入容器的内存使用量,受到容器级别内存资源上限(Memory Resource Limit)的限制。示例{tabs}{tabs-pane label="示例1"}--- apiVersion: v1 kind: pod metadata: name: pod1 spec: containers: - image: busybox name: test1 volumeMounts: - mountPath: /cache name: cache-volume volumes: - name: cache-volume emptyDir: {}{/tabs-pane}{tabs-pane label="示例2"}#设置emptyDir使用内存 apiVersion: v1 kind: pod …… volumes: - name: cache-volume emptyDir: medium: "Memory"{/tabs-pane}{tabs-pane label="示例3"}#设置emptyDir使用内存,并设置可使用的内存上限 #需要开启SizeMemoryBackedVolumes apiVersion: v1 kind: pod …… volumes: - name: cache-volume emptyDir: medium: "Memory" sizeLimit: 500Mi{/tabs-pane}{/tabs}Generic EphemeralGeneric Ephemeral类型的Volume(通用临时卷)与emptyDir的功能相似,但更加灵活,有以下特性:后端的存储既可以是本地磁盘,也可以是网络存储;可以为Generic Ephemeral设置容量上限;在Generic Ephemeral内可以有一些初始数据。在驱动支持的情况下,Generic Ephemeral支持快照、克隆、调整大小、容量跟踪等标准的卷操作。示例--- apiVersion: v1 kind: pod metadata: name: my-app spec: containers: - name: my-frontend image: busybox command: [ "sleep", "1000" ] volumeMounts: - mountPath: "/scratch" name: scratch-volume volumes: - name: scratch-volume ephemeral: volumeClaimTemplate: matedata: labels: type: my-frontend-volume spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "scratch-storage-class" resources: requests: storage: 1Gi 说明: 上面的示例中,Generic Ephemeral类型的Volume的参数设置需要从storageClass"scratch-storage-class"中申请1GiB的存储空间。根据volumeClaimTemplate的配置,系统将自动创建一个对应的PVC,并确保在删除Pod时自动删除这个PVC。这个PVC会以Pod的名称和Volume的名称的组合为其命名,中间以“-”连接,本例中PVC的名称是“my-app-scratch-volume”。某些情况下,这种命名机制可能会引起冲突,在部署Pod时需要注意。在安全方面,当用户有权限创建Pod的时候,Generic Ephemeral会隐式地创建一个PVC(即使用户没有创建PVC的权限),这可能不符合安全要求。{mtitle title="其他类型临时卷"/}Kubernetes的一些内部资源对象也可以通过Volume的形式挂载为容器的目录或文件,包括configMap、Secret、Downward API等,这些类型的Volume也是临时卷,会随着Pod的销毁而被系统删除。ConfigMapConfigMap主要保存应用所需的配置文件,并且通过Valume的形式挂载到容器内的文件系统中,以供容器内的应用读取。这样就可以做到配置文件与镜像的分离,使容器具有可移植性。ConfigMap在使用之前需要先创建它,ConfigMap不能用来保存大量的数据,其中保存的数据不可以超过1MIB。ConfigMap主要用来生成容器内的环境变量,设置容器启动命令的命令行参数(需要设置为环境变量),以Volume的形式挂载为容器内的文件或目录等。由于ConfigMap受限于命名空间,所以要引用ConfigMap的Pod必须与ConfigMap处于相同的命名空间中才能被成功引用。静态Pod因为不受master管理,无法引用ConfigMap。创建ConfigMap的方式ConfigMap中不存在spec字段,它通过data或binaryData字段定义配置数据。data字段用于保存经过utf-8编码的字符串,binaryData字段用于保存经过Base64编码的二进制数据。ConfigMap中有个immutable字段,用于设置配置数据不可更改。即ConfigMap一旦创建成功后就不可修改。设置这个字段可以防止意外更新ConfigMap对应用带来的异常影响,减少API Server监控ConfigMap的变化带来的性能损耗。1.基于本地配置文件--- apiVersion: v1 kind: ConfigMap metadata: name: cm-appvare data: apploglevel: info appdatadir: /var/data#通过kubectl创建这个ConfigMap kubectl apply -f cm-appvare.yaml2.基于kubectl命令行 可以直接通过kubectl create configmap 命令创建ConfigMap,支持通过下面三种参数来指定不同类型的数据源创建ConfigMap。--from-file:基于指定的文件或目录创建ConfigMap--from-env-file:基于指定的env文件创建ConfigMap--from-literal:基于指定的键值对创建ConfigMap--from-file 如果基于指定文件创建ConfigMap,默认情况下key的值会被设置为文件名,value的值会被设置为问几点内容。也可以通过命令行参数指定key名,不将文件名作为key名。如果基于指定的目录创建ConfigMap,则目录下的每个文件都会被创建为data中的一个key:value键值对。参数--from-file可以多次出现,用于在一个kubectl create命令行中将多个文件或目录创建到一个ConfigMap中。用文件名作为key值时需要注意文件名要符合key的命名规范,否则命令将运行失败。名称中只能使用这些字符:[a-z] [A-Z] [0-9] - _ .#在当前目录下存在server.xml文件,创建一个只包含该文件内容的ConfigMap kubectl create configmap server-config --from-file=server.xml #在当前目录下有个configs子目录,里面有两个配置文件,创建一个包含这两个配置文件内容的ConfigMap kubectl create configmap app-config --from-file=./configs #创建ConfigMap时指定key的名字为mykey kubectl create configmap server-config --from-file=mykey=server.xml #多次使用--from-file参数,创建一个包含多个配置文件内容的ConfigMap kubectl create configmap app-config --from-file=server.xml --from-file=logging.properties--from-env-file--from-env-file同样支持多次使用该参数创建一个包含多个源配置文件的ConfigMap。 env文件包含一组环境变量的配置数据,其内容遵循如下语法规则:每行文本都为VAR=VALUE的格式,等号两边不能有空格忽略以“#”开头的注释行忽略空行对文本中的引号不做转义处理,即保留原始文本并将其作为value的值#环境变量文件示例 cat log.properties level=FINE directory="${catalina.base}/logs" prefix=catalina. #通过kubectl create命令进行创建 kubectl create configmap log-env-config --from-env-file=log.properties --from-literal --from-literal可以多次使用从而生成多个ConfigMap的数据内容。使用该参数时只能直接从命令行输入键值对,适用于简单的环境变量或少量键值对。该参数生成的ConfigMap无法动态更新。kubectl create configmap appenv --from-literal=loglevel=info --from-literal=appdatadir=/var/data在Pod中使用ConfigMap容器应用通过以下两种方式使用ConfigMap将ConfigMap中的内容设置为容器的环境变量通过volume将ConfigMap中的内容挂载为容器内的文件或目录{tabs}{tabs-pane label="ConfigMap文件示例"}cat cm-appvars apiVersion: v1 kind: ConfigMap metadata: name: cm-appvars data: apploglevel: info appdatadir: /var/data{/tabs-pane}{tabs-pane label="挂载示例1"}apiVersion: v1 kind: Pod metadata: name: cm-test-pod spec: containers: - name: cm-test image: busybox command: [ "/bin/sh", "-c", "env | grep APP" ] env: - name: APPLOGLEVEL #定义环境变量的名称 valueFrom: #key"APPLOGLEVEL"对应的值 configMapKeyRef: name: cm-appvars #环境变量的值取自cm-appvars key: apploglevel #key为apploglevel - name: APPDATADIR #定义环境变量的名称 valueFrom: #key"APPDATADIR"对应的值 configMapKeyRef: name: cm-appvars #环境变量的值取自cm-appvars key: appdatadir #key为appdatadir restartPolicy: Never kubectl create -f cm-test-pod.yaml kubectl logs cm-test-pod APPDATADIR=/var/data APPLOGLEVEL=info{/tabs-pane}{tabs-pane label="挂载示例2"}--- apiVersion: v1 kind: Pod metadata: name: cm-test-pod spec: containers: - name: cm-test image: busybox command: [ "/bin/sh", "-c", "env" ] envFrom: - configMapRef: name: cm-appvars restartPolicy: Never kubectl apply -f cm-test-pod2.yaml kubectl logs cm-test-pod2 apploglevel=info appdatadir=/var/data{/tabs-pane}{/tabs}示例2中通过envFrom字段,实现了在Pod环境下将ConfigMap中的所有key:value键值对都自动生成环境变量。环境变量的命名受POSIX命名规范约束(a-zA-Z_*),不能以数字开头。如果包含非法字符,则系统将挑过该环境变量的创建,并记录一个Event来提示环境变量无法生成,但并不阻止Pod的启动。通过Volume将ConfigMap中的内容挂载为容器内的文件或目录 {tabs}{tabs-pane label="configmap文件内容"}--- apiVersion: v1 kind: ConfigMap metadata: name: cm-appconfigfiles data: key-serverxml: | <?xml version='1.0' encoding='utf-8'?> <Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> …… …… </Service> </Server> key-loggingproperties: "handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, …… …… = 4host-manager.org.apache.juli.FileHandler\r\n\r\n"{/tabs-pane}{tabs-pane label="示例1"}--- apiVersion: v1 kind: Pod metadata: name: cm-test-app spec: containers: - name: cm-test-app image: kubeguide/tomcat-app:v1 ports: - containerPort: 8080 volumeMounts: - name: serverxml #引用Volume的名称 mountPath: /configfiles #挂载到容器内该目录下 volumes: - name: serverxml #定义Volume的名称 configMap: name: cm-appconfigfiles #指定ConfigMap的名称 items: - key: key-serverxml #ConfigMap中key的名称 path: server.xml #key对应的值(value)将以server.xml文件名挂载 - key: key-loggingproperties #ConfigMap中key的名称 path: logging.properties #key对应的值(value)将以logging.properties文件名挂载到容器内 kubectl exec -it cm-test-app --bash ls /configfiles sserver.xml logging.properties{/tabs-pane}{tabs-pane label="示例2"}#如果在引用ConfigMap时不指定items,则通过volumeMount方式在容器内的目录下为每个item都生成一个名为“key”的文件,文件的内容为key的值。 --- apiVersion: v1 kind: Pod metadata: name: cm-test-app spec: containers: - name: cm-test-app image: kubeguide/tomcat-app:v1 imagePullPolicy: Never ports: - containerPort: 8080 volumeMounts: - name: serverxml #引用Volume的名称 mountPath: /configfiles #挂载到容器的该目录下 volumes: - name: serverxml #定义Volume的名称 configMap: name: cm-appconfigfiles #使用ConfigMap“cm-appconfigfiles” kubectl exec -it cm-test-app --bash ls /configfiles key-loggingproperties key-serverxml {/tabs-pane}{/tabs}ConfigMap可选设置在Pod的定义中,可以将对ConfigMap的引用设置为是否可选(optional),若设置为可选(optional=true),则表示如果ConfigMap不存在,或者引用的数据项在ConfigMap中不存在,那么目标数据将被设置为空值。当ConfigMap被设置为Volume存储卷时,表示当ConfigMap不存在时,目标挂载的文件内容是空的。{tabs}{tabs-pane label="示例1"}--- apiVersion: v1 kind: Pod metadata: name: cm-test-pod-cm-env-optional spec: containers: - name: cm-test image: busybox command: [ "/bin/sh", "-c", "env | grep APP" ] env: - name: APPLOGLEVEL valueFrom: configMapKeyRef: name: cm-appvars key: apploglevel optional: true #设置为可选 - name: APPDATADIR valueFrom: configMapKeyRef: name: cm-appvars key: appdatadir optional: true #设置为可选 restartPolicy: Never kubec logs cm-test-pod-cm-env-optional [结果为空]{/tabs-pane}{tabs-pane label="示例2"}--- apiVersion: v1 kind: Pod metadata: name: cm-test-app-cm-volume-optional spec: containers: - name: tomcat image: busybox command: [ "/bin/sh", "-c", "tail -f /dev/null" ] volumeMounts: - name: serverxml mountPath: /configfiles volumes: - name: serverxml configMap: name: cm-appconfigfiles optional: true kubectl exec -it cm-test-app-cm-volume-optional --bash ls /configfiles [结果为空]{/tabs-pane}{/tabs}SecretSecret专门用于保存机密数据。在设置Secret.data字段时,所有键值都必须是经过base64编码的字符串。Secret主要用来为容器配置环境变量,挂载配置文件/目录到容器。此外,由Kubelet为Pod拉取镜像时,在需要登录仓库的时候使用。Downward API通过Downward API 可以将Pod或者Container的某些元数据信息(如Pod名称、Pod IP、Node Ip、Label、Annotation、容器资源限制等)以文件的形式挂载到容器内,以供容器内的应用使用。Downward API可以通过两种方式将Pod和容器的元数据信息注入到容器内。环境变量方式:将Pod或container的配置信息设置为容器内的环境变量Volume挂载方式:将Pod或container的配置信息以文件的形式挂载到容器内Downward API支持设置的Pod和Container信息可以通过fieldRef设置的字段字段名说明metadata.namePod名称metadata.namespacePod所在名称空间的名称metadata.uidPod的UIDmetadata.labels['']Pod的某个Label的值,通过引用metadata.annotations['']Pod某个Annotation的值,通过引用Pod的以下元数据信息可以被设置为容器内的环境变量,但在设置downwardAPI为存储卷类型时不能再设置filedRef字段的内容字段名说明spec.serviceAccountNamePod使用的ServiceAccount名称spec.nodeNamePod所在的Node的名称status.hostIPPod所在Node的IP地址status.hostIPsPod所在Node的IPv4和IPv5双栈地址status.podIPPod的IP地址status.podIPsPod的IPv4和IPv5双栈地址在设置downwardAPI为存储卷类型时,可以在其fieldRef字段设置以下信息,但不能通过环境变量的方式设置。mmetadata.lables:Pod的Label列表,每个Lable都以key为文件名,value为文件的内容,每个Label各占一行metadata.annotation:Pod的Annotation列表,每个Annotation都以key为文件名,value为文件的内容,每个Annotation各占一行可以通过resourceFieldRef设置的字段字段名说明limits.cpuContainer级别的CPU Limitrequests.cpuContainer级别的CPU Requestlimits.memoryContainer级别的Memory Limitrequests.memoryContainer级别的Memory Requestlimits.hugepages-*Container级别的HugePage(巨页)Limitrequests.hugepages-*Container级别的HugePage(巨页)Requestlimits.ephemeral-storageContainer级别的临时存储空间Limitrequests.ephemeral-storageContainer级别的临时存储空间RequestProjected VolumeProjected Volume是一种特殊的Volume类型,用于将一个或多个资源对象(ConfigMap、Secret、Downward API)一次性挂载到容器内的同一个目录下。常见应用场景通过Pod的标签生成不同的配置文件,需要使用配置文件及用户名和密码时,需要使用3种资源:ConfigMap、Secret、Downward API。在自动化运维应用中使用配置文件和帐号信息时,需要使用ConfigMap、Secret。在配置文件中使用Pod名称(metadata.name)记录日志时,需要使用ConfigMap、Downward API。使用某个Secret对Pod所在的命名空间(metadata.namespace)进行加密时,需要使用Secret、Downward API。Project Volume在Pod的Volume定义中类型为projected,通过sources字段来设置一个或多个的ConfigMap、Secret、Downward API、Service Account Token等资源。各种类型的资源配置内容与单独设置为Volume时基本一致,需要注意以下两个不同点:对于Secret类型的Volume,字段名“secretName”在projected.sources.secret中被改为“name”;Volume的挂载模式“defaultMode”只可以设置为projected级别。对于各子项,仍然可以设置各自的挂载模式,使用的字段名为“mode”。
2025年04月23日
46 阅读
0 评论
0 点赞
2025-04-21
对容器进行资源限额的几种方式
在一个集群内如何更合理的为大量容器分配有限的资源,是需要重点运维和管理的工作。
2025年04月21日
44 阅读
0 评论
0 点赞
2025-04-18
容器的调度策略介绍
kubernetes scheduler是负责Pod调度的进程(组件),它的作用是先对等待调度的Pod通过一些复杂的调度流程计算出其最佳的目标Node,再將Pod绑定到目标Node上。随着kubernetes功能的不断增强和完善,Pod的调度也变得越来越复杂。Scheduler内部的实现机制也在不断优化,从最初的两阶段调度机制(Predicates&Priorities)发展到现在的调度框架(Scheduling Framework),以满足越来越复杂的调度场景。Pod调度复杂的原因:kubernetes要努力满足不同类型应用的不同需求并努力让大家和平相处。kubernetes集群里的Pod可以分为三类:无状态服务类,有状态集群类,批处理类。不同类型的Pod对资源占用的需求不同,对Node故障引发的中断/恢复及Node迁移方面的容忍度不同。调度流程kube-apiserver将待调度的Pod的信息发送给kube-scheduler,scheduler通过一系列的计算把Pod要绑定的最优Node(或者暂时不存在)信息返还返还给apiserver。调度流程过滤阶段(Filtering):遍历所有的Node,筛选出符合要求的候选Node。此阶段Scheduler会将不合适的Node全部过滤掉,只留下符合条件的候选Node。具体方式是通过一系列待定的Predicates对每个Node进行筛选,在筛选完成后通常会有多个候选Node供调度,从而进入打分阶段。如果筛选的结果集为空,则表示当前没有符合条件的Node,此时Pod会一直处于Pending状态。打分阶段(Scoring):在过滤阶段的基础上,采用优选策略计算出每个候选Node的积分,积分最高者胜出。在挑选出最佳Node后,Scheduler会把目标Pod安置到该Node上,完成调度。注:当Node处于以下状态时,Scheduler不在给它调度新的Pod。NotReadyUnschedulableMemoryPressure(不再调度新的BestEffort PodPod到这个Node)DiskPressure调度策略指定Node名称的定向调度策略Kubernetes支持在Pod的配置中通过指定nodeName字段的方式指定要调度的目标Node名称。这个字段的优先级高于nodeSelector和亲和性策略。设置了nodeName字段的Pod将不再参与调度器的调度过程,相当于已经完成了调度,apiserver将直接通知目标Node上的kubelet开始创建这个Pod。使用nodeName具有以下限制:如果指定的node不存在或者失联,则Pod将无法运行;如果指定的node资源不足,则pod可能会运行失败;在某些云环境下,node名称不一定是稳定的。验证一下污点策略的优先级示例:--- apiVersion: v1 kind: pod metadata: name: nginx spec: containers: - name: nginx image: nginx nodeName: 192.168.88.61基于Node Label的调度策略Node也是kubernetes管理的一种资源对象,可以为其设置多个Label。在Pod的配置中,可以方便的使用Label Selector来声明需要调度到具有指定Label的Node上,调度器会在具有这些Label的Node中进行选择。通过基于Node Label的调度方式,可以把集群中具有不同特点的Node都贴上不同的Label(如“role=frontend”,“role=backend”,“role=database”等),在部署应用时可以根据应用的需求设置NodeSelector来进行指定Node范围的调度。需要注意的是,如果指定了nodeselector条件,但是在集群中不存在包含相应Label的Node,那么集群中即便存在可供使用的Node,这个Pod也无法被成功调度。示例:--- apiVersion: v1 kind: pod metadata: name: pod-node-selector spec: nodeSelector: disk: ssd containers: - name: busybox image: busybox command: ['sh','-c','sleep 3600']亲和性调度策略亲和性和反亲和性的机制,扩展了Pod的调度能力,实现了更加灵活和精细的策略。其具有如下优点:更强的逻辑选择能力(不仅仅是“符合全部”的简单情况)可以设置为软性限制或优选,使得调度器在无法找到全部满足要求的Node时,也会寻找其他Node来调度Pod。除了基于Node上的Label,还可以依据Node上正在运行的其他Pod的Label来进行亲和性和反亲和性设置。这样可以定义一组规则来描述Pod间的亲和或者互斥关系。亲和性调度功能包括节点亲和性(NodeAffinity)和Pod亲和性(PodAffinity)两种类型。节点亲和性调度策略节点亲和性调度策略与NodeSelector类似,但表达能力更强,并且允许设置软性匹配规则。设置方法也是通过Node上的Label来设置Pod是否可以调度到目标Node上。节点亲和性的配置类型有以下两种:requiredDuringSchedulingIgnoredDuringExecution:必须满足指定的规则才可以调度Pod到Node上,是硬性要求,它的功能与nodeSelector相似,但是使用的是更加灵活的语法。preferredDuringSchedulingIgnoredDuringExecution:强调优先满足指定规则,调度器会尝试调度Pod到Node上,但并不强求,是软性限制。可以设置多个规则,还可以给每个规则设置权重值(weight),以定义判断的优先级顺序。权重 可以为每个规则设置一个1-100的权重值(weight),用于给调度器提供一个类似于优先级的分数,调度器会为满足条件的Node加上weight设置的值,以选出最终得分最高的Node。这两种策略中的IgnoredDuringExecution的意思是:如果一个Pod所在的节点在Pod运行期间其标签发生了变化,不再符合该Pod的亲和性需求,则系统将忽略Node上的Label变化,让Pod在原Node上继续运行。也就是说Pod正常运行后,不再对Node进行亲和性验证。在Label的匹配规则中,使用逻辑操作符(operator)进行设置,可用使用的操作符及其含义如下:In:Label的值(value)在给定的集合中。NotIn: Label的值(value)不在给定的集合中。Exists:需要具有此Label Key,此时不需要设置key的值。DoseNotExist:需要不存在此Label的值,此时不需要设置key的值。Gt;Label的值(Value)的整数值需要大于给定的值。Lt:Label的值(Value)的整数值需要小于给定的值。{callout color="#f75008"}NodeAffinity规则设置的注意事项如下:如果在Pod配置中同时使用了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,才能将Pod调度到指定的Node上。(既要满足标签调度策略,又要满足亲和性调度策略。)如果nodeAffinity指定了多个nodeSelectorTerms,则则只需要其中一个条件能匹配成功就能完成Pod的调度,即多个条件之间是逻辑或(or)的关系。如果matchExperssions在nodeSelectorTerms中设置了多个条件表达式,那么必须满足所有的条件才能完成Pod的调度,即多个条件之间是逻辑与(and)的关系。{/callout}{tabs}{tabs-pane label="示例一"}#要求运行在具有标签“kubernetes.io/arch=amd64”的节点上。 #要求尽量运行在具有标签“disk-type=ssd”的节点上,如果没有,也可以运行在其他节点上。 --- apiVersion: v1 kind: Pod metadata: name: pod-with-node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/arch operator: In values: - amd64 preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: disk-type operator: In values: - ssd containers: - name: nginx image: nginx {/tabs-pane}{tabs-pane label="示例二"}对于具有zone=north标签的节点,系统会在调度算法的得分上加1(weigh=1),对于具有dis-type=ssd标签的节点,系统会在调度算法得分上加50(weight=50),然后综合其他条件计算出最终得分,并将pod调度到得分最高的Node上。apiVersion: v1 kind: Pod metadata: name: pod-with-node-affinity-weight spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: zone operator: In values: - north - weight: 50 preference: matchExpressions: - key: disk-type operator: In values: - ssd containers: - name: nginx image: nginx {/tabs-pane}{/tabs}Pod亲和性调度策略Pod亲和性:存在某些相互依赖,需要频繁互相调用的Pod,它们需要被尽可能地部署在同一个节点、机架、机房、网段或者区域(Zone)内。Pod反亲和性:处于避免竞争或者容错的需求,也可能使某些Pod尽可能地远离另外一些Pod。简单来说,某几个Pod可以在同一个拓扑域中共存,就是“Pod Affinity”,不能在同一个拓扑域中共存,就是“Pod Anti Affinity”。Pod亲和性与反亲和性调度的具体做法,就是通过在Pod的定义中增加topologyKey属性,来声明对应的目标拓扑域内几种相关联的Pod是“在一起还是不在一起”。需要注意的是,对于Pod的反亲和性策略,要求目标Node上需要存在相同的Label,实际上就是要求每个节点都具有相同的topologyKey指定的Label。如果某些Node不具有topologyKey指定的Label,则可能造成不可预估的调度结果。另外,设置Pod间的亲和性和反亲和性规则,会给调度器引入更多的计算量,在大规模集群中可能会造成性能问题,因此在配置Pod间的亲和性策略时需要谨慎。关于topoloygKey: 拓扑域:一个拓扑域由一些Node组成。这些Node通常具有相同的地理空间坐标。比如,在同一个机架、机房或地区。一般用Region表示机架、机房等的拓扑区域,用Zone表示地区这样跨度更大的拓扑区域。在某些情况下,可以认为一个Node就是一个拓扑区域。kubernetes为Node内置了一些常用的用于表示拓扑域概念的Label。kubernetes.io/hostnametopoloyg.kubernetes.io/regiontopoloyg.kubernetes.io/zone以上拓扑域是由kubernetes自己维护的。在node初始化时,Controller Manager会为Node设置许多标签。如,kubernetes.io/hostname这个标签的值会被设置为Node的hostname,云厂商会设置topoloyg.kubernetes.io/region和topoloyg.kubernetes.io/zone的值,以确定各个Node所属的拓扑域。{tabs}{tabs-pane label="参照Pod"}#带有两个Label --- apiVersion: v1 kind: Pod metadata: name: pod-flag labels: security: "S1" app: "nginx" spec: containers: - name: nginx image: nginx{/tabs-pane}{tabs-pane label="亲和性调度"}#亲和性Label是“security=S1” --- apiVersion: v1 kind: Pod metadata: name: pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: kubernetes.io/hostname containers: - name: pod-affinity image: nginx{/tabs-pane}{tabs-pane label="反亲和性调度1"}#新Pod与具有security=S1的Label的Pod在同一个zone的Node上运行 # 新Pod不能与具有app=nginx的Label的Pod在同一个Node上运行 --- apiVersion: v1 kind: Pod metadata: name: pod-anti-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: topology.kubernetes.io/zone podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - nginx topologyKey: kubernetes.io/hostname containers: - name: pod-anti-affinity image: nginx{/tabs-pane}{tabs-pane label="反亲和性调度2"}#在同一个Node上不运行多个Pod副本。 --- apiVersion: apps/v1 kind: Deployment metadata: name: app-with-anti-affinity spec: selector: matchLabels: app: nginx replicas: 3 template: metadata: labels: app: nginx spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - nginx topologyKey: "kubernetes.io/hostname" containers: - name: nginx image: nginx {/tabs-pane}{/tabs}污点和容忍度调度策略污点(Taint)配置在Node上,可以让Node拒绝一些具有某些特征的Pod在其上运行。容忍度(Toleration)配置在Pod中,用于高速系统允许调度到具有指定污点的节点上运行。默认情况下,在Node上设置一个或多个Taint后,除非Pod声明中明确能够容忍这些污点,否则无法在这些Node上运行。污点和容忍度的配合使用,可以避免将Pod调度到不合适的Node上。例如,某个Node存在问题(磁盘空间不足,计算资源不足,存在安全隐患等),希望新的Pod不要调度过来,就可以通过设置某些污点来实现。但设置了污点的Node并非不可用,仍是有效的Node。所以对于可用在这些Node上运行的Pod,可以给Pod设置与污点匹配的容忍度来实现调度。污点策略:PreferNoSchedule 尽量不调度,一个Pod如果没有声明容忍这个Taint,则系统会尽量避免把这个Pod调度到这一个Node上,但不保证一定能够避免NoScheduler 不被调度,除非Pod设置了与Taint匹配的容忍度。NoExecute 驱逐节点,不能在改node上运行,包括以下几种情况。对于正在该Node上运行的Pod,如果不能容忍指定的污点,则会被立刻从该Node驱逐。对于正在该Node上运行的Pod,如果能够容忍指定的污点,但未设置运行时限(tolerationSeconds),则会在该Pod上持续运行。对于正在该Node上运行的Pod,如果能够容忍指定的污点,但设置了运行时限(tolerationSeconds),则会在到达运行时限后从该Node上被驱逐。添加污点标签kubectl taint node node-0001 key=v1:PreferNoSchedule kubectl taint node node-0002 key=v2:NoScheduler容忍策略{tabs}{tabs-pane label="精确匹配"}…… spec: tolerations: - operator: "Equal" # 完全匹配键值对 key: "k" # 键 value: "v2" # 值 effect: "NoSchedule" # 污点标签 ……{/tabs-pane}{tabs-pane label="模糊匹配"}…… spec: tolerations: - operator: "Exists" # 部分匹配,存在即可 key: "k" # 键 effect: "NoSchedule" # 污点标签 ……{/tabs-pane}{tabs-pane label="所有污点标签"}…… spec: tolerations: - operator: "Exists" # 模糊匹配 key: "k" # 键 effect: # 没有设置污点标签代表所有 ……{/tabs-pane}{/tabs}优先级和抢占调度策略技术背景:对于运行各种负载(如Service,Job)的中等规模或者大规模的集群来说,需要尽可能提高集群的资源利用率。常规做法是采用优先级方案,即不同类型的负载对应不同的优先级,同时允许集群中的所有负载 所需要的资源总量超过集群可提供的资源。在这种情况下,当资源不足时,系统可以选择释放一些低优先级的负载,保障高优先级的负载获得足够的资源稳定运行。调度方式:由集群管理员创建priorityClass,Priority是不受限于命名空间的资源类型{tabs}{tabs-pane label="高优先级不抢占"}--- kind: PriorityClass apiVersion: scheduling.k8s.io/v1 metadata: name: high-non globalDefault: false preemptionPolicy: Never value: 1000 description: non-preemptive {/tabs-pane}{tabs-pane label="低优先级不抢占"}--- kind: PriorityClass apiVersion: scheduling.k8s.io/v1 metadata: name: low-non globalDefault: false preemptionPolicy: Never value: 500 description: non-preemptive{/tabs-pane}{tabs-pane label="高优先级抢占"}--- kind: PriorityClass apiVersion: scheduling.k8s.io/v1 metadata: name: high globalDefault: false preemptionPolicy: PreemptLowerPriority value: 1000 description: non-preemptive{/tabs-pane}{/tabs-pane}{tabs-pane label="低优先级抢占"}--- kind: PriorityClass apiVersion: scheduling.k8s.io/v1 metadata: name: low globalDefault: false preemptionPolicy: PreemptLowerPriority value: 500 description: non-preemptive{/tabs-pane}{/tabs-pane}{tabs-pane label="使用方式"}--- kind: Pod apiVersion: v1 metadata: name: php3 spec: nodeSelector: kubernetes.io/hostname: node-0002 priorityClassName: high-non # 优先级名称 containers: ……{/tabs-pane}{/tabs}其中,优先级的值越高,优先级越高,允许的设置范围是(-2147483648到1000000000),最大值是10亿,超过10亿的数字被系统保留,用于设置给系统组件。在上面的配置中,globalDefault设置为true表示这个优先级配置是全局默认配置,即对没有配置priorityCKassName的Pod都默认使用这个优先级设置。在系统没有设置全局默认优先级的情况下,对于没有配置priorityClassName的Pod,系统默认设置这些Pod的优先级为0。description字段用于设置一个说明,通常用来描述该priorityClass的用途。preemptionPolicy字段用于设置抢占策略。可用设置的策略有下面两个:PreemptLowerPriority:默认策略,表示允许具有该priorityClass优先级的Pod抢占较低优先级Pod的资源。Never:具有该优先级的Pod会被置于调度优先级队列中优先级数值更低的Pod之前,但不抢占其他Pod的资源,这些Pod将一直在调度列队中等待,知道有足够的可用资源后,才会被调度。抢占式调度的主要流程考察每个候选Node,找出为了满足新Pod的调度要求,需要释放的最少Pod实例;以抢占导致的代价最小原则,对筛查出来的所有候选Node进行考察,挑选出最优的候选Node作为最终被占用的目标Node;把目标Node与新Pod绑定,使得新Pod在下一轮的调度过程中可以使用这个目标Node来完成最终的调度流程,同时,调用APIServer删除目标Node上需要被释放的Pod以释放Node资源。最优Node选择规则拥有最小违反PodDisruptionBudget约束的Node;把Node上被释放的拥有最高优先级的Pod都找出来并进行比较,优先级排名垫底的Pod所在的Node;被释放的Pod的优先级之和(目标Pod需要的资源可能需要释放多个Pod才能满足)排名垫底的Node;被释放的Pod数量最少的Node;把Node上被释放的拥有最高优先级的Pod找出来,最晚启动的那个Pod所在的Node如果上述步骤还是无法选出最佳Node(可供选择的Node还有多个),就随机选择一个。注意事项如果目标Pod与候选Node上的某个优先级比它低的Pod之间有亲和性,则发生资源抢占后(这个低优先级的Pod被删除),目标pod不满足节点亲和性规则,此时该Node不符合抢占要求,Scheduler会考虑其他候选Node,无法保证目标Pod调度成功。要避免此类情况,要注意Pod亲和性和优先级的关系——具有亲和性关系的Pod不应该被设置为低优先级的。
2025年04月18日
53 阅读
0 评论
0 点赞
1
...
4
5
6
...
15