用户可以通过 UI 或者 CLI 提交一个 Pod 给 Kubernetes 进行部署,这个 Pod 请求首先会通过 CLI 或者 UI 提交给 Kubernetes API Server,下一步 API Server 会把这个信息写入到它的存储系统 etcd,之后 Scheduler 会通过 API Server 的 watch 或者叫做 notification 机制得到这个信息:有一个 Pod 需要被调度。
这个时候 Scheduler 会根据它的内存状态进行一次调度决策,在完成这次调度之后,它会向 API Server report 说:“OK!这个 Pod 需要被调度到某一个节点上。”
这个时候 API Server 接收到这次操作之后,会把这次的结果再次写到 etcd 中,然后 API Server 会通知相应的节点进行这次 Pod 真正的执行启动。相应节点的 kubelet 会得到这个通知,kubelet 就会去调 Container runtime 来真正去启动配置这个容器和这个容器的运行环境,去调度 Storage Plugin 来去配置存储,network Plugin 去配置网络。
3.4.1 概念
1、List-Watch是Kubernetes API Server提供的一种资源监控机制。它允许客户端通过API Server获取资源对象的列表(List),并通过建立长连接(Watch)来实时监控资源对象的变化。当资源对象发生创建、更新或删除等操作时,API Server会向订阅了相关资源的客户端发送事件通知,实现资源的实时同步和响应
2、List-watch机制是一种比较常用的分布式协调机制,它使得系统中的多个节点能够相互通信并且同步更新状态
3、list-watch机制的基本原理是:一个节点A将发布一个列表存储到共享内存,然后另一个节点B可以访问该存储列表,当A对该存储列表进行任何变更时,系统会自动通知B节点同步数据。
3.4.2 工作机制
List-Watch机制的工作原理可以简单概括为以下两个步骤
1)List操作
客户端向Kubernetes API Server发送List请求,指定要获取的资源类型和筛选条件。API Server根据请求返回符合条件的资源对象列表。客户端可以根据这个列表来初始化自己的状态或进行其他操作。
2)Watch操作
客户端在获取到资源对象列表后,可以继续向API Server发送Watch请求,建立与API Server的长连接。API Server会持续监控指定资源的变化,并将变化事件以流的形式发送给客户端。客户端可以解析这些事件通知,并触发相应的处理逻辑。
3.4.3 数据流向
1)初始化阶段:Kubernetes的各种组件(如Controller Manager、Scheduler、kubelet等)在启动时,会与APIServer建立连接,并初始化List-Watch机制。
2)List操作:组件向APIServer发送List请求,获取当前集群中指定资源类型的所有资源对象列表。例如,Controller Manager可能会请求获取所有Pod的列表。APIServer处理List请求,查询etcd存储系统,并将结果返回给组件。
3)Watch操作:组件向APIServer发送Watch请求,建立一个长连接,用于监听指定资源类型的变化。APIServer处理Watch请求,并在内部与etcd建立Watch连接,以监听etcd中对应资源的变化。
4)事件触发:当etcd中的资源发生变化(如Pod的创建、更新或删除)时,etcd会发送一个事件通知给APIServer。APIServer接收到事件通知后,会将事件封装成HTTP响应,并通过之前建立的长连接发送给对应的组件。
5)组件处理:组件接收到APIServer发送的事件通知后,会解析通知中的信息,并根据事件的类型(如ADD、UPDATE、DELETE)执行相应的操作。例如,如果Controller Manager接收到Pod被创建的事件,它可能会触发相应的控制器逻辑,如ReplicaSet控制器会根据Pod的创建来调整副本集的状态。
6)数据同步:通过List-Watch机制,Kubernetes的各个组件能够实时感知集群中资源的变化,并据此进行相应的操作,从而保持数据的同步和一致性。
3.4.4 流程案例
在 Kubernetes 中,所有部署的信息都会写到 etcd 中保存。实际上 etcd 在存储部署信息的时候,会发送 Create 事件给 APIServer,而 APIServer 会通过监听(Watch)etcd 发过来的事件。其他组件也会监听(Watch)APIServer 发出来的事件。
一个Pod的典型启动过程如下:
(1)这里有三个 List-Watch,分别是 Controller Manager(运行在 Master),Scheduler(运行在 Master),kubelet(运行在 Node)。他们在进程已启动就会监听(Watch)APIServer 发出来的事件。
(2)用户通过 kubectl 或其他 API 客户端提交请求给 APIServer 来建立一个 Pod 对象副本。
(3)APIServer 尝试着将 Pod 对象的相关元信息存入 etcd 中,待写入操作执行完成,APIServer 即会返回确认信息至客户端。
(4)当 etcd 接受创建 Pod 信息以后,会发送一个 Create 事件给 APIServer。
(5)由于 Controller Manager 一直在监听(Watch,通过http的8080端口)APIServer 中的事件。此时 APIServer 接受到了 Create 事件,又会发送给 Controller Manager。
(6)Controller Manager 在接到 Create 事件以后,调用其中的 Replication Controller 来保证 Node 上面需要创建的副本数量。一旦副本数量少于 RC 中定义的数量,RC 会自动创建副本。总之它是保证副本数量的 Controller(PS:扩容缩容的担当)。
(7)在 Controller Manager 创建 Pod 副本以后,APIServer 会在 etcd 中记录这个 Pod 的详细信息。例如 Pod 的副本数,Container 的内容是什么。
(8)同样的 etcd 会将创建 Pod 的信息通过事件发送给 APIServer。
(9)由于 Scheduler 在监听(Watch)APIServer,并且它在系统中起到了“承上启下”的作用,“承上”是指它负责接收创建的 Pod 事件,为其安排 Node;“启下”是指安置工作完成后,Node 上的 kubelet 进程会接管后继工作,负责 Pod 生命周期中的“下半生”。 换句话说,Scheduler 的作用是将待调度的 Pod 按照调度算法和策略绑定到集群中 Node 上。
(10)Scheduler 调度完毕以后会更新 Pod 的信息,此时的信息更加丰富了。除了知道 Pod 的副本数量,副本内容。还知道部署到哪个 Node 上面了。并将上面的 Pod 信息更新至 API Server,由 APIServer 更新至 etcd 中,保存起来。
(11)etcd 将更新成功的事件发送给 APIServer,APIServer 也开始反映此 Pod 对象的调度结果。
(12)kubelet 是在 Node 上面运行的进程,它也通过 List-Watch 的方式监听(Watch,通过https的6443端口)APIServer 发送的 Pod 更新的事件。kubelet 会尝试在当前节点上调用 Docker 启动容器,并将 Pod 以及容器的结果状态回送至 APIServer。
(13)APIServer 将 Pod 状态信息存入 etcd 中。在 etcd 确认写入操作成功完成后,APIServer将确认信息发送至相关的 kubelet,事件将通过它被接受。
注意:在创建 Pod 的工作就已经完成了后,为什么 kubelet 还要一直监听呢?原因很简单,假设这个时候 kubectl 发命令,要扩充 Pod 副本数量,那么上面的流程又会触发一遍,kubelet 会根据最新的 Pod 的部署情况调整 Node 的资源。又或者 Pod 副本数量没有发生变化,但是其中的镜像文件升级了,kubelet 也会自动获取最新的镜像文件并且加载。
Pod 是 Kubernetes 的一个最小调度以及资源单元。用户可以通过 Kubernetes 的 Pod API 生产一个 Pod,让 Kubernetes 对这个 Pod 进行调度,也就是把它放在某一个 Kubernetes 管理的节点上运行起来。一个 Pod 简单来说是对一组容器的集合,它里面会包含一个或多个容器。
每个 Pod 都由一个特殊的根容器 Pause 容器,以及一个或多个紧密相关的用户业务容器组成。
Pause 容器作为 Pod 的根容器,以它的状态代表整个容器组的状态。K8S 为每个 Pod 都分配了唯一的 IP 地址,称之为 Pod IP。Pod 里的多个业务容器共享 Pause 容器的IP,共享 Pause 容器挂载的 Volume。
比如像下面的这幅图里面,它包含了两个容器,每个容器可以指定它所需要资源大小。比如说,一个核一个 G,或者说 0.5 个核,0.5 个 G。
当然在这个 Pod 中也可以包含一些其他所需要的资源:比如说我们所看到的 Volume 卷这个存储资源;比如说我们需要 100 个 GB 的存储或者 20GB 的另外一个存储。
在 Pod 里面,我们也可以去定义容器所需要运行的方式。比如说运行容器的 Command,以及运行容器的环境变量等等。Pod 也给这些容器提供了一个共享的运行环境,它们会共享同一个网络环境,这些容器可以用 localhost 来进行直接的连接。而 Pod 与 Pod 之间,是互相有 isolation 隔离的。
4.1.1 Pod 的类型
在K8s中有两类行的Pod:普通的Pod和静态Pod(Static Pod)。
【静态 pod】
- 由kubelet进行创建,并且在kubelet所在的Node上运行。
- 静态Pod由kubelet进行管理的仅存于特定Node上的Pod。不能通过API Server进行管理。无法与RC、Deployment、DaemonSet进行关联。
- kubelet无法对它们进行健康检查。
- 作用:有效预防通过kubectl、或管理工具操作的误删除,可以用来部署核心组件应用。保障应用服务总是运行稳定数量和提供稳定服务。比如一些核心组件:
【普通 pod】
Kubernetes使用更高级的称为Controller的抽象层,来管理Pod实例,Pod一旦被创建,就会被放入etcd中存储,并且被K8s Master调度到某个具体的Node节点上绑定,该Pod被对应的Node上的kubelet进程实例化成一组相关的Docker容器并启动。在默认情况下,当Pod里面的某个容器停止时,K8s会自动检测到这个问题并且重新启动这个Pod(重启Pod里面所有的容器),如果Node宕机,K8S Master就会将这个Node上所有Pod都重新调度到其他的节点上。
4.1.2 Pod 创建案例】
apiVersion: v1 #核心API
kind #指明资源类型,此处为Pod
metadata #元数据,用于描述当前资源类型。
metadata.name #Pod的名称为tomcat
metadata.labels.name #定义该Pod有一个名为name=tomcat的标签
metadata.namespace #指定该Pod属于哪个命名空间
spec #定义Pod里面的容器组
spec.containers #定义容器组
containers.name #容器的名字为tomcat
containers.image #容器使用的镜像为kubeguide/tomcat-app:v1
containers.imagePullPolicy #IfNotPresent表示如果本地存在就不去镜像仓库拉取,不存在则拉取
containers.resources #定义容器的资源配额
resources.requests #定义请求的资源,现只支持CPU和内存,此处申请0.25个CPU和64MiB内存,
# 该值必须小于或者等于limits设置的值
resources.limits #资源最多申请0.5个CPU和128MiB内存
containers.ports #定义端口
ports.containerPort #容器应用监听的端口为8080
containers.env #往容器注入环境变量,以KV键值对的形式。此处注入了MYSQL_SERVICE_HOST='mysql'的环境变量containers.imagePullPolicy:
kubelet 始终尝试拉取此引用。如果拉取失败,kubelet 会将 Pod 设置为 。
kubelet 从不拉取此引用,仅使用本地镜像或工件。 如果本地没有任何镜像层存在,或者该镜像的清单未被缓存,则 Pod 会变为 。
如果引用在磁盘上不存在,kubelet 会进行拉取。 如果引用不存在且拉取失败,则 Pod 会变为 。
4.1.3 pod的生命周期
Pod 遵循预定义的生命周期,起始于 Pending 阶段, 如果至少其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以失败状态结束而进入 Succeeded 或者 Failed 阶段,Pod的生命周期主要特点:
- 和一个个独立的应用容器一样,Pod 也被认为是相对临时性(而不是长期存在)的实体。 Pod 会被创建、赋予一个唯一的 ID(UID),并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。
- Pod 在其生命周期中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者被终止
- 任何给定的 Pod (由 UID 定义)从不会被“重新调度(rescheduled)”到不同的节点; 相反,这一 Pod 可以被一个新的、几乎完全相同的 Pod 替换掉。 如果需要,新 Pod 的名字可以不变,但是其 UID 会不同。
- 如果一个节点死掉了,调度到该节点 的 Pod 也被计划在给定超时期限结束后删除。
- Pod 自身不具有自愈能力。如果 Pod 被调度到某节点 而该节点之后失效,或者调度操作本身失效,Pod 会被删除;与此类似,Pod 无法在节点资源 耗尽或者节点维护期间继续存活。Kubernetes 使用一种高级抽象,称作控制器,来管理这些相对而言可随时丢弃的 Pod 实例。
- 如果某物声称其生命期与某 Pod 相同,例如存储卷, 这就意味着该对象在此 Pod (UID 亦相同)存在期间也一直存在。 如果 Pod 因为任何原因被删除,甚至某完全相同的替代 Pod 被创建时, 这个相关的对象(例如这里的卷)也会被删除并重建。
Pod在整个生命周期中系统定义为各种状态,Pod的状态如下表所示:
取值
描述
(挂起)
Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
(运行中)
Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。
(成功)
Pod 中的所有容器都已成功终止,并且不会再重启。
(失败)
Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。
(未知)
因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。
下图是Pod的生命周期示意图,从图中可以看到Pod状态的变化:
4.1.3 pod的状态
Unschedulable
Pod不能被调度,kube-scheduler 没有匹配到合适的 node 节点。
PodScheduled
Pod 正处于调度中,在 kube-scheduler 刚开始调度的时候,还没有将 Pod 分配到指定的 node,在筛选出合适的节点后就会更新 etcd 数据,将 Pod 分配到指定的 node。
Initialized
所有 pod 中的初始化容器已经完成了。
ImagePullBackOff
Pod 所在的 node 节点下载镜像失败
其它状态
1)Error
Pod 启动过程中发生错误。
4.1.4 pod的健康检查和可用性检查
K8s对Pod的健康检查主要通过三类探针来配置:
- LivenessProbe(存活性探测):
- ReadinessProbe(就绪型探测):
- StartupProbe(启动探测):
指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。如果容器不提供存活探针, 则默认状态为 。
- kubelet 使用存活探针来确定什么时候要重启容器。例如,存活探针可以探测到应用死锁(应用程序在运行,但是无法继续执行后面的步骤)情况。 重启这种状态下的容器有助于提高应用的可用性,即使其中存在缺陷。
- 存活探针的常见模式是为就绪探针使用相同的低成本 HTTP 端点,但具有更高的 failureThreshold。 这样可以确保在硬性终止 Pod 之前,将观察到 Pod 在一段时间内处于非就绪状态。
指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 。 如果容器不提供就绪态探针,则默认状态为 。
- kubelet 使用就绪探针可以知道容器何时准备好接受请求流量,当一个 Pod 内的所有容器都就绪时,才能认为该 Pod 就绪。 这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。 若 Pod 尚未就绪,会被从 Service 的负载均衡器中剔除。
指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。如果启动探测失败, 将杀死容器, 而容器依其重启策略进行重启。 如果容器没有提供启动探测,则默认状态为 。
- 如果配置了这类探针,你就可以控制容器在启动成功后再进行存活性和就绪态检查, 确保这些存活、就绪探针不会影响应用的启动。
何时该使用存活态探针?
如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活态探针; 将根据 Pod 的 自动执行修复操作。
如果你希望容器在探测失败时被杀死并重新启动,那么请指定一个存活态探针, 并指定 为 "" 或 ""。
何时该使用就绪态探针?
如果要仅在探测成功时才开始向 Pod 发送请求流量,请指定就绪态探针。 在这种情况下,就绪态探针可能与存活态探针相同,但是规约中的就绪态探针的存在意味着 Pod 将在启动阶段不接收任何数据,并且只有在探针探测成功后才开始接收数据。
如果你希望容器能够自行进入维护状态,也可以指定一个就绪态探针, 检查某个特定于就绪态的因此不同于存活态探测的端点。
如果你的应用程序对后端服务有严格的依赖性,你可以同时实现存活态和就绪态探针。 当应用程序本身是健康的,存活态探针检测通过后,就绪态探针会额外检查每个所需的后端服务是否可用。 这可以帮助你避免将流量导向只能返回错误信息的 Pod。
如果你的容器需要在启动期间加载大型数据、配置文件或执行迁移, 你可以使用启动探针。 然而,如果你想区分已经失败的应用和仍在处理其启动数据的应用,你可能更倾向于使用就绪探针
何时该使用启动探针?
对于所包含的容器需要较长时间才能启动就绪的 Pod 而言,启动探针是有用的。 你不再需要配置一个较长的存活态探测时间间隔,只需要设置另一个独立的配置选定, 对启动期间的容器执行探测,从而允许使用远远超出存活态时间间隔所允许的时长。
【探针配置方式】
以上三种类型的探针可配置以下几种实现方式:
- Exec探针: 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
- http探针:对容器的 IP 地址上指定端口和路径执行 HTTP 请求。如果响应的状态码大于等于 200 且小于 400,则诊断被认为是成功的。
- TCP探针:对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。 如果远程系统(容器)在打开连接后立即将其关闭,这算作是健康的。
【探针配置案例】
【exec】:
- initialDelaySeconds:启动容器后进行首次健康检查的等待时间,单位为s。
- 在上面的例子中,通过执行“cat /tmp/health”命令来判断一个容器运行是否正常。在该Pod运行后,将在创建/tmp/health文件10s后删除该文件,而LivenessProbe健康检查的初始探测时间(initialDelaySeconds)为15s,探测结果是Fail,将导致kubelet杀掉该容器并重启它:
【http】
【TCP】通过与容器内的localhost:80建立TCP连接进行健康检查
对于每种探测方式,都需要设置initialDelaySeconds和timeoutSeconds两个参数,它们的含义分别如下。
- initialDelaySeconds:启动容器后进行首次健康检查的等待时间,单位为s。
- timeoutSeconds:健康检查发送请求后等待响应的超时时间,单位为s。当超时发生时,kubelet会认为容器已经无法提供服务,将会重启该容器。
k8s东西真多,🐶都不学,还有 pod 的调度、升级、扩容、终止。。。。。。。。。真是上早八。
Volume 就是卷的概念,它是用来管理 Kubernetes 存储的,是用来声明在 Pod 中的容器可以访问文件目录的,一个卷可以被挂载在 Pod 中一个或者多个容器的指定路径下面。
而 Volume 本身是一个抽象的概念,一个 Volume 可以去支持多种的后端的存储。比如说 Kubernetes 的 Volume 就支持了很多存储插件,它可以支持本地的存储,可以支持分布式的存储,比如说像 ceph,GlusterFS ;它也可以支持云存储,比如说阿里云上的云盘、AWS 上的云盘、Google 上的云盘等等。
卷 | Kubernetes
Kubernetes (K8s) 提供了以下几种卷类型:
- 空白卷(emptyDir):这是一个临时的卷,它在 Pod 生命周期内存在,但在 Pod 关闭或重新启动后会被清空。
- 主机路径卷(hostPath):将节点上的目录或文件挂载到 Pod 中,可以使用节点上的文件系统或文件。
- 持久卷(Persistent Volume,PV):PV 是独立于 Pod 的一种资源,它可以由管理员手动创建并供 Pod 使用。PV 存储在集群中,并可以被多个 Pod 共享。
- 持久卷声明(Persistent Volume Claim,PVC):PVC 是对 PV 的请求,它描述了所需的存储属性,并由管理员或开发者创建。PVC 会与 PV 进行匹配,并将 PV 动态分配给请求该存储的 Pod。
- 配置映射卷(ConfigMap):ConfigMap 是一个用于存储非敏感配置数据的对象,可以将其作为卷挂载到 Pod 中,从而使 Pod 可以访问其中的配置数据。
- 密钥卷(Secret):Secret 是用于存储敏感数据(如密码、令牌等)的对象。它可以以卷的形式挂载到 Pod 中,以供应用程序使用。
- 存储类(StorgeClass):可以自动创建持久卷
简单整理几种常见卷的类型
4.2.1 空白卷(emptyDir)
对于定义了 卷的 Pod,在 Pod 被指派到某节点时此卷会被创建。 就像其名称所表示的那样, 卷最初是空的。尽管 Pod 中的容器挂载 卷的路径可能相同也可能不同,但这些容器都可以读写 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时, 卷中的数据也会被永久删除。主要用来存储临时数据。
说明:
容器崩溃并不会导致 Pod 被从节点上移除,因此容器崩溃期间 卷中的数据是安全的。
4.2.2 主机路径卷(hostPath)
卷能将主机节点文件系统上的文件或目录挂载到你的 Pod 中。 虽然这不是大多数 Pod 需要的,但是它为一些应用提供了强大的逃生舱。
的一些用法有:
- 运行一个需要访问节点级系统组件的容器 (例如一个将系统日志传输到集中位置的容器,使用只读挂载 来访问这些日志)
- 让存储在主机系统上的配置文件可以被静态 Pod 以只读方式访问;与普通 Pod 不同,静态 Pod 无法访问 ConfigMap。
hostPath FileOrCreate 配置示例
以下清单定义了一个 Pod,将 挂载到 Pod 中的单个容器内。 如果节点上还没有路径 ,kubelet 会创建这一目录,然后将其挂载到 Pod 中。
如果 已经存在但不是一个目录,Pod 会失败。 此外,kubelet 还会尝试在该目录内创建一个名为 的文件(从主机的视角来看); 如果在该路径上已经存在某个东西且不是常规文件,则 Pod 会失败。
4.2.3 持久卷
持久卷(PersistentVolume,PV) 是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。
持久卷申领(PersistentVolumeClaim,PVC) 表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存)。同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以挂载为 ReadWriteOnce、ReadOnlyMany、ReadWriteMany 或 ReadWriteOncePod,
【卷的制备】
PV 卷的制备有两种方式:静态制备或动态制备。
静态制备
集群管理员创建若干 PV 卷。这些卷对象带有真实存储的细节信息, 并且对集群用户可用(可见)。PV 卷对象存在于 Kubernetes API 中,可供用户消费(使用)。
动态制备
如果管理员所创建的所有静态 PV 卷都无法与用户的 PersistentVolumeClaim 匹配, 集群可以尝试为该 PVC 申领动态制备一个存储卷。 这一制备操作是基于 StorageClass 来实现的:PVC 申领必须请求某个 存储类, 同时集群管理员必须已经创建并配置了该类,这样动态制备卷的动作才会发生。 如果 PVC 申领指定存储类为 ,则相当于为自身禁止使用动态制备的卷。
【pvc 与 pv 的绑定】
用户创建一个带有特定存储容量和特定访问模式需求的 PersistentVolumeClaim 对象; 在动态制备场景下,这个 PVC 对象可能已经创建完毕。 控制平面中的控制回路监测新的 PVC 对象,寻找与之匹配的 PV 卷(如果可能的话), 并将二者绑定到一起。 如果为了新的 PVC 申领动态制备了 PV 卷,则控制回路总是将该 PV 卷绑定到这一 PVC 申领。 否则,用户总是能够获得他们所请求的资源,只是所获得的 PV 卷可能会超出所请求的配置。 一旦绑定关系建立,则PersistentVolumeClaim 绑定就是排他性的, 无论该 PVC 申领是如何与 PV 卷建立的绑定关系。 PVC 申领与 PV 卷之间的绑定是一种一对一的映射,实现上使用 ClaimRef 来记述 PV 卷与 PVC 申领间的双向绑定关系。
如果找不到匹配的 PV 卷,PVC 申领会无限期地处于未绑定状态。 当与之匹配的 PV 卷可用时,PVC 申领会被绑定。 例如,即使某集群上制备了很多 50 Gi 大小的 PV 卷,也无法与请求 100 Gi 大小的存储的 PVC 匹配。当新的 100 Gi PV 卷被加入到集群时, 该 PVC 才有可能被绑定。
【持久卷的类型】
PV 持久卷是用插件的形式来实现的。Kubernetes 目前支持以下插件(还有一些弃用的,仍可以用):
- csi - 容器存储接口(CSI)
- fc - Fibre Channel(FC)存储
- hostPath - HostPath 卷 (仅供单节点测试使用;不适用于多节点集群;请尝试使用 卷作为替代)
- iscsi - iSCSI(IP 上的 SCSI)存储
- local - 节点上挂载的本地存储设备
- nfs - 网络文件系统(NFS)存储
【持久卷的创建】
容量:
一般而言,每个 PV 卷都有确定的存储容量。 这是通过 PV 的 属性设置的,
卷模式:
针对 PV 持久卷,Kubernetes 支持两种卷模式(): 和 。 是一个可选的 API 参数。 如果该参数被省略,默认的卷模式是 。
属性设置为 的卷会被 Pod 挂载(Mount) 到某个目录。 如果卷的存储来自某块设备而该设备目前为空,Kuberneretes 会在第一次挂载卷之前在设备上创建文件系统。
你可以将 设置为 ,以便将卷作为原始块设备来使用。 这类卷以块设备的方式交给 Pod 使用,其上没有任何文件系统。 这种模式对于为 Pod 提供一种使用最快可能方式来访问卷而言很有帮助, Pod 和卷之间不存在文件系统层。另外,Pod 中运行的应用必须知道如何处理原始块设备。
访问模式:
PV 卷可以用资源提供者所支持的任何方式挂载到宿主系统上。 如下表所示,提供者(驱动)的能力不同,每个 PV 卷的访问模式都会设置为对应卷所支持的模式值。 例如,NFS 可以支持多个读写客户,但是某个特定的 NFS PV 卷可能在服务器上以只读的方式导出。 每个 PV 卷都会获得自身的访问模式集合,描述的是特定 PV 卷的能力。
访问模式有:
卷可以被一个节点以读写方式挂载。 ReadWriteOnce 访问模式仍然可以在同一节点上运行的多个 Pod 访问该卷。 对于单个 Pod 的访问,请参考 ReadWriteOncePod 访问模式。
卷可以被多个节点以只读方式挂载。
卷可以被多个节点以读写方式挂载。
卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。
说明:
Kubernetes 使用卷访问模式来匹配 PersistentVolumeClaim 和 PersistentVolume。 在某些场合下,卷访问模式也会限制 PersistentVolume 可以挂载的位置。 卷访问模式并不会在存储已经被挂载的情况下为其实施写保护。 即使访问模式设置为 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany,它们也不会对卷形成限制。 例如,即使某个卷创建时设置为 ReadOnlyMany,也无法保证该卷是只读的。 如果访问模式设置为 ReadWriteOncePod,则卷会被限制起来并且只能挂载到一个 Pod 上。
重要提醒! 每个卷同一时刻只能以一种访问模式挂载,即使该卷能够支持多种访问模式。
存储类
每个 PV 可以属于某个类(Class),通过将其 属性设置为某个 StorageClass 的名称来指定。 特定类的 PV 卷只能绑定到请求该类存储卷的 PVC 申领。 未设置 的 PV 卷没有类设定,只能绑定到那些没有指定特定存储类的 PVC 申领。
【持久卷经历阶段】
每个持久卷会处于以下阶段(Phase)之一:
卷是一个空闲资源,尚未绑定到任何申领
该卷已经绑定到某申领
所绑定的申领已被删除,但是关联存储资源尚未被集群回收
卷的自动回收操作失败
你可以使用 查看已绑定到 PV 的 PVC 的名称。
【PVC 的创建】
存储类:
PVC可以通过为 属性设置 StorageClass 的名称来请求特定的存储类。 值与 PVC 设置相同的 PV 卷, 才能绑定到 PVC 。
PVC 申领不必一定要请求某个类。如果 PVC 的 属性值设置为 , 则被视为要请求的是没有设置存储类的 PV 卷,因此这一 PVC 申领只能绑定到未设置存储类的 PV 卷(未设置注解或者注解值为 的 PersistentVolume(PV)对象在系统中不会被删除, 因为这样做可能会引起数据丢失)。未设置 的 PVC 与此大不相同, 也会被集群作不同处理。具体筛查方式取决于 DefaultStorageClass 准入控制器插件 是否被启用。
说明:
目前,设置了非空 的 PVC 对象无法让集群为其动态制备 PV 卷。
【卷的使用】
Pod 将 PVC 申领当做存储卷来使用。集群会检视 PVC 申领,找到所绑定的卷, 并为 Pod 挂载该卷。对于支持多种访问模式的卷, 用户要在 Pod 中以卷的形式使用申领时指定期望的访问模式。
一旦用户有了申领对象并且该申领已经被绑定, 则所绑定的 PV 卷在用户仍然需要它期间一直属于该用户。 用户通过在 Pod 的 块中包含 节区来调度 Pod,访问所申领的 PV 卷。
Pod 将PVC作为卷来使用,并藉此访问存储资源。 PVC必须位于使用它的 Pod 所在的同一名字空间内。 集群在 Pod 的名字空间中查找PVC,并使用它来获得PVC所使用的 PV 卷。 之后,卷会被挂载到宿主上并挂载到 Pod 中。
持久卷 | Kubernetes ,更多见此连接
4.2.4 存储类
Kubernetes 存储类的概念类似于一些其他存储系统设计中的"配置文件"。
4.2.5 映射卷
configMap 卷提供了向 Pod 注入配置数据的方法。 ConfigMap 对象中存储的数据可以被 类型的卷引用,然后被 Pod 中运行的容器化应用使用。
引用 configMap 对象时,你可以在卷中通过它的名称来引用。 你可以自定义 ConfigMap 中特定条目所要使用的路径。 下面的配置显示了如何将名为 的 ConfigMap 挂载到名为 的 Pod 中:
ConfigMap 以卷的形式挂载,并且存储在 条目中的所有内容都被挂载到 Pod 的 路径下。 请注意,这个路径来源于卷的 和 键对应的 。
说明:
- 你必须先创建 ConfigMap, 才能使用它。
- ConfigMap 总是以 的模式挂载。
- 容器以 subPath 卷挂载方式使用 ConfigMap 时,将无法接收 ConfigMap 的更新。
- 文本数据挂载成文件时采用 UTF-8 字符编码。如果使用其他字符编码形式,可使用 字段。
ReplicaSet 的作用是维持在任何给定时间运行的一组稳定的副本 Pod。 通常,你会定义一个 Deployment,并用这个 Deployment 自动管理 ReplicaSet。这实际上意味着,你可能永远不需要操作 ReplicaSet 对象:而是使用 Deployment,并在 spec 部分定义你的应用。
ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。
一句话就是用来确保任何时间都有指定数量的 Pod 副本在运行.
【Replication Controller,RC】(升级版本为ReplicaSet)
RC是Kubernetes系统中的核心概念之一,简单来说,它其实是定义了一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,所以RC的定义包括如下几个部分:
- Pod期待的副本数(replicas)。
- 用于筛选目标Pod的Label Selector。
- 当Pod的副本数量小于预期数量时,用于创建新Pod的Pod模版(template)。
下面是一个完整的RC定义的例子,即确保拥有tier=frontend标签的这个Pod(运行nginx容器)在整个Kubernetes集群中始终只有一个副本:
当定义了一个RC并提交到K8S集群中后,Master节点上的Controller Manager组件就得到通知,定期巡检系统中当前存活的目标Pod,并确保目标Pod实例的数量刚好等于此RC的期望值,如果有过多的Pod副本在运行,系统就会停掉一些Pod,否则系统就会再自动创建一些Pod。可以说,通过RC,Kubernetes实现了用户应用集群的高可用性,并且大大减少了系统管理员在传统IT环境中需要完成的许多手工运维工作(如主机监控脚本、应用监控脚本、故障恢复脚本等)。
当我们的应用升级时,通常会通过Build一个新的Docker镜像,并用新的镜像版本来替代旧的版本的方式达到目的,在系统升级的过程中,我们希望是平滑的方式,比如当前系统中10个对应的旧版本的Pod,最佳的方式是旧版本的Pod每次停止一个,同时创建一个新版本的Pod,在整个升级过程中,此消彼长,而运行中的Pod数量始终是10个,几分钟以后,当所有的Pod都已经是最新版本时,升级过程完成。通过RC的机制,Kubernetes很容易就实现了这种高级实用的特性,被称为“滚动升级”(Rolling Update)。
【Replica Set, RS】
由于Replication Controller与Kubernetes代码中的模块Replication Controller同名,同时这个词也无法准确表达它的本意,所以在Kubernetes v1.2时,它就升级成了另外一个新的概念 – Replica Set,官方解释为“下一代的RC”,它与RC当前存在的唯一区别是:Replica Sets支持基于集合的Label selector(Set-based selector),而RC只支持基于等式的Label Selector(equality-based selector),这使得Replica Set的功能更强,下面是等价于之前RC例子的Replica Set的定义(省去了Pod模版部分的内容):
注:Kubernetes官方强烈建议避免直接使用ReplicaSet,而应该通过Deployment来创建RS和Pod。
Deployment 是在 Pod 这个抽象上更为上层的一个抽象,它可以定义一组 Pod 的副本数目、以及这个 Pod 的版本。一般大家用 Deployment 这个抽象来做应用的真正的管理,而 Pod 是组成 Deployment 最小的单元。因此,Deployment 用于管理运行一个应用负载的一组 Pod,通常适用于不保持状态的负载。
Kubernetes 是通过 Controller控制器去维护 Deployment 中 Pod 的数目,它也会去帮助 Deployment 自动恢复失败的 Pod。
比如说我可以定义一个 Deployment,这个 Deployment 里面需要两个 Pod,当一个 Pod 失败的时候,控制器就会监测到,它重新把 Deployment 中的 Pod 数目从一个恢复到两个,通过再去新生成一个 Pod。通过控制器,我们也会帮助完成发布的策略。比如说进行滚动升级,进行重新生成的升级,或者进行版本的回滚。
4.4.1 用例
在该例中:
- 创建名为 (由 字段标明)的 Deployment。 该名称将成为后续创建 ReplicaSet 和 Pod 的命名基础。
- 该 Deployment 创建一个 ReplicaSet,它创建三个(由 字段标明)Pod 副本。
- 字段定义所创建的 ReplicaSet 如何查找要管理的 Pod。 在这里,你选择在 Pod 模板中定义的标签()。 不过,更复杂的选择规则是也可能的,只要 Pod 模板本身满足所给规则即可。
- 字段包含以下子字段:
- Pod 被使用 字段打上 标签。
- Pod 模板规约(即 字段)指示 Pod 运行一个 容器, 该容器运行版本为 1.14.2 的 Docker Hub 镜像。
- 创建一个容器并使用 字段将其命名为 。
Deployment是Kubernetes v1.2引入的概念,引入的目的是为了更好地解决Pod的编排问题。为此,Deployment在内部使用了Replica Set来实现目的,无论从Deployment的作用与目的,它的YAML定义,还是从它的具体命令行操作来看,我们都可以把它看作RC的一次升级,两者相似度超过90%。
Deployment相对于RC的一个最大升级是我们随时知道当前Pod“部署”的进度。实际上由于一个Pod的创建、调度、绑定节点及在目标Node上启动对应的容器这一完整过程需要一定的时间,所以我们期待系统启动N个Pod副本的目标状态,实际上是一个连续变化的“部署过程”导致的最终状态,此外,RS不支持回滚更新操作,Deployment支持。
Deployment的典型使用场景有以下几个:
管理无状态应用
具有上线部署、副本设定、滚动升级、回滚等功能
创建一个Deployment对象来生成对应的Replica Set并完成Pod副本的创建过程。
检查Deployment的状态来看部署动作是否完成(Pod副本的数量是否达到预期的值)。
滚动升级和回滚应用:更新Deployment以创建新的Pod(比如镜像升级),如果当前Deployment不稳定,则回滚到一个早先的Deployment版本。
暂停Deployment以便于一次性修改多个PodTemplateSpec的配置项,之后再恢复Deployment,进行新的发布。
扩容和缩容:扩展Deployment以应对高负载。
查看Deployment的状态,以此作为发布是否成功的指标。
清理不再需要的旧版本ReplicaSets。
Deployments | Kubernetes
Service 提供了一个或者多个 Pod 实例的稳定访问地址。
比如在上面的例子中,我们看到:一个 Deployment 可能有两个甚至更多个完全相同的 Pod。对于一个外部的用户来讲,访问哪个 Pod 其实都是一样的,所以它希望做一次负载均衡,在做负载均衡的同时,我只想访问某一个固定的 VIP,也就是 Virtual IP 地址,而不希望得知每一个具体的 Pod 的 IP 地址。
对一个外部用户来讲,提供了多个具体的 Pod 地址,这个用户要不停地去更新 Pod 地址,当这个 Pod 再失败重启之后,我们希望有一个抽象,把所有 Pod 的访问能力抽象成一个第三方的一个 IP 地址,实现这个的 Kubernetes 的抽象就叫 Service。
实现 Service 有多种方式,Kubernetes 支持 Cluster IP,上面我们讲过的 kuber-proxy 的组网,它也支持 nodePort、 LoadBalancer 等其他的一些访问的能力。
Namespace 是用来做一个集群内部的逻辑隔离的,它包括鉴权、资源管理等。Kubernetes 的每个资源,比如刚才讲的 Pod、Deployment、Service 都属于一个 Namespace,同一个 Namespace 中的资源需要命名的唯一性,不同的 Namespace 中的资源可以重名。
Namespace 一个用例,我们内部会有很多个 business units,在每一个 business units 之间,希望有一个视图上的隔离,并且在鉴权上也不一样,在 cuda 上面也不一样,我们就会用 Namespace 来去给每一个 BU 提供一个他所看到的这么一个看到的隔离的机制。
标签,附加到某个资源上,用于关联对象、查询和筛选。一个 Label 是一个 key=value 的键值对,key 与 value 由用户自己指定。Label 可以附加到各种资源上,一个资源对象可以定义任意数量的 Label,同一个 Label 也可以被添加到任意数量的资源上。
我们可以通过给指定的资源对象捆绑一个或多个不同的 Label 来实现多维度的资源分组管理功能,以便于灵活、方便地进行资源分配、调度、配置、部署等工作。
K8S 通过 Label Selector(标签选择器)来查询和筛选拥有某些 Label 的资源对象。Label Selector 有基于等式( name=label1 )和基于集合( name in (label1, label2) )的两种方式。
下面我们介绍一下 Kubernetes 的 API 的基础知识。从 high-level 上看,Kubernetes API 是由 HTTP+JSON 组成的:用户访问的方式是 HTTP,访问的 API 中 content 的内容是 JSON 格式的。
Kubernetes 的 kubectl 也就是 command tool,Kubernetes UI,或者有时候用 curl,直接与 Kubernetes 进行沟通,都是使用 HTTP + JSON 这种形式。
下面有个例子:比如说,对于这个 Pod 类型的资源,它的 HTTP 访问的路径,就是 API,然后是 apiVesion: V1, 之后是相应的 Namespaces,以及 Pods 资源,最终是 Podname,也就是 Pod 的名字。
如果我们去提交一个 Pod,或者 get 一个 Pod 的时候,它的 content 内容都是用 JSON 或者是 YAML 表达的。上图中有个 yaml 的例子,在这个 yaml file 中,对 Pod 资源的描述也分为几个部分。
第一个部分,一般来讲会是 API 的 version。比如在这个例子中是 V1,它也会描述我在操作哪个资源;比如说我的 kind 如果是 pod,在 Metadata 中,就写上这个 Pod 的名字;比如说 nginx,我们也会给它打一些 label,我们等下会讲到 label 的概念。在 Metadata 中,有时候也会去写 annotation,也就是对资源的额外的一些用户层次的描述。
比较重要的一个部分叫做 Spec,Spec 也就是我们希望 Pod 达到的一个预期的状态。比如说它内部需要有哪些 container 被运行;比如说这里面有一个 nginx 的 container,它的 image 是什么?它暴露的 port 是什么?
当我们从 Kubernetes API 中去获取这个资源的时候,一般来讲在 Spec 下面会有一个项目叫 status,它表达了这个资源当前的状态;比如说一个 Pod 的状态可能是正在被调度、或者是已经 running、或者是已经被 terminates,就是被执行完毕了。
刚刚在 API 之中,我们讲了一个比较有意思的 metadata 叫做“label”,这个 label 可以是一组 KeyValuePair。
比如下图的第一个 pod 中,label 就可能是一个 color 等于 red,即它的颜色是红颜色。当然你也可以加其他 label,比如说 size: big 就是大小,定义为大的,它可以是一组 label。
这些 label 是可以被 selector,也就是选择器所查询的。这个能力实际上跟我们的 sql 类型的 select 语句是非常相似的,比如下图中的三个 Pod 资源中,我们就可以进行 select。name color 等于 red,就是它的颜色是红色的,我们也可以看到,只有两个被选中了,因为只有他们的 label 是红色的,另外一个 label 中写的 color 等于 yellow,也就是它的颜色是黄色,是不会被选中的
通过 label,kubernetes 的 API 层就可以对这些资源进行一个筛选,那这些筛选也是 kubernetes 对资源的集合所表达默认的一种方式。
例如说,我们刚刚介绍的 Deployment,它可能是代表一组的 Pod,它是一组 Pod 的抽象,一组 Pod 就是通过 label selector 来表达的。当然我们刚才讲到说 service 对应的一组 Pod,就是一个 service 要对应一个或者多个的 Pod,来对它们进行统一的访问,这个描述也是通过 label selector 来进行 select 选取的一组 Pod。
-----------------
用于笔记。
若侵权-联系-删。
到此这篇k8s 发布时间(k8s发布时间)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/jszy-gxgz/45454.html